@inoo-ch/payload-image-optimizer 1.4.5 → 1.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/AGENT_DOCS.md +40 -5
- package/README.md +17 -5
- package/dist/components/FadeImage.d.ts +23 -0
- package/dist/components/FadeImage.js +34 -0
- package/dist/components/FadeImage.js.map +1 -0
- package/dist/components/ImageBox.d.ts +4 -0
- package/dist/components/ImageBox.js +13 -4
- package/dist/components/ImageBox.js.map +1 -1
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.js +1 -0
- package/dist/exports/client.js.map +1 -1
- package/package.json +30 -55
- package/src/components/FadeImage.tsx +51 -0
- package/src/components/ImageBox.tsx +19 -3
- package/src/exports/client.ts +2 -0
package/AGENT_DOCS.md
CHANGED
|
@@ -219,7 +219,7 @@ Import from `@inoo-ch/payload-image-optimizer/client`:
|
|
|
219
219
|
|
|
220
220
|
### `ImageBox` Component
|
|
221
221
|
|
|
222
|
-
Drop-in Next.js `<Image>` wrapper with automatic ThumbHash blur placeholders
|
|
222
|
+
Drop-in Next.js `<Image>` wrapper with automatic ThumbHash blur placeholders, focal point support, and smooth fade-in transition.
|
|
223
223
|
|
|
224
224
|
```tsx
|
|
225
225
|
import { ImageBox } from '@inoo-ch/payload-image-optimizer/client'
|
|
@@ -229,21 +229,55 @@ import { ImageBox } from '@inoo-ch/payload-image-optimizer/client'
|
|
|
229
229
|
|
|
230
230
|
// With a plain URL string
|
|
231
231
|
<ImageBox media="/images/fallback.jpg" alt="Fallback" width={800} height={600} />
|
|
232
|
+
|
|
233
|
+
// Disable fade animation
|
|
234
|
+
<ImageBox media={doc.image} alt="Photo" fade={false} />
|
|
235
|
+
|
|
236
|
+
// Custom fade duration
|
|
237
|
+
<ImageBox media={doc.image} alt="Photo" fadeDuration={300} />
|
|
232
238
|
```
|
|
233
239
|
|
|
234
240
|
**Props:** Extends all Next.js `ImageProps` (except `src`), plus:
|
|
235
241
|
|
|
236
|
-
| Prop | Type | Description |
|
|
237
|
-
|
|
238
|
-
| `media` | `MediaResource \| string` | Payload media document or URL string |
|
|
239
|
-
| `alt` | `string` | Alt text (overrides `media.alt`) |
|
|
242
|
+
| Prop | Type | Default | Description |
|
|
243
|
+
|------|------|---------|-------------|
|
|
244
|
+
| `media` | `MediaResource \| string` | — | Payload media document or URL string |
|
|
245
|
+
| `alt` | `string` | — | Alt text (overrides `media.alt`) |
|
|
246
|
+
| `fade` | `boolean` | `true` | Enable smooth blur-to-sharp fade transition on load |
|
|
247
|
+
| `fadeDuration` | `number` | `500` | Duration of the fade animation in milliseconds |
|
|
240
248
|
|
|
241
249
|
Automatically applies:
|
|
242
250
|
- ThumbHash blur placeholder (if available on the media resource)
|
|
251
|
+
- Smooth blur-to-sharp fade transition on image load (disable with `fade={false}`)
|
|
243
252
|
- Focal point positioning via `objectPosition` (using `focalX`/`focalY`)
|
|
244
253
|
- Cache-busting via `updatedAt` query parameter
|
|
245
254
|
- `objectFit: 'cover'` by default (overridable via `style`)
|
|
246
255
|
|
|
256
|
+
### `FadeImage` Component
|
|
257
|
+
|
|
258
|
+
Standalone Next.js `<Image>` wrapper with fade-in transition for use with `getImageOptimizerProps()`. Use this when you have a custom image component and want the fade effect without `ImageBox`.
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
import { FadeImage, getImageOptimizerProps } from '@inoo-ch/payload-image-optimizer/client'
|
|
262
|
+
|
|
263
|
+
const optimizerProps = getImageOptimizerProps(resource)
|
|
264
|
+
|
|
265
|
+
<FadeImage
|
|
266
|
+
src={resource.url}
|
|
267
|
+
alt=""
|
|
268
|
+
width={800}
|
|
269
|
+
height={600}
|
|
270
|
+
optimizerProps={optimizerProps}
|
|
271
|
+
/>
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Props:** Extends all Next.js `ImageProps` (except `placeholder`, `blurDataURL`, `onLoad`), plus:
|
|
275
|
+
|
|
276
|
+
| Prop | Type | Default | Description |
|
|
277
|
+
|------|------|---------|-------------|
|
|
278
|
+
| `optimizerProps` | `ImageOptimizerProps` | — | Props returned by `getImageOptimizerProps()` |
|
|
279
|
+
| `fadeDuration` | `number` | `500` | Duration of the fade animation in milliseconds |
|
|
280
|
+
|
|
247
281
|
### `getImageOptimizerProps()` Utility
|
|
248
282
|
|
|
249
283
|
For integrating with existing image components (e.g., the Payload website template's `ImageMedia`):
|
|
@@ -360,6 +394,7 @@ import type {
|
|
|
360
394
|
|
|
361
395
|
import type {
|
|
362
396
|
ImageBoxProps,
|
|
397
|
+
FadeImageProps,
|
|
363
398
|
ImageOptimizerProps, // return type of getImageOptimizerProps
|
|
364
399
|
} from '@inoo-ch/payload-image-optimizer/client'
|
|
365
400
|
```
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @inoo-ch/payload-image-optimizer
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@inoo-ch/payload-image-optimizer)
|
|
4
|
+
[](https://www.npmjs.com/package/@inoo-ch/payload-image-optimizer)
|
|
5
|
+
[](https://github.com/PascalEugster/payloadcms-plugin-image-optimizer)
|
|
6
|
+
|
|
3
7
|
A [Payload CMS](https://payloadcms.com) plugin for automatic image optimization. Converts uploads to WebP/AVIF, resizes to configurable limits, strips EXIF metadata, generates [ThumbHash](https://evanw.github.io/thumbhash/) blur placeholders, and provides bulk regeneration from the admin panel.
|
|
4
8
|
|
|
5
9
|
Built and maintained by [inoo.ch](https://inoo.ch) — a Swiss digital agency crafting modern web experiences.
|
|
@@ -13,7 +17,8 @@ Built and maintained by [inoo.ch](https://inoo.ch) — a Swiss digital agency cr
|
|
|
13
17
|
- **Bulk regeneration** — Re-process existing images from the admin UI with progress tracking
|
|
14
18
|
- **Per-collection config** — Override formats, quality, and dimensions per collection
|
|
15
19
|
- **Admin UI** — Status badges, file size savings, and blur previews in the sidebar
|
|
16
|
-
- **ImageBox component** — Drop-in Next.js `<Image>` wrapper with automatic ThumbHash blur
|
|
20
|
+
- **ImageBox component** — Drop-in Next.js `<Image>` wrapper with automatic ThumbHash blur and smooth fade-in
|
|
21
|
+
- **FadeImage component** — Standalone fade-in image for custom setups using `getImageOptimizerProps()`
|
|
17
22
|
|
|
18
23
|
## Requirements
|
|
19
24
|
|
|
@@ -142,7 +147,7 @@ Payload CMS ships with [sharp](https://sharp.pixelplumbing.com/) built-in and ca
|
|
|
142
147
|
| Blur hash placeholders | Requires custom hooks | ThumbHash generated automatically |
|
|
143
148
|
| Optimization status & savings | Not available | Admin sidebar panel per image |
|
|
144
149
|
| Bulk re-process existing images | Not available | One-click regeneration with progress tracking |
|
|
145
|
-
| Next.js `<Image>` with blur placeholder | Manual wiring | Drop-in `<ImageBox>`
|
|
150
|
+
| Next.js `<Image>` with blur placeholder | Manual wiring | Drop-in `<ImageBox>` / `<FadeImage>` components |
|
|
146
151
|
| Per-collection format/quality overrides | N/A | Supported |
|
|
147
152
|
|
|
148
153
|
### CPU & Resource Impact
|
|
@@ -167,7 +172,7 @@ A **Regenerate Images** button appears in collection list views, allowing you to
|
|
|
167
172
|
|
|
168
173
|
## ImageBox Component
|
|
169
174
|
|
|
170
|
-
The plugin exports an `ImageBox` component — a Next.js `<Image>` wrapper that automatically applies ThumbHash blur placeholders:
|
|
175
|
+
The plugin exports an `ImageBox` component — a Next.js `<Image>` wrapper that automatically applies ThumbHash blur placeholders with a smooth blur-to-sharp fade transition:
|
|
171
176
|
|
|
172
177
|
```tsx
|
|
173
178
|
import { ImageBox } from '@inoo-ch/payload-image-optimizer/client'
|
|
@@ -177,10 +182,17 @@ import { ImageBox } from '@inoo-ch/payload-image-optimizer/client'
|
|
|
177
182
|
|
|
178
183
|
// Or use a plain URL string
|
|
179
184
|
<ImageBox media="/images/photo.jpg" alt="Photo" width={800} height={600} />
|
|
185
|
+
|
|
186
|
+
// Disable fade animation
|
|
187
|
+
<ImageBox media={doc.image} alt="Photo" fade={false} />
|
|
188
|
+
|
|
189
|
+
// Custom fade duration (default: 500ms)
|
|
190
|
+
<ImageBox media={doc.image} alt="Photo" fadeDuration={300} />
|
|
180
191
|
```
|
|
181
192
|
|
|
182
193
|
**Features:**
|
|
183
194
|
- Automatic ThumbHash `blurDataURL` from the media document
|
|
195
|
+
- Smooth blur-to-sharp fade transition on load (enabled by default)
|
|
184
196
|
- Respects Payload focal point (`focalX` / `focalY`) for `objectPosition`
|
|
185
197
|
- Lazy loading by default, with `priority` prop for above-the-fold images
|
|
186
198
|
- Cache busting via `updatedAt` timestamp
|
|
@@ -250,7 +262,7 @@ Copy-paste this instruction to your AI coding agent to have it autonomously inte
|
|
|
250
262
|
>
|
|
251
263
|
> 1. Which upload collections should be optimized and with what settings
|
|
252
264
|
> 2. Whether to use `replaceOriginal` or keep originals alongside variants
|
|
253
|
-
> 3. Where to add `<ImageBox
|
|
265
|
+
> 3. Where to add `<ImageBox>`, `<FadeImage>`, or `getImageOptimizerProps()` in the frontend for ThumbHash blur placeholders with smooth fade-in and focal point support
|
|
254
266
|
> 4. Whether any existing image rendering code should use the optimized variants
|
|
255
267
|
>
|
|
256
268
|
> Use the zero-config default (`collections: { <slug>: true }`) unless the project has specific requirements that call for custom settings.
|
|
@@ -259,7 +271,7 @@ Copy-paste this instruction to your AI coding agent to have it autonomously inte
|
|
|
259
271
|
|
|
260
272
|
This plugin is open source and we welcome community involvement:
|
|
261
273
|
|
|
262
|
-
- **Issues** — Found a bug or have a feature request? [Open an issue](https://github.com/payloadcms-
|
|
274
|
+
- **Issues** — Found a bug or have a feature request? [Open an issue](https://github.com/PascalEugster/payloadcms-plugin-image-optimizer/issues).
|
|
263
275
|
- **Pull Requests** — PRs are welcome! Please open an issue first to discuss larger changes.
|
|
264
276
|
|
|
265
277
|
All changes are reviewed and merged by the package maintainer at [inoo.ch](https://inoo.ch).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type ImageProps } from 'next/image';
|
|
3
|
+
import type { ImageOptimizerProps } from '../utilities/getImageOptimizerProps.js';
|
|
4
|
+
export interface FadeImageProps extends Omit<ImageProps, 'placeholder' | 'blurDataURL' | 'onLoad'> {
|
|
5
|
+
/** Props returned by `getImageOptimizerProps()`. */
|
|
6
|
+
optimizerProps: ImageOptimizerProps;
|
|
7
|
+
/** Duration of the fade animation in milliseconds. Defaults to `500`. */
|
|
8
|
+
fadeDuration?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A Next.js `<Image>` wrapper that applies ThumbHash blur placeholders with a
|
|
12
|
+
* smooth blur-to-sharp fade transition on load.
|
|
13
|
+
*
|
|
14
|
+
* Use this when you call `getImageOptimizerProps()` manually instead of using `ImageBox`:
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { FadeImage, getImageOptimizerProps } from '@inoo-ch/payload-image-optimizer/client'
|
|
18
|
+
*
|
|
19
|
+
* const optimizerProps = getImageOptimizerProps(resource)
|
|
20
|
+
* <FadeImage src={src} alt="" optimizerProps={optimizerProps} width={800} height={600} />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare const FadeImage: React.FC<FadeImageProps>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import NextImage from 'next/image';
|
|
5
|
+
/**
|
|
6
|
+
* A Next.js `<Image>` wrapper that applies ThumbHash blur placeholders with a
|
|
7
|
+
* smooth blur-to-sharp fade transition on load.
|
|
8
|
+
*
|
|
9
|
+
* Use this when you call `getImageOptimizerProps()` manually instead of using `ImageBox`:
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { FadeImage, getImageOptimizerProps } from '@inoo-ch/payload-image-optimizer/client'
|
|
13
|
+
*
|
|
14
|
+
* const optimizerProps = getImageOptimizerProps(resource)
|
|
15
|
+
* <FadeImage src={src} alt="" optimizerProps={optimizerProps} width={800} height={600} />
|
|
16
|
+
* ```
|
|
17
|
+
*/ export const FadeImage = ({ optimizerProps, style, fadeDuration = 500, ...props })=>{
|
|
18
|
+
const [loaded, setLoaded] = useState(false);
|
|
19
|
+
const { blurDataURL, style: optimizerStyle } = optimizerProps;
|
|
20
|
+
return /*#__PURE__*/ _jsx(NextImage, {
|
|
21
|
+
...props,
|
|
22
|
+
placeholder: blurDataURL ? 'blur' : 'empty',
|
|
23
|
+
blurDataURL: blurDataURL,
|
|
24
|
+
style: {
|
|
25
|
+
...optimizerStyle,
|
|
26
|
+
...style,
|
|
27
|
+
filter: loaded ? 'blur(0px)' : 'blur(20px)',
|
|
28
|
+
transition: loaded ? `filter ${fadeDuration}ms ease-in-out` : undefined
|
|
29
|
+
},
|
|
30
|
+
onLoad: ()=>setLoaded(true)
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=FadeImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/FadeImage.tsx"],"sourcesContent":["'use client'\n\nimport React, { useState } from 'react'\nimport NextImage, { type ImageProps } from 'next/image'\nimport type { ImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'\n\nexport interface FadeImageProps extends Omit<ImageProps, 'placeholder' | 'blurDataURL' | 'onLoad'> {\n /** Props returned by `getImageOptimizerProps()`. */\n optimizerProps: ImageOptimizerProps\n /** Duration of the fade animation in milliseconds. Defaults to `500`. */\n fadeDuration?: number\n}\n\n/**\n * A Next.js `<Image>` wrapper that applies ThumbHash blur placeholders with a\n * smooth blur-to-sharp fade transition on load.\n *\n * Use this when you call `getImageOptimizerProps()` manually instead of using `ImageBox`:\n *\n * ```tsx\n * import { FadeImage, getImageOptimizerProps } from '@inoo-ch/payload-image-optimizer/client'\n *\n * const optimizerProps = getImageOptimizerProps(resource)\n * <FadeImage src={src} alt=\"\" optimizerProps={optimizerProps} width={800} height={600} />\n * ```\n */\nexport const FadeImage: React.FC<FadeImageProps> = ({\n optimizerProps,\n style,\n fadeDuration = 500,\n ...props\n}) => {\n const [loaded, setLoaded] = useState(false)\n\n const { blurDataURL, style: optimizerStyle } = optimizerProps\n\n return (\n <NextImage\n {...props}\n placeholder={blurDataURL ? 'blur' : 'empty'}\n blurDataURL={blurDataURL}\n style={{\n ...optimizerStyle,\n ...style,\n filter: loaded ? 'blur(0px)' : 'blur(20px)',\n transition: loaded ? `filter ${fadeDuration}ms ease-in-out` : undefined,\n }}\n onLoad={() => setLoaded(true)}\n />\n )\n}\n"],"names":["React","useState","NextImage","FadeImage","optimizerProps","style","fadeDuration","props","loaded","setLoaded","blurDataURL","optimizerStyle","placeholder","filter","transition","undefined","onLoad"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,QAAQ,QAAQ,QAAO;AACvC,OAAOC,eAAoC,aAAY;AAUvD;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMC,YAAsC,CAAC,EAClDC,cAAc,EACdC,KAAK,EACLC,eAAe,GAAG,EAClB,GAAGC,OACJ;IACC,MAAM,CAACC,QAAQC,UAAU,GAAGR,SAAS;IAErC,MAAM,EAAES,WAAW,EAAEL,OAAOM,cAAc,EAAE,GAAGP;IAE/C,qBACE,KAACF;QACE,GAAGK,KAAK;QACTK,aAAaF,cAAc,SAAS;QACpCA,aAAaA;QACbL,OAAO;YACL,GAAGM,cAAc;YACjB,GAAGN,KAAK;YACRQ,QAAQL,SAAS,cAAc;YAC/BM,YAAYN,SAAS,CAAC,OAAO,EAAEF,aAAa,cAAc,CAAC,GAAGS;QAChE;QACAC,QAAQ,IAAMP,UAAU;;AAG9B,EAAC"}
|
|
@@ -4,5 +4,9 @@ import type { MediaResource } from '../types.js';
|
|
|
4
4
|
export interface ImageBoxProps extends Omit<ImageProps, 'src' | 'alt'> {
|
|
5
5
|
media: MediaResource | string;
|
|
6
6
|
alt?: string;
|
|
7
|
+
/** Enable smooth blur-to-sharp fade transition on load. Defaults to `true`. */
|
|
8
|
+
fade?: boolean;
|
|
9
|
+
/** Duration of the fade animation in milliseconds. Defaults to `500`. */
|
|
10
|
+
fadeDuration?: number;
|
|
7
11
|
}
|
|
8
12
|
export declare const ImageBox: React.FC<ImageBoxProps>;
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import React from 'react';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
4
|
import NextImage from 'next/image';
|
|
5
5
|
import { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js';
|
|
6
|
-
export const ImageBox = ({ media, alt: altFromProps, fill, sizes, priority, loading: loadingFromProps, style: styleFromProps, ...props })=>{
|
|
6
|
+
export const ImageBox = ({ media, alt: altFromProps, fill, sizes, priority, loading: loadingFromProps, style: styleFromProps, fade = true, fadeDuration = 500, ...props })=>{
|
|
7
|
+
const [loaded, setLoaded] = useState(false);
|
|
7
8
|
const loading = priority ? undefined : loadingFromProps ?? 'lazy';
|
|
9
|
+
const fadeStyle = fade ? {
|
|
10
|
+
filter: loaded ? 'blur(0px)' : 'blur(20px)',
|
|
11
|
+
transition: loaded ? `filter ${fadeDuration}ms ease-in-out` : undefined
|
|
12
|
+
} : undefined;
|
|
8
13
|
if (typeof media === 'string') {
|
|
9
14
|
return /*#__PURE__*/ _jsx(NextImage, {
|
|
10
15
|
...props,
|
|
@@ -16,10 +21,12 @@ export const ImageBox = ({ media, alt: altFromProps, fill, sizes, priority, load
|
|
|
16
21
|
style: {
|
|
17
22
|
objectFit: 'cover',
|
|
18
23
|
objectPosition: 'center',
|
|
24
|
+
...fadeStyle,
|
|
19
25
|
...styleFromProps
|
|
20
26
|
},
|
|
21
27
|
priority: priority,
|
|
22
|
-
loading: loading
|
|
28
|
+
loading: loading,
|
|
29
|
+
onLoad: fade ? ()=>setLoaded(true) : undefined
|
|
23
30
|
});
|
|
24
31
|
}
|
|
25
32
|
const width = media.width ?? undefined;
|
|
@@ -39,12 +46,14 @@ export const ImageBox = ({ media, alt: altFromProps, fill, sizes, priority, load
|
|
|
39
46
|
style: {
|
|
40
47
|
objectFit: 'cover',
|
|
41
48
|
...optimizerProps.style,
|
|
49
|
+
...fadeStyle,
|
|
42
50
|
...styleFromProps
|
|
43
51
|
},
|
|
44
52
|
placeholder: optimizerProps.placeholder,
|
|
45
53
|
blurDataURL: optimizerProps.blurDataURL,
|
|
46
54
|
priority: priority,
|
|
47
|
-
loading: loading
|
|
55
|
+
loading: loading,
|
|
56
|
+
onLoad: fade ? ()=>setLoaded(true) : undefined
|
|
48
57
|
});
|
|
49
58
|
};
|
|
50
59
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/ImageBox.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport NextImage, { type ImageProps } from 'next/image'\nimport type { MediaResource } from '../types.js'\nimport { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'\n\nexport interface ImageBoxProps extends Omit<ImageProps, 'src' | 'alt'> {\n media: MediaResource | string\n alt?: string\n}\n\nexport const ImageBox: React.FC<ImageBoxProps> = ({\n media,\n alt: altFromProps,\n fill,\n sizes,\n priority,\n loading: loadingFromProps,\n style: styleFromProps,\n ...props\n}) => {\n const loading = priority ? undefined : (loadingFromProps ?? 'lazy')\n\n if (typeof media === 'string') {\n return (\n <NextImage\n {...props}\n src={media}\n alt={altFromProps || ''}\n quality={80}\n fill={fill}\n sizes={sizes}\n style={{ objectFit: 'cover', objectPosition: 'center', ...styleFromProps }}\n priority={priority}\n loading={loading}\n />\n )\n }\n\n const width = media.width ?? undefined\n const height = media.height ?? undefined\n const alt = altFromProps || (media as any).alt || media.filename || ''\n const src = media.url ? `${media.url}${media.updatedAt ? `?${media.updatedAt}` : ''}` : ''\n\n const optimizerProps = getImageOptimizerProps(media)\n\n return (\n <NextImage\n {...props}\n src={src}\n alt={alt}\n quality={80}\n fill={fill}\n width={!fill ? width : undefined}\n height={!fill ? height : undefined}\n sizes={sizes}\n style={{ objectFit: 'cover', ...optimizerProps.style, ...styleFromProps }}\n placeholder={optimizerProps.placeholder}\n blurDataURL={optimizerProps.blurDataURL}\n priority={priority}\n loading={loading}\n />\n )\n}\n"],"names":["React","NextImage","getImageOptimizerProps","ImageBox","media","alt","altFromProps","fill","sizes","priority","loading","loadingFromProps","style","styleFromProps","props","undefined","src","quality","objectFit","objectPosition","width","height","filename","url","updatedAt","optimizerProps","placeholder","blurDataURL"],"mappings":"AAAA;;AAEA,OAAOA,
|
|
1
|
+
{"version":3,"sources":["../../src/components/ImageBox.tsx"],"sourcesContent":["'use client'\n\nimport React, { useState } from 'react'\nimport NextImage, { type ImageProps } from 'next/image'\nimport type { MediaResource } from '../types.js'\nimport { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'\n\nexport interface ImageBoxProps extends Omit<ImageProps, 'src' | 'alt'> {\n media: MediaResource | string\n alt?: string\n /** Enable smooth blur-to-sharp fade transition on load. Defaults to `true`. */\n fade?: boolean\n /** Duration of the fade animation in milliseconds. Defaults to `500`. */\n fadeDuration?: number\n}\n\nexport const ImageBox: React.FC<ImageBoxProps> = ({\n media,\n alt: altFromProps,\n fill,\n sizes,\n priority,\n loading: loadingFromProps,\n style: styleFromProps,\n fade = true,\n fadeDuration = 500,\n ...props\n}) => {\n const [loaded, setLoaded] = useState(false)\n const loading = priority ? undefined : (loadingFromProps ?? 'lazy')\n\n const fadeStyle = fade\n ? {\n filter: loaded ? 'blur(0px)' : 'blur(20px)',\n transition: loaded ? `filter ${fadeDuration}ms ease-in-out` : undefined,\n }\n : undefined\n\n if (typeof media === 'string') {\n return (\n <NextImage\n {...props}\n src={media}\n alt={altFromProps || ''}\n quality={80}\n fill={fill}\n sizes={sizes}\n style={{ objectFit: 'cover', objectPosition: 'center', ...fadeStyle, ...styleFromProps }}\n priority={priority}\n loading={loading}\n onLoad={fade ? () => setLoaded(true) : undefined}\n />\n )\n }\n\n const width = media.width ?? undefined\n const height = media.height ?? undefined\n const alt = altFromProps || (media as any).alt || media.filename || ''\n const src = media.url ? `${media.url}${media.updatedAt ? `?${media.updatedAt}` : ''}` : ''\n\n const optimizerProps = getImageOptimizerProps(media)\n\n return (\n <NextImage\n {...props}\n src={src}\n alt={alt}\n quality={80}\n fill={fill}\n width={!fill ? width : undefined}\n height={!fill ? height : undefined}\n sizes={sizes}\n style={{ objectFit: 'cover', ...optimizerProps.style, ...fadeStyle, ...styleFromProps }}\n placeholder={optimizerProps.placeholder}\n blurDataURL={optimizerProps.blurDataURL}\n priority={priority}\n loading={loading}\n onLoad={fade ? () => setLoaded(true) : undefined}\n />\n )\n}\n"],"names":["React","useState","NextImage","getImageOptimizerProps","ImageBox","media","alt","altFromProps","fill","sizes","priority","loading","loadingFromProps","style","styleFromProps","fade","fadeDuration","props","loaded","setLoaded","undefined","fadeStyle","filter","transition","src","quality","objectFit","objectPosition","onLoad","width","height","filename","url","updatedAt","optimizerProps","placeholder","blurDataURL"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,QAAQ,QAAQ,QAAO;AACvC,OAAOC,eAAoC,aAAY;AAEvD,SAASC,sBAAsB,QAAQ,yCAAwC;AAW/E,OAAO,MAAMC,WAAoC,CAAC,EAChDC,KAAK,EACLC,KAAKC,YAAY,EACjBC,IAAI,EACJC,KAAK,EACLC,QAAQ,EACRC,SAASC,gBAAgB,EACzBC,OAAOC,cAAc,EACrBC,OAAO,IAAI,EACXC,eAAe,GAAG,EAClB,GAAGC,OACJ;IACC,MAAM,CAACC,QAAQC,UAAU,GAAGlB,SAAS;IACrC,MAAMU,UAAUD,WAAWU,YAAaR,oBAAoB;IAE5D,MAAMS,YAAYN,OACd;QACEO,QAAQJ,SAAS,cAAc;QAC/BK,YAAYL,SAAS,CAAC,OAAO,EAAEF,aAAa,cAAc,CAAC,GAAGI;IAChE,IACAA;IAEJ,IAAI,OAAOf,UAAU,UAAU;QAC7B,qBACE,KAACH;YACE,GAAGe,KAAK;YACTO,KAAKnB;YACLC,KAAKC,gBAAgB;YACrBkB,SAAS;YACTjB,MAAMA;YACNC,OAAOA;YACPI,OAAO;gBAAEa,WAAW;gBAASC,gBAAgB;gBAAU,GAAGN,SAAS;gBAAE,GAAGP,cAAc;YAAC;YACvFJ,UAAUA;YACVC,SAASA;YACTiB,QAAQb,OAAO,IAAMI,UAAU,QAAQC;;IAG7C;IAEA,MAAMS,QAAQxB,MAAMwB,KAAK,IAAIT;IAC7B,MAAMU,SAASzB,MAAMyB,MAAM,IAAIV;IAC/B,MAAMd,MAAMC,gBAAgB,AAACF,MAAcC,GAAG,IAAID,MAAM0B,QAAQ,IAAI;IACpE,MAAMP,MAAMnB,MAAM2B,GAAG,GAAG,GAAG3B,MAAM2B,GAAG,GAAG3B,MAAM4B,SAAS,GAAG,CAAC,CAAC,EAAE5B,MAAM4B,SAAS,EAAE,GAAG,IAAI,GAAG;IAExF,MAAMC,iBAAiB/B,uBAAuBE;IAE9C,qBACE,KAACH;QACE,GAAGe,KAAK;QACTO,KAAKA;QACLlB,KAAKA;QACLmB,SAAS;QACTjB,MAAMA;QACNqB,OAAO,CAACrB,OAAOqB,QAAQT;QACvBU,QAAQ,CAACtB,OAAOsB,SAASV;QACzBX,OAAOA;QACPI,OAAO;YAAEa,WAAW;YAAS,GAAGQ,eAAerB,KAAK;YAAE,GAAGQ,SAAS;YAAE,GAAGP,cAAc;QAAC;QACtFqB,aAAaD,eAAeC,WAAW;QACvCC,aAAaF,eAAeE,WAAW;QACvC1B,UAAUA;QACVC,SAASA;QACTiB,QAAQb,OAAO,IAAMI,UAAU,QAAQC;;AAG7C,EAAC"}
|
package/dist/exports/client.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { OptimizationStatus } from '../components/OptimizationStatus.js';
|
|
2
2
|
export { ImageBox } from '../components/ImageBox.js';
|
|
3
3
|
export type { ImageBoxProps } from '../components/ImageBox.js';
|
|
4
|
+
export { FadeImage } from '../components/FadeImage.js';
|
|
5
|
+
export type { FadeImageProps } from '../components/FadeImage.js';
|
|
4
6
|
export { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js';
|
|
5
7
|
export type { ImageOptimizerProps } from '../utilities/getImageOptimizerProps.js';
|
|
6
8
|
export { RegenerationButton } from '../components/RegenerationButton.js';
|
package/dist/exports/client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { OptimizationStatus } from '../components/OptimizationStatus.js';
|
|
2
2
|
export { ImageBox } from '../components/ImageBox.js';
|
|
3
|
+
export { FadeImage } from '../components/FadeImage.js';
|
|
3
4
|
export { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js';
|
|
4
5
|
export { RegenerationButton } from '../components/RegenerationButton.js';
|
|
5
6
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { OptimizationStatus } from '../components/OptimizationStatus.js'\nexport { ImageBox } from '../components/ImageBox.js'\nexport type { ImageBoxProps } from '../components/ImageBox.js'\nexport { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'\nexport type { ImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'\nexport { RegenerationButton } from '../components/RegenerationButton.js'\n"],"names":["OptimizationStatus","ImageBox","getImageOptimizerProps","RegenerationButton"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,sCAAqC;AACxE,SAASC,QAAQ,QAAQ,4BAA2B;AAEpD,SAASC,sBAAsB,QAAQ,yCAAwC;AAE/E,SAASC,kBAAkB,QAAQ,sCAAqC"}
|
|
1
|
+
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { OptimizationStatus } from '../components/OptimizationStatus.js'\nexport { ImageBox } from '../components/ImageBox.js'\nexport type { ImageBoxProps } from '../components/ImageBox.js'\nexport { FadeImage } from '../components/FadeImage.js'\nexport type { FadeImageProps } from '../components/FadeImage.js'\nexport { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'\nexport type { ImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'\nexport { RegenerationButton } from '../components/RegenerationButton.js'\n"],"names":["OptimizationStatus","ImageBox","FadeImage","getImageOptimizerProps","RegenerationButton"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,sCAAqC;AACxE,SAASC,QAAQ,QAAQ,4BAA2B;AAEpD,SAASC,SAAS,QAAQ,6BAA4B;AAEtD,SAASC,sBAAsB,QAAQ,yCAAwC;AAE/E,SAASC,kBAAkB,QAAQ,sCAAqC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inoo-ch/payload-image-optimizer",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.7",
|
|
4
4
|
"description": "Payload CMS plugin for automatic image optimization — WebP/AVIF conversion, resize, EXIF strip, ThumbHash placeholders, and bulk regeneration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -16,54 +16,39 @@
|
|
|
16
16
|
"resize",
|
|
17
17
|
"compress"
|
|
18
18
|
],
|
|
19
|
-
"homepage": "https://github.com/payloadcms-
|
|
19
|
+
"homepage": "https://github.com/PascalEugster/payloadcms-plugin-image-optimizer",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/payloadcms-
|
|
22
|
+
"url": "https://github.com/PascalEugster/payloadcms-plugin-image-optimizer"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/PascalEugster/payloadcms-plugin-image-optimizer/issues"
|
|
23
26
|
},
|
|
24
27
|
"type": "module",
|
|
25
28
|
"exports": {
|
|
26
29
|
".": {
|
|
27
30
|
"import": "./dist/index.js",
|
|
28
|
-
"types": "./
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
29
32
|
"default": "./dist/index.js"
|
|
30
33
|
},
|
|
31
34
|
"./client": {
|
|
32
35
|
"import": "./dist/exports/client.js",
|
|
33
|
-
"types": "./
|
|
36
|
+
"types": "./dist/exports/client.d.ts",
|
|
34
37
|
"default": "./dist/exports/client.js"
|
|
35
38
|
},
|
|
36
39
|
"./rsc": {
|
|
37
40
|
"import": "./dist/exports/rsc.js",
|
|
38
|
-
"types": "./
|
|
41
|
+
"types": "./dist/exports/rsc.d.ts",
|
|
39
42
|
"default": "./dist/exports/rsc.js"
|
|
40
43
|
}
|
|
41
44
|
},
|
|
42
|
-
"main": "./
|
|
43
|
-
"types": "./
|
|
45
|
+
"main": "./dist/index.js",
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
44
47
|
"files": [
|
|
45
48
|
"dist",
|
|
46
49
|
"src",
|
|
47
50
|
"AGENT_DOCS.md"
|
|
48
51
|
],
|
|
49
|
-
"scripts": {
|
|
50
|
-
"build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
|
|
51
|
-
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
52
|
-
"build:types": "tsc --outDir dist --rootDir ./src",
|
|
53
|
-
"clean": "rimraf {dist,*.tsbuildinfo}",
|
|
54
|
-
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
|
55
|
-
"dev": "next dev dev --turbo",
|
|
56
|
-
"dev:generate-importmap": "pnpm dev:payload generate:importmap",
|
|
57
|
-
"dev:generate-types": "pnpm dev:payload generate:types",
|
|
58
|
-
"dev:payload": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
|
|
59
|
-
"generate:importmap": "pnpm dev:generate-importmap",
|
|
60
|
-
"generate:types": "pnpm dev:generate-types",
|
|
61
|
-
"lint": "eslint",
|
|
62
|
-
"lint:fix": "eslint ./src --fix",
|
|
63
|
-
"test": "pnpm test:int && pnpm test:e2e",
|
|
64
|
-
"test:e2e": "playwright test",
|
|
65
|
-
"test:int": "vitest"
|
|
66
|
-
},
|
|
67
52
|
"devDependencies": {
|
|
68
53
|
"@eslint/eslintrc": "^3.2.0",
|
|
69
54
|
"@payloadcms/db-mongodb": "3.79.0",
|
|
@@ -109,36 +94,26 @@
|
|
|
109
94
|
"node": "^18.20.2 || >=20.9.0",
|
|
110
95
|
"pnpm": "^9 || ^10"
|
|
111
96
|
},
|
|
112
|
-
"publishConfig": {
|
|
113
|
-
"exports": {
|
|
114
|
-
".": {
|
|
115
|
-
"import": "./dist/index.js",
|
|
116
|
-
"types": "./dist/index.d.ts",
|
|
117
|
-
"default": "./dist/index.js"
|
|
118
|
-
},
|
|
119
|
-
"./client": {
|
|
120
|
-
"import": "./dist/exports/client.js",
|
|
121
|
-
"types": "./dist/exports/client.d.ts",
|
|
122
|
-
"default": "./dist/exports/client.js"
|
|
123
|
-
},
|
|
124
|
-
"./rsc": {
|
|
125
|
-
"import": "./dist/exports/rsc.js",
|
|
126
|
-
"types": "./dist/exports/rsc.d.ts",
|
|
127
|
-
"default": "./dist/exports/rsc.js"
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
"main": "./dist/index.js",
|
|
131
|
-
"types": "./dist/index.d.ts"
|
|
132
|
-
},
|
|
133
|
-
"pnpm": {
|
|
134
|
-
"onlyBuiltDependencies": [
|
|
135
|
-
"sharp",
|
|
136
|
-
"esbuild",
|
|
137
|
-
"unrs-resolver"
|
|
138
|
-
]
|
|
139
|
-
},
|
|
140
97
|
"registry": "https://registry.npmjs.org/",
|
|
141
98
|
"dependencies": {
|
|
142
99
|
"thumbhash": "^0.1.1"
|
|
100
|
+
},
|
|
101
|
+
"scripts": {
|
|
102
|
+
"build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
|
|
103
|
+
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
104
|
+
"build:types": "tsc --outDir dist --rootDir ./src",
|
|
105
|
+
"clean": "rimraf {dist,*.tsbuildinfo}",
|
|
106
|
+
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
|
107
|
+
"dev": "next dev dev --turbo",
|
|
108
|
+
"dev:generate-importmap": "pnpm dev:payload generate:importmap",
|
|
109
|
+
"dev:generate-types": "pnpm dev:payload generate:types",
|
|
110
|
+
"dev:payload": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
|
|
111
|
+
"generate:importmap": "pnpm dev:generate-importmap",
|
|
112
|
+
"generate:types": "pnpm dev:generate-types",
|
|
113
|
+
"lint": "eslint",
|
|
114
|
+
"lint:fix": "eslint ./src --fix",
|
|
115
|
+
"test": "pnpm test:int && pnpm test:e2e",
|
|
116
|
+
"test:e2e": "playwright test",
|
|
117
|
+
"test:int": "vitest"
|
|
143
118
|
}
|
|
144
|
-
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react'
|
|
4
|
+
import NextImage, { type ImageProps } from 'next/image'
|
|
5
|
+
import type { ImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'
|
|
6
|
+
|
|
7
|
+
export interface FadeImageProps extends Omit<ImageProps, 'placeholder' | 'blurDataURL' | 'onLoad'> {
|
|
8
|
+
/** Props returned by `getImageOptimizerProps()`. */
|
|
9
|
+
optimizerProps: ImageOptimizerProps
|
|
10
|
+
/** Duration of the fade animation in milliseconds. Defaults to `500`. */
|
|
11
|
+
fadeDuration?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A Next.js `<Image>` wrapper that applies ThumbHash blur placeholders with a
|
|
16
|
+
* smooth blur-to-sharp fade transition on load.
|
|
17
|
+
*
|
|
18
|
+
* Use this when you call `getImageOptimizerProps()` manually instead of using `ImageBox`:
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import { FadeImage, getImageOptimizerProps } from '@inoo-ch/payload-image-optimizer/client'
|
|
22
|
+
*
|
|
23
|
+
* const optimizerProps = getImageOptimizerProps(resource)
|
|
24
|
+
* <FadeImage src={src} alt="" optimizerProps={optimizerProps} width={800} height={600} />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const FadeImage: React.FC<FadeImageProps> = ({
|
|
28
|
+
optimizerProps,
|
|
29
|
+
style,
|
|
30
|
+
fadeDuration = 500,
|
|
31
|
+
...props
|
|
32
|
+
}) => {
|
|
33
|
+
const [loaded, setLoaded] = useState(false)
|
|
34
|
+
|
|
35
|
+
const { blurDataURL, style: optimizerStyle } = optimizerProps
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<NextImage
|
|
39
|
+
{...props}
|
|
40
|
+
placeholder={blurDataURL ? 'blur' : 'empty'}
|
|
41
|
+
blurDataURL={blurDataURL}
|
|
42
|
+
style={{
|
|
43
|
+
...optimizerStyle,
|
|
44
|
+
...style,
|
|
45
|
+
filter: loaded ? 'blur(0px)' : 'blur(20px)',
|
|
46
|
+
transition: loaded ? `filter ${fadeDuration}ms ease-in-out` : undefined,
|
|
47
|
+
}}
|
|
48
|
+
onLoad={() => setLoaded(true)}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import React from 'react'
|
|
3
|
+
import React, { useState } from 'react'
|
|
4
4
|
import NextImage, { type ImageProps } from 'next/image'
|
|
5
5
|
import type { MediaResource } from '../types.js'
|
|
6
6
|
import { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'
|
|
@@ -8,6 +8,10 @@ import { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'
|
|
|
8
8
|
export interface ImageBoxProps extends Omit<ImageProps, 'src' | 'alt'> {
|
|
9
9
|
media: MediaResource | string
|
|
10
10
|
alt?: string
|
|
11
|
+
/** Enable smooth blur-to-sharp fade transition on load. Defaults to `true`. */
|
|
12
|
+
fade?: boolean
|
|
13
|
+
/** Duration of the fade animation in milliseconds. Defaults to `500`. */
|
|
14
|
+
fadeDuration?: number
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export const ImageBox: React.FC<ImageBoxProps> = ({
|
|
@@ -18,10 +22,20 @@ export const ImageBox: React.FC<ImageBoxProps> = ({
|
|
|
18
22
|
priority,
|
|
19
23
|
loading: loadingFromProps,
|
|
20
24
|
style: styleFromProps,
|
|
25
|
+
fade = true,
|
|
26
|
+
fadeDuration = 500,
|
|
21
27
|
...props
|
|
22
28
|
}) => {
|
|
29
|
+
const [loaded, setLoaded] = useState(false)
|
|
23
30
|
const loading = priority ? undefined : (loadingFromProps ?? 'lazy')
|
|
24
31
|
|
|
32
|
+
const fadeStyle = fade
|
|
33
|
+
? {
|
|
34
|
+
filter: loaded ? 'blur(0px)' : 'blur(20px)',
|
|
35
|
+
transition: loaded ? `filter ${fadeDuration}ms ease-in-out` : undefined,
|
|
36
|
+
}
|
|
37
|
+
: undefined
|
|
38
|
+
|
|
25
39
|
if (typeof media === 'string') {
|
|
26
40
|
return (
|
|
27
41
|
<NextImage
|
|
@@ -31,9 +45,10 @@ export const ImageBox: React.FC<ImageBoxProps> = ({
|
|
|
31
45
|
quality={80}
|
|
32
46
|
fill={fill}
|
|
33
47
|
sizes={sizes}
|
|
34
|
-
style={{ objectFit: 'cover', objectPosition: 'center', ...styleFromProps }}
|
|
48
|
+
style={{ objectFit: 'cover', objectPosition: 'center', ...fadeStyle, ...styleFromProps }}
|
|
35
49
|
priority={priority}
|
|
36
50
|
loading={loading}
|
|
51
|
+
onLoad={fade ? () => setLoaded(true) : undefined}
|
|
37
52
|
/>
|
|
38
53
|
)
|
|
39
54
|
}
|
|
@@ -55,11 +70,12 @@ export const ImageBox: React.FC<ImageBoxProps> = ({
|
|
|
55
70
|
width={!fill ? width : undefined}
|
|
56
71
|
height={!fill ? height : undefined}
|
|
57
72
|
sizes={sizes}
|
|
58
|
-
style={{ objectFit: 'cover', ...optimizerProps.style, ...styleFromProps }}
|
|
73
|
+
style={{ objectFit: 'cover', ...optimizerProps.style, ...fadeStyle, ...styleFromProps }}
|
|
59
74
|
placeholder={optimizerProps.placeholder}
|
|
60
75
|
blurDataURL={optimizerProps.blurDataURL}
|
|
61
76
|
priority={priority}
|
|
62
77
|
loading={loading}
|
|
78
|
+
onLoad={fade ? () => setLoaded(true) : undefined}
|
|
63
79
|
/>
|
|
64
80
|
)
|
|
65
81
|
}
|
package/src/exports/client.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { OptimizationStatus } from '../components/OptimizationStatus.js'
|
|
2
2
|
export { ImageBox } from '../components/ImageBox.js'
|
|
3
3
|
export type { ImageBoxProps } from '../components/ImageBox.js'
|
|
4
|
+
export { FadeImage } from '../components/FadeImage.js'
|
|
5
|
+
export type { FadeImageProps } from '../components/FadeImage.js'
|
|
4
6
|
export { getImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'
|
|
5
7
|
export type { ImageOptimizerProps } from '../utilities/getImageOptimizerProps.js'
|
|
6
8
|
export { RegenerationButton } from '../components/RegenerationButton.js'
|