@lonik/oh-image 1.0.4 → 1.2.0
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/dist/client.d.ts +14 -1
- package/dist/plugin.d.ts +2 -46
- package/dist/plugin.js +33 -29
- package/dist/react.d.ts +23 -37
- package/dist/react.js +6 -9
- package/package.json +6 -6
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
+
export interface ImageSrc {
|
|
2
|
+
/** Original width of the source image in pixels */
|
|
3
|
+
width: number;
|
|
4
|
+
/** Original height of the source image in pixels */
|
|
5
|
+
height: number;
|
|
6
|
+
/** URL to the placeholder image (if placeholder was enabled) */
|
|
7
|
+
placeholderUrl?: string;
|
|
8
|
+
/** Array of responsive image sources at different breakpoints */
|
|
9
|
+
srcSets: string;
|
|
10
|
+
/** URL to the main processed image */
|
|
11
|
+
src: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
1
14
|
declare module "*?oh" {
|
|
2
|
-
const imageSrc:
|
|
15
|
+
const imageSrc: ImageSrc;
|
|
3
16
|
export default imageSrc;
|
|
4
17
|
}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -3,18 +3,10 @@ import * as vite0 from "vite";
|
|
|
3
3
|
import * as rollup0 from "rollup";
|
|
4
4
|
|
|
5
5
|
//#region src/plugin/types.d.ts
|
|
6
|
-
|
|
7
|
-
* Configuration options for the oh-image Vite plugin.
|
|
8
|
-
* Extends ImageOptions with all properties required, plus plugin-specific settings.
|
|
9
|
-
*/
|
|
10
|
-
interface PluginConfig extends Required<ImageOptions> {
|
|
6
|
+
interface PluginConfig extends Required<Pick<ImageOptions, "placeholder" | "bps" | "format">> {
|
|
11
7
|
/** Directory name where processed images will be output during build */
|
|
12
8
|
distDir: string;
|
|
13
9
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Options for image processing and transformation.
|
|
16
|
-
* Can be passed via query parameters or plugin configuration.
|
|
17
|
-
*/
|
|
18
10
|
interface ImageOptions {
|
|
19
11
|
/** Target width for the processed image in pixels */
|
|
20
12
|
width?: number | null;
|
|
@@ -26,44 +18,8 @@ interface ImageOptions {
|
|
|
26
18
|
blur?: number | boolean;
|
|
27
19
|
/** Whether to generate a placeholder image for lazy loading */
|
|
28
20
|
placeholder?: boolean;
|
|
29
|
-
/** Width of the placeholder image in pixels */
|
|
30
|
-
placeholderW?: number;
|
|
31
|
-
/** Height of the placeholder image in pixels */
|
|
32
|
-
placeholderH?: number;
|
|
33
|
-
/** Output format for the placeholder image */
|
|
34
|
-
placeholderF?: keyof FormatEnum;
|
|
35
|
-
/** Blur setting for the placeholder (true for default, or sigma value) */
|
|
36
|
-
placeholderB: boolean | number;
|
|
37
21
|
/** Breakpoints array - widths in pixels for responsive srcSet generation */
|
|
38
22
|
bps?: number[];
|
|
39
|
-
/** Output format for srcSet images */
|
|
40
|
-
srcSetsF: keyof FormatEnum;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Represents a single entry in the srcSet array.
|
|
44
|
-
* Used for responsive image loading at different viewport widths.
|
|
45
|
-
*/
|
|
46
|
-
interface ImageSrcSet {
|
|
47
|
-
/** Width descriptor (e.g., '640w', '1080w') */
|
|
48
|
-
width: string;
|
|
49
|
-
/** URL or path to the image at this breakpoint */
|
|
50
|
-
src: string;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* The processed image source object returned by the plugin.
|
|
54
|
-
* Contains all URLs and metadata needed for responsive image rendering.
|
|
55
|
-
*/
|
|
56
|
-
interface ImageSrc {
|
|
57
|
-
/** Original width of the source image in pixels */
|
|
58
|
-
width: number;
|
|
59
|
-
/** Original height of the source image in pixels */
|
|
60
|
-
height: number;
|
|
61
|
-
/** URL to the placeholder image (if placeholder was enabled) */
|
|
62
|
-
placeholderUrl?: string;
|
|
63
|
-
/** Array of responsive image sources at different breakpoints */
|
|
64
|
-
srcSets: ImageSrcSet[];
|
|
65
|
-
/** URL to the main processed image */
|
|
66
|
-
src: string;
|
|
67
23
|
}
|
|
68
24
|
//#endregion
|
|
69
25
|
//#region src/plugin/plugin.d.ts
|
|
@@ -81,4 +37,4 @@ declare function ohImage(options?: Partial<PluginConfig>): {
|
|
|
81
37
|
writeBundle(this: rollup0.PluginContext): Promise<void>;
|
|
82
38
|
};
|
|
83
39
|
//#endregion
|
|
84
|
-
export { type ImageOptions, type
|
|
40
|
+
export { type ImageOptions, type PluginConfig, ohImage };
|
package/dist/plugin.js
CHANGED
|
@@ -60,6 +60,9 @@ async function processImage(path, options) {
|
|
|
60
60
|
|
|
61
61
|
//#endregion
|
|
62
62
|
//#region src/plugin/plugin.ts
|
|
63
|
+
const DEFAULT_IMAGE_FORMAT = "webp";
|
|
64
|
+
const PLACEHOLDER_IMG_SIZE = 8;
|
|
65
|
+
const PLACEHOLDER_BLUR_QUALITY = 70;
|
|
63
66
|
const DEFAULT_CONFIGS = {
|
|
64
67
|
distDir: "oh-images",
|
|
65
68
|
bps: [
|
|
@@ -76,18 +79,10 @@ const DEFAULT_CONFIGS = {
|
|
|
76
79
|
1920
|
|
77
80
|
],
|
|
78
81
|
format: "webp",
|
|
79
|
-
|
|
80
|
-
width: null,
|
|
81
|
-
height: null,
|
|
82
|
-
placeholder: false,
|
|
83
|
-
placeholderH: 100,
|
|
84
|
-
placeholderW: 100,
|
|
85
|
-
placeholderB: true,
|
|
86
|
-
placeholderF: "webp",
|
|
87
|
-
srcSetsF: "webp"
|
|
82
|
+
placeholder: false
|
|
88
83
|
};
|
|
89
84
|
const PROCESS_KEY = "oh";
|
|
90
|
-
const SUPPORTED_IMAGE_FORMATS = /\.(jpe?g|png|webp|avif|gif|
|
|
85
|
+
const SUPPORTED_IMAGE_FORMATS = /\.(jpe?g|png|webp|avif|gif|svg)(\?.*)?$/i;
|
|
91
86
|
const DEV_DIR = "/@oh-images/";
|
|
92
87
|
function ohImage(options) {
|
|
93
88
|
let isBuild = false;
|
|
@@ -163,7 +158,6 @@ function ohImage(options) {
|
|
|
163
158
|
const mainEntry = {
|
|
164
159
|
width: mergedOptions.width,
|
|
165
160
|
height: mergedOptions.height,
|
|
166
|
-
blur: mergedOptions.blur,
|
|
167
161
|
format: mergedOptions.format,
|
|
168
162
|
origin
|
|
169
163
|
};
|
|
@@ -172,32 +166,42 @@ function ohImage(options) {
|
|
|
172
166
|
width: metadata.width,
|
|
173
167
|
height: metadata.height,
|
|
174
168
|
src: mainIdentifier,
|
|
175
|
-
srcSets:
|
|
169
|
+
srcSets: ""
|
|
176
170
|
};
|
|
177
171
|
if (parsed.options?.placeholder) {
|
|
178
|
-
|
|
172
|
+
let placeholderHeight = 0;
|
|
173
|
+
let placeholderWidth = 0;
|
|
174
|
+
if (metadata.width >= metadata.height) {
|
|
175
|
+
placeholderWidth = PLACEHOLDER_IMG_SIZE;
|
|
176
|
+
placeholderHeight = Math.max(Math.round(metadata.height / metadata.width * PLACEHOLDER_IMG_SIZE), 1);
|
|
177
|
+
} else {
|
|
178
|
+
placeholderWidth = Math.max(Math.round(metadata.width / metadata.height * PLACEHOLDER_IMG_SIZE), 1);
|
|
179
|
+
placeholderHeight = PLACEHOLDER_IMG_SIZE;
|
|
180
|
+
}
|
|
181
|
+
const placeholderIdentifier = genIdentifier(name, DEFAULT_IMAGE_FORMAT, "placeholder");
|
|
179
182
|
const placeholderEntry = {
|
|
180
|
-
width:
|
|
181
|
-
height:
|
|
182
|
-
format:
|
|
183
|
-
blur:
|
|
183
|
+
width: placeholderWidth,
|
|
184
|
+
height: placeholderHeight,
|
|
185
|
+
format: DEFAULT_IMAGE_FORMAT,
|
|
186
|
+
blur: PLACEHOLDER_BLUR_QUALITY,
|
|
184
187
|
origin
|
|
185
188
|
};
|
|
186
189
|
imageEntries.set(placeholderIdentifier, placeholderEntry);
|
|
187
190
|
src.placeholderUrl = placeholderIdentifier;
|
|
188
191
|
}
|
|
189
|
-
if (mergedOptions.bps)
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
192
|
+
if (mergedOptions.bps) {
|
|
193
|
+
const srcSets = [];
|
|
194
|
+
for (const breakpoint of mergedOptions.bps) {
|
|
195
|
+
const srcSetIdentifier = genIdentifier(name, DEFAULT_IMAGE_FORMAT, `breakpoint-${breakpoint}`);
|
|
196
|
+
const srcSetEntry = {
|
|
197
|
+
width: breakpoint,
|
|
198
|
+
format: DEFAULT_IMAGE_FORMAT,
|
|
199
|
+
origin
|
|
200
|
+
};
|
|
201
|
+
imageEntries.set(srcSetIdentifier, srcSetEntry);
|
|
202
|
+
srcSets.push(`${srcSetIdentifier} ${breakpoint}w`);
|
|
203
|
+
}
|
|
204
|
+
src.srcSets = srcSets.join(", ");
|
|
201
205
|
}
|
|
202
206
|
return `export default ${JSON.stringify(src)};`;
|
|
203
207
|
} catch (err) {
|
package/dist/react.d.ts
CHANGED
|
@@ -1,55 +1,41 @@
|
|
|
1
1
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { ImgHTMLAttributes } from "react";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
5
|
-
/**
|
|
6
|
-
* Image source type - can be either a simple URL string or a full ImageSrc object
|
|
7
|
-
*/
|
|
8
|
-
type ImageSrcType = string | ImageSrc;
|
|
9
|
-
/**
|
|
10
|
-
* Optimized image source with multiple responsive variants
|
|
11
|
-
*/
|
|
4
|
+
//#region src/client.d.ts
|
|
12
5
|
interface ImageSrc {
|
|
13
|
-
/** Original image
|
|
6
|
+
/** Original width of the source image in pixels */
|
|
14
7
|
width: number;
|
|
15
|
-
/** Original image
|
|
8
|
+
/** Original height of the source image in pixels */
|
|
16
9
|
height: number;
|
|
17
|
-
/**
|
|
10
|
+
/** URL to the placeholder image (if placeholder was enabled) */
|
|
18
11
|
placeholderUrl?: string;
|
|
19
|
-
/** Array of responsive image
|
|
20
|
-
srcSets:
|
|
21
|
-
/**
|
|
12
|
+
/** Array of responsive image sources at different breakpoints */
|
|
13
|
+
srcSets: string;
|
|
14
|
+
/** URL to the main processed image */
|
|
22
15
|
src: string;
|
|
23
16
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
interface ImageSrcSet {
|
|
28
|
-
/** Width descriptor (e.g., "1920w") */
|
|
29
|
-
width: string;
|
|
30
|
-
/** Image URL for this variant */
|
|
31
|
-
src: string;
|
|
17
|
+
declare module "*?oh" {
|
|
18
|
+
const imageSrc: ImageSrc;
|
|
19
|
+
export default imageSrc;
|
|
32
20
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/** Load the image immediately, bypassing lazy loading */
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/react/types.d.ts
|
|
23
|
+
type ImageSrcType = string | ImageSrc;
|
|
24
|
+
interface ImageProps extends Partial<Pick<ImgHTMLAttributes<HTMLImageElement>, "alt" | "fetchPriority" | "decoding" | "loading" | "height" | "width" | "srcSet" | "className" | "sizes" | "style">> {
|
|
25
|
+
/** Configures the Image component to load the image immediately. */
|
|
39
26
|
asap?: boolean;
|
|
40
|
-
/**
|
|
27
|
+
/** */
|
|
41
28
|
src: ImageSrcType;
|
|
42
|
-
/**
|
|
29
|
+
/** The URL of the placeholder image to display while loading. */
|
|
43
30
|
placeholderUrl?: string | undefined;
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/** Make image fill its container (position: absolute) */
|
|
31
|
+
/**
|
|
32
|
+
* Sets the image to "fill mode", which eliminates the height/width requirement and adds
|
|
33
|
+
* styles such that the image fills its containing element.
|
|
34
|
+
*/
|
|
49
35
|
fill?: boolean;
|
|
50
36
|
}
|
|
51
37
|
//#endregion
|
|
52
38
|
//#region src/react/image.d.ts
|
|
53
39
|
declare function Image(props: ImageProps): react_jsx_runtime0.JSX.Element;
|
|
54
40
|
//#endregion
|
|
55
|
-
export { Image, type ImageProps
|
|
41
|
+
export { Image, type ImageProps };
|
package/dist/react.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as ReactDOM from "react-dom";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/react/image.tsx
|
|
5
|
+
const preload = "preload" in ReactDOM && typeof ReactDOM.preload === "function" ? ReactDOM.preload : null;
|
|
5
6
|
function resolveOptions(props) {
|
|
6
7
|
const { src, ...rest } = props;
|
|
7
8
|
const resolved = { ...rest };
|
|
@@ -9,14 +10,14 @@ function resolveOptions(props) {
|
|
|
9
10
|
resolved.src = src.src;
|
|
10
11
|
resolved.width ??= src.width;
|
|
11
12
|
resolved.height ??= src.height;
|
|
12
|
-
resolved.
|
|
13
|
+
resolved.srcSet ??= src.srcSets;
|
|
13
14
|
resolved.placeholderUrl ??= src.placeholderUrl;
|
|
14
15
|
} else resolved.src = src;
|
|
15
16
|
if (props.asap) {
|
|
16
17
|
resolved.decoding = "async";
|
|
17
18
|
resolved.loading = "eager";
|
|
18
19
|
resolved.fetchPriority = "high";
|
|
19
|
-
preload(resolved.src, {
|
|
20
|
+
if (preload) preload(resolved.src, {
|
|
20
21
|
as: "image",
|
|
21
22
|
fetchPriority: "high"
|
|
22
23
|
});
|
|
@@ -25,11 +26,7 @@ function resolveOptions(props) {
|
|
|
25
26
|
return resolved;
|
|
26
27
|
}
|
|
27
28
|
function getPlaceholderStyles(props) {
|
|
28
|
-
if (!props.
|
|
29
|
-
if (!props.placeholderUrl) {
|
|
30
|
-
console.warn("Blur URL is required for placeholder");
|
|
31
|
-
return {};
|
|
32
|
-
}
|
|
29
|
+
if (!props.placeholderUrl) return {};
|
|
33
30
|
return {
|
|
34
31
|
backgroundPosition: "50% 50%",
|
|
35
32
|
backgroundRepeat: "no-repeat",
|
|
@@ -60,7 +57,7 @@ function Image(props) {
|
|
|
60
57
|
src: options.src,
|
|
61
58
|
width: options.width,
|
|
62
59
|
height: options.height,
|
|
63
|
-
srcSet: options.
|
|
60
|
+
srcSet: options.srcSet,
|
|
64
61
|
alt: options.alt,
|
|
65
62
|
loading: options.loading,
|
|
66
63
|
decoding: options.decoding,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lonik/oh-image",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "A React component library for optimized image handling.",
|
|
6
6
|
"author": "Luka Onikadze <lukonik@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -45,16 +45,16 @@
|
|
|
45
45
|
"prepublishOnly": "pnpm run build"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"react": "
|
|
49
|
-
"react-dom": "
|
|
50
|
-
"sharp": "
|
|
48
|
+
"react": ">=18",
|
|
49
|
+
"react-dom": ">=18",
|
|
50
|
+
"sharp": ">=0.34.5"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@eslint/js": "^9.39.2",
|
|
54
54
|
"@tsconfig/strictest": "^2.0.8",
|
|
55
55
|
"@types/node": "^25.0.3",
|
|
56
|
-
"@types/react": "^
|
|
57
|
-
"@types/react-dom": "^
|
|
56
|
+
"@types/react": "^18",
|
|
57
|
+
"@types/react-dom": "^18",
|
|
58
58
|
"@vitejs/plugin-react": "^5.1.2",
|
|
59
59
|
"@vitest/browser-playwright": "^4.0.16",
|
|
60
60
|
"bumpp": "^10.3.2",
|