@vividwebau/react-static-images 0.1.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/README.md +64 -0
- package/dist/ImageStatic.d.ts +23 -0
- package/dist/ImageStatic.d.ts.map +1 -0
- package/dist/ImageStatic.js +97 -0
- package/dist/ImageStatic.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest-registry.d.ts +4 -0
- package/dist/manifest-registry.d.ts.map +1 -0
- package/dist/manifest-registry.js +8 -0
- package/dist/manifest-registry.js.map +1 -0
- package/dist/manifest.d.ts +11 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +74 -0
- package/dist/manifest.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +16 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +70 -0
- package/dist/utils.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @vividwebau/react-static-images
|
|
2
|
+
|
|
3
|
+
A pure server-component React image component that consumes the static image pipeline’s
|
|
4
|
+
manifest and renders fully responsive, framework‑agnostic `<picture>` markup.
|
|
5
|
+
|
|
6
|
+
This component works across all React SSR/RSC frameworks:
|
|
7
|
+
- Next.js (App Router)
|
|
8
|
+
- Remix
|
|
9
|
+
- Astro
|
|
10
|
+
- Hydrogen
|
|
11
|
+
- Gatsby (SSR)
|
|
12
|
+
- Any React SSR environment
|
|
13
|
+
|
|
14
|
+
No client JavaScript.
|
|
15
|
+
No hydration.
|
|
16
|
+
No framework-specific imports.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- Pure server component (RSC-safe)
|
|
21
|
+
- `<picture>` markup with AVIF/WebP/JPEG fallbacks
|
|
22
|
+
- Responsive `srcset` + `sizes`
|
|
23
|
+
- Native lazy loading (`loading="lazy"`)
|
|
24
|
+
- CSS-only blur-up placeholders
|
|
25
|
+
- Container-query-friendly sizing
|
|
26
|
+
- Optional preload hints
|
|
27
|
+
- Zero runtime transforms
|
|
28
|
+
|
|
29
|
+
## Why server components?
|
|
30
|
+
|
|
31
|
+
Because all image variants are generated at build time, the component can remain fully
|
|
32
|
+
static and deterministic. Browsers handle responsive selection, fallbacks, and viewport
|
|
33
|
+
changes automatically.
|
|
34
|
+
|
|
35
|
+
This results in:
|
|
36
|
+
- zero client JS
|
|
37
|
+
- zero hydration cost
|
|
38
|
+
- zero runtime image optimization
|
|
39
|
+
- maximum compatibility across frameworks
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
Use a stable image reference from your app’s original source set. This is the public consumer API and
|
|
44
|
+
is the contract app authors should rely on.
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { ImageStatic } from "@vividwebau/react-static-images";
|
|
50
|
+
|
|
51
|
+
export default function Hero() {
|
|
52
|
+
return (
|
|
53
|
+
<ImageStatic
|
|
54
|
+
image="hero.jpg"
|
|
55
|
+
alt="Hero image"
|
|
56
|
+
sizes="100vw"
|
|
57
|
+
priority
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For new code, the public API should stay as simple as `image` + `alt`.
|
|
64
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ImgHTMLAttributes } from "react";
|
|
2
|
+
import type { ManifestData } from "./types.js";
|
|
3
|
+
export type ImageLayout = "intrinsic" | "responsive" | "fill" | "fixed";
|
|
4
|
+
type Px = `${number}px`;
|
|
5
|
+
type Vw = `${number}vw`;
|
|
6
|
+
type Percent = `${number}%`;
|
|
7
|
+
type NumericFraction = 0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 | 1.0 | 1;
|
|
8
|
+
type SizeValue = Px | Vw | Percent | NumericFraction;
|
|
9
|
+
export interface ImageStaticProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, "sizes"> {
|
|
10
|
+
image: string;
|
|
11
|
+
layout?: ImageLayout;
|
|
12
|
+
/** Fallback to the global manifest if not provided */
|
|
13
|
+
manifest?: ManifestData;
|
|
14
|
+
/** Whether the image should be prioritized for loading; sets the `loading`, `fetchPriority` and `decoding` attributes accordingly */
|
|
15
|
+
priority?: boolean;
|
|
16
|
+
/** Extend `sizes` to include an object mapping media queries to sizes */
|
|
17
|
+
sizes?: string | {
|
|
18
|
+
[key in "xs" | "sm" | "md" | "lg" | "xl"]?: SizeValue;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function ImageStatic({ alt, image, layout, manifest, priority, width, height, sizes, ...props }: ImageStaticProps): import("react").JSX.Element;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=ImageStatic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageStatic.d.ts","sourceRoot":"","sources":["../src/ImageStatic.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC;AAExE,KAAK,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC;AACxB,KAAK,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC;AACxB,KAAK,OAAO,GAAG,GAAG,MAAM,GAAG,CAAC;AAC5B,KAAK,eAAe,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;AACzF,KAAK,SAAS,GAAG,EAAE,GAAG,EAAE,GAAG,OAAO,GAAG,eAAe,CAAC;AAErD,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC1F,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,qIAAqI;IACrI,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,GAAG;SAAG,GAAG,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,SAAS;KAAE,CAAC;CAC5E;AAED,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,KAAK,EACL,MAAoB,EACpB,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,KAAe,EACf,GAAG,KAAK,EACT,EAAE,gBAAgB,+BAmIlB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getStaticImageManifest } from "./manifest-registry.js";
|
|
3
|
+
function resolveImage(manifest, image) {
|
|
4
|
+
return manifest.images.find((img) => img.src === image || img.id === image);
|
|
5
|
+
}
|
|
6
|
+
export function ImageStatic({ alt, image, layout = "intrinsic", manifest, priority, width, height, sizes = "100vw", ...props }) {
|
|
7
|
+
const manifestToUse = manifest ?? getStaticImageManifest();
|
|
8
|
+
const manifestItem = manifestToUse ? resolveImage(manifestToUse, image) : null;
|
|
9
|
+
if (!manifestItem) {
|
|
10
|
+
return _jsx("img", { src: image, alt: alt, ...props });
|
|
11
|
+
}
|
|
12
|
+
// --- SIZES ---
|
|
13
|
+
const breakpointMap = {
|
|
14
|
+
xs: "480px",
|
|
15
|
+
sm: "640px",
|
|
16
|
+
md: "768px",
|
|
17
|
+
lg: "1024px",
|
|
18
|
+
xl: "1280px",
|
|
19
|
+
};
|
|
20
|
+
const normalizeSizeValue = (value) => typeof value === "string" && value.endsWith("%")
|
|
21
|
+
? `${value.slice(0, -1)}vw`
|
|
22
|
+
: typeof value === "string" && value.endsWith("px")
|
|
23
|
+
? value
|
|
24
|
+
: typeof value === "string" && value.endsWith("vw")
|
|
25
|
+
? value
|
|
26
|
+
: typeof value === "number"
|
|
27
|
+
? `${value * 100}vw`
|
|
28
|
+
: value;
|
|
29
|
+
if (typeof sizes === "object") {
|
|
30
|
+
sizes = Object.entries(sizes)
|
|
31
|
+
.map(([key, value]) => `(min-width: ${breakpointMap[key]}) ${normalizeSizeValue(value)}`)
|
|
32
|
+
.join(", ");
|
|
33
|
+
}
|
|
34
|
+
const wrapperStyle = {};
|
|
35
|
+
const imgStyle = {};
|
|
36
|
+
// --- LAYOUT LOGIC ---
|
|
37
|
+
if (layout === "intrinsic") {
|
|
38
|
+
imgStyle.width = "100%";
|
|
39
|
+
imgStyle.height = "auto";
|
|
40
|
+
Object.assign(imgStyle, props.style);
|
|
41
|
+
}
|
|
42
|
+
if (layout === "responsive") {
|
|
43
|
+
const padding = `${100 / (manifestItem?.aspectRatio ?? 1)}%`;
|
|
44
|
+
wrapperStyle.position = "relative";
|
|
45
|
+
wrapperStyle.width = "100%";
|
|
46
|
+
wrapperStyle.paddingBottom = padding;
|
|
47
|
+
Object.assign(wrapperStyle, props.style);
|
|
48
|
+
imgStyle.position = "absolute";
|
|
49
|
+
imgStyle.inset = "0";
|
|
50
|
+
imgStyle.width = "100%";
|
|
51
|
+
imgStyle.height = "100%";
|
|
52
|
+
imgStyle.objectFit = "cover";
|
|
53
|
+
Object.assign(imgStyle, props.style);
|
|
54
|
+
}
|
|
55
|
+
if (layout === "fill") {
|
|
56
|
+
wrapperStyle.position = "relative";
|
|
57
|
+
wrapperStyle.width = "100%";
|
|
58
|
+
wrapperStyle.height = "100%";
|
|
59
|
+
Object.assign(wrapperStyle, props.style);
|
|
60
|
+
imgStyle.position = "absolute";
|
|
61
|
+
imgStyle.inset = "0";
|
|
62
|
+
imgStyle.width = "100%";
|
|
63
|
+
imgStyle.height = "100%";
|
|
64
|
+
imgStyle.objectFit = props.style?.objectFit ?? "cover";
|
|
65
|
+
Object.assign(imgStyle, props.style);
|
|
66
|
+
}
|
|
67
|
+
if (layout === "fixed") {
|
|
68
|
+
imgStyle.width = width ?? manifestItem?.width;
|
|
69
|
+
imgStyle.height = height ?? manifestItem?.height;
|
|
70
|
+
Object.assign(imgStyle, props.style);
|
|
71
|
+
}
|
|
72
|
+
// --- BLUR PLACEHOLDER ---
|
|
73
|
+
const blur = manifestItem.blurDataURL;
|
|
74
|
+
const consumerOpacity = props.style?.opacity;
|
|
75
|
+
if (blur) {
|
|
76
|
+
imgStyle.backgroundImage = `url(${blur})`;
|
|
77
|
+
imgStyle.backgroundSize = "cover";
|
|
78
|
+
imgStyle.backgroundPosition = "center";
|
|
79
|
+
imgStyle.transition = "opacity 0.4s ease";
|
|
80
|
+
imgStyle.opacity = 0;
|
|
81
|
+
}
|
|
82
|
+
const formats = ["avif", "webp", "jpeg"];
|
|
83
|
+
const pictureElement = (_jsxs("picture", { children: [formats.map((format) => {
|
|
84
|
+
if (!manifestItem?.variants?.length)
|
|
85
|
+
return null;
|
|
86
|
+
const variants = manifestItem.variants.filter((v) => v.format === format);
|
|
87
|
+
if (!variants.length)
|
|
88
|
+
return null;
|
|
89
|
+
const srcSet = variants.map((v) => `${v.src} ${v.width}w`).join(", ");
|
|
90
|
+
return _jsx("source", { type: `image/${format}`, srcSet: srcSet, sizes: sizes }, format);
|
|
91
|
+
}), _jsx("img", { alt: alt, src: manifestItem.src, sizes: sizes, loading: priority ? "eager" : "lazy", fetchPriority: priority ? "high" : undefined, decoding: priority ? undefined : "async", width: width ?? manifestItem.width, height: height ?? manifestItem.height, style: { ...imgStyle, opacity: consumerOpacity ?? 1 }, ...props })] }));
|
|
92
|
+
if (layout === "fill" || layout === "responsive") {
|
|
93
|
+
return _jsx("div", { style: wrapperStyle, children: pictureElement });
|
|
94
|
+
}
|
|
95
|
+
return pictureElement;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=ImageStatic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageStatic.js","sourceRoot":"","sources":["../src/ImageStatic.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export all public APIs
|
|
3
|
+
*/
|
|
4
|
+
export type { ImageStaticProps } from "./ImageStatic.js";
|
|
5
|
+
export { ImageStatic } from "./ImageStatic.js";
|
|
6
|
+
export type { ImageEntry, ManifestData } from "./manifest.js";
|
|
7
|
+
export { getImageById, getImageBySource, getImageCluster, loadManifest, } from "./manifest.js";
|
|
8
|
+
export { getStaticImageManifest, setStaticImageManifest, } from "./manifest-registry.js";
|
|
9
|
+
export type { BlurPlaceholder, ImageMetadata, ImageStaticConfig, ImageVariant, ResponsiveImage, } from "./types.js";
|
|
10
|
+
export { calculateAspectRatio, formatDominantColor, generatePaddingBottom, generatePictureSizes, generateSrcSet, } from "./utils.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,GACf,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export all public APIs
|
|
3
|
+
*/
|
|
4
|
+
export { ImageStatic } from "./ImageStatic.js";
|
|
5
|
+
export { getImageById, getImageBySource, getImageCluster, loadManifest, } from "./manifest.js";
|
|
6
|
+
export { getStaticImageManifest, setStaticImageManifest, } from "./manifest-registry.js";
|
|
7
|
+
export { calculateAspectRatio, formatDominantColor, generatePaddingBottom, generatePictureSizes, generateSrcSet, } from "./utils.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAQhC,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,GACf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-registry.d.ts","sourceRoot":"","sources":["../src/manifest-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,YAAY,QAE5D;AAED,wBAAgB,sBAAsB,IAAI,YAAY,GAAG,IAAI,CAE5D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-registry.js","sourceRoot":"","sources":["../src/manifest-registry.ts"],"names":[],"mappings":"AAEA,IAAI,cAAc,GAAwB,IAAI,CAAC;AAE/C,MAAM,UAAU,sBAAsB,CAAC,QAAsB;IAC3D,cAAc,GAAG,QAAQ,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest loading and management
|
|
3
|
+
*/
|
|
4
|
+
import type { ImageEntry, ManifestData } from "./types.js";
|
|
5
|
+
export type { ImageEntry, ManifestData };
|
|
6
|
+
export declare function loadManifest(manifestPath: string | ManifestData): Promise<ManifestData>;
|
|
7
|
+
export declare function getImageBySource(manifest: ManifestData, src: string): ImageEntry | undefined;
|
|
8
|
+
export declare function getImageByReference(manifest: ManifestData, imageReference: string): ImageEntry | undefined;
|
|
9
|
+
export declare function getImageById(manifest: ManifestData, id: string): ImageEntry | undefined;
|
|
10
|
+
export declare function getImageCluster(manifest: ManifestData, imageId: string): string[] | undefined;
|
|
11
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE3D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAQzC,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAiC7F;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAI5F;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EACtB,cAAc,EAAE,MAAM,GACrB,UAAU,GAAG,SAAS,CAcxB;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAIvF;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAe7F"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest loading and management
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Load and cache manifest data
|
|
6
|
+
* In a real implementation, this would fetch from a URL or import from a file
|
|
7
|
+
*/
|
|
8
|
+
let cachedManifest = null;
|
|
9
|
+
export async function loadManifest(manifestPath) {
|
|
10
|
+
console.log("[loadManifest] Loading manifest");
|
|
11
|
+
// If already an object, return it
|
|
12
|
+
if (typeof manifestPath === "object") {
|
|
13
|
+
cachedManifest = manifestPath;
|
|
14
|
+
return manifestPath;
|
|
15
|
+
}
|
|
16
|
+
// If cached, return cached version
|
|
17
|
+
if (cachedManifest) {
|
|
18
|
+
return cachedManifest;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
// Attempt to import/load the manifest
|
|
22
|
+
// In a real Next.js app, this would use require() or import()
|
|
23
|
+
console.log(`[loadManifest] Loading from: ${manifestPath}`);
|
|
24
|
+
// For now, return a placeholder
|
|
25
|
+
const manifest = {
|
|
26
|
+
version: "1.0.0",
|
|
27
|
+
generated: new Date().toISOString(),
|
|
28
|
+
images: [],
|
|
29
|
+
clusters: {},
|
|
30
|
+
};
|
|
31
|
+
cachedManifest = manifest;
|
|
32
|
+
return manifest;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error("[loadManifest] Error loading manifest:", error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function getImageBySource(manifest, src) {
|
|
40
|
+
console.log(`[getImageBySource] Finding image: ${src}`);
|
|
41
|
+
const found = manifest.images.find((img) => img.src === src);
|
|
42
|
+
return found;
|
|
43
|
+
}
|
|
44
|
+
export function getImageByReference(manifest, imageReference) {
|
|
45
|
+
const normalized = imageReference.replace(/\\/g, "/").split("?")[0].split("#")[0];
|
|
46
|
+
const basename = normalized.split("/").pop() || normalized;
|
|
47
|
+
return manifest.images.find((img) => {
|
|
48
|
+
const entrySrc = img.src.replace(/\\/g, "/").split("?")[0].split("#")[0];
|
|
49
|
+
return (entrySrc === normalized ||
|
|
50
|
+
img.src === normalized ||
|
|
51
|
+
entrySrc.endsWith(`/${basename}`) ||
|
|
52
|
+
normalized.endsWith(`/${basename}`) ||
|
|
53
|
+
basename === img.id);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export function getImageById(manifest, id) {
|
|
57
|
+
console.log(`[getImageById] Finding image: ${id}`);
|
|
58
|
+
const found = manifest.images.find((img) => img.id === id);
|
|
59
|
+
return found;
|
|
60
|
+
}
|
|
61
|
+
export function getImageCluster(manifest, imageId) {
|
|
62
|
+
console.log(`[getImageCluster] Finding cluster for: ${imageId}`);
|
|
63
|
+
if (!manifest.clusters) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
// Find which cluster contains this image
|
|
67
|
+
for (const [clusterId, members] of Object.entries(manifest.clusters)) {
|
|
68
|
+
if (members.includes(imageId)) {
|
|
69
|
+
return members;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for react-static-images
|
|
3
|
+
*/
|
|
4
|
+
export interface ImageVariant {
|
|
5
|
+
width: number;
|
|
6
|
+
format: string;
|
|
7
|
+
src: string;
|
|
8
|
+
filename: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ImageEntry {
|
|
11
|
+
id: string;
|
|
12
|
+
src: string;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
aspectRatio: number;
|
|
16
|
+
blur?: string;
|
|
17
|
+
blurDataURL?: string;
|
|
18
|
+
dominantColor?: string;
|
|
19
|
+
cluster?: number;
|
|
20
|
+
variants?: ImageVariant[];
|
|
21
|
+
}
|
|
22
|
+
export interface ManifestData {
|
|
23
|
+
version: string;
|
|
24
|
+
generated: string;
|
|
25
|
+
images: ImageEntry[];
|
|
26
|
+
clusters?: Record<number, string[]>;
|
|
27
|
+
}
|
|
28
|
+
export interface ImageMetadata {
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
aspectRatio: number;
|
|
32
|
+
dominantColor?: string;
|
|
33
|
+
blur?: string;
|
|
34
|
+
cluster?: number;
|
|
35
|
+
blurDataURL?: string;
|
|
36
|
+
variants?: ImageVariant[];
|
|
37
|
+
}
|
|
38
|
+
export interface ImageStaticConfig {
|
|
39
|
+
enableBlurUp?: boolean;
|
|
40
|
+
enableClustering?: boolean;
|
|
41
|
+
responsiveSizes?: number[];
|
|
42
|
+
}
|
|
43
|
+
export interface BlurPlaceholder {
|
|
44
|
+
/**
|
|
45
|
+
* Base64-encoded blur image data or SVG data URL
|
|
46
|
+
*/
|
|
47
|
+
data: string;
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
}
|
|
51
|
+
export interface ResponsiveImage {
|
|
52
|
+
src: string;
|
|
53
|
+
srcSet: string;
|
|
54
|
+
sizes?: string;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for image handling
|
|
3
|
+
*/
|
|
4
|
+
export interface ImageVariant {
|
|
5
|
+
width: number;
|
|
6
|
+
src: string;
|
|
7
|
+
format?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function calculateAspectRatio(width: number, height: number): number;
|
|
10
|
+
export declare function getMimeTypeForFormat(format: string): string;
|
|
11
|
+
export declare function generateSrcSet(variants?: ImageVariant[]): string;
|
|
12
|
+
export declare function groupVariantsByFormat(variants?: ImageVariant[]): Record<string, ImageVariant[]>;
|
|
13
|
+
export declare function formatDominantColor(color: string): string;
|
|
14
|
+
export declare function generatePaddingBottom(aspectRatio: number): string;
|
|
15
|
+
export declare function generatePictureSizes(variants: ImageVariant[]): string;
|
|
16
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAS3D;AAED,wBAAgB,cAAc,CAAC,QAAQ,GAAE,YAAY,EAAO,GAAG,MAAM,CAMpE;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,GAAE,YAAY,EAAO,GAC5B,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAOhC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQjE;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM,CAsBrE"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for image handling
|
|
3
|
+
*/
|
|
4
|
+
export function calculateAspectRatio(width, height) {
|
|
5
|
+
return width / height;
|
|
6
|
+
}
|
|
7
|
+
export function getMimeTypeForFormat(format) {
|
|
8
|
+
const normalized = format.toLowerCase();
|
|
9
|
+
if (normalized === "avif")
|
|
10
|
+
return "image/avif";
|
|
11
|
+
if (normalized === "webp")
|
|
12
|
+
return "image/webp";
|
|
13
|
+
if (normalized === "jpg" || normalized === "jpeg")
|
|
14
|
+
return "image/jpeg";
|
|
15
|
+
if (normalized === "png")
|
|
16
|
+
return "image/png";
|
|
17
|
+
return `image/${normalized}`;
|
|
18
|
+
}
|
|
19
|
+
export function generateSrcSet(variants = []) {
|
|
20
|
+
if (variants.length === 0) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
return variants.map((variant) => `${variant.src} ${variant.width}w`).join(", ");
|
|
24
|
+
}
|
|
25
|
+
export function groupVariantsByFormat(variants = []) {
|
|
26
|
+
return variants.reduce((acc, variant) => {
|
|
27
|
+
const format = (variant.format ?? "jpeg").toLowerCase();
|
|
28
|
+
acc[format] ?? (acc[format] = []);
|
|
29
|
+
acc[format].push(variant);
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
}
|
|
33
|
+
export function formatDominantColor(color) {
|
|
34
|
+
console.log(`[formatDominantColor] Formatting: ${color}`);
|
|
35
|
+
// Ensure it's a valid hex color
|
|
36
|
+
if (color.startsWith("#")) {
|
|
37
|
+
return color;
|
|
38
|
+
}
|
|
39
|
+
// Prefix with # if missing
|
|
40
|
+
return `#${color}`;
|
|
41
|
+
}
|
|
42
|
+
export function generatePaddingBottom(aspectRatio) {
|
|
43
|
+
/**
|
|
44
|
+
* Generates CSS padding-bottom value to prevent layout shift
|
|
45
|
+
* Formula: (height / width) * 100%
|
|
46
|
+
* Since aspectRatio = width / height, we use: (1 / aspectRatio) * 100%
|
|
47
|
+
*/
|
|
48
|
+
const percentage = (1 / aspectRatio) * 100;
|
|
49
|
+
return `${percentage}%`;
|
|
50
|
+
}
|
|
51
|
+
export function generatePictureSizes(variants) {
|
|
52
|
+
/**
|
|
53
|
+
* Generate sizes attribute for <picture> element
|
|
54
|
+
* Example: "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
|
55
|
+
*/
|
|
56
|
+
if (variants.length === 0) {
|
|
57
|
+
return "100vw";
|
|
58
|
+
}
|
|
59
|
+
// Group variants by width and generate appropriate breakpoints
|
|
60
|
+
const sorted = [...variants].sort((a, b) => a.width - b.width);
|
|
61
|
+
const sizes = [];
|
|
62
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
63
|
+
const width = sorted[i].width;
|
|
64
|
+
sizes.push(`(max-width: ${width}px) ${width}px`);
|
|
65
|
+
}
|
|
66
|
+
// Last variant is the default
|
|
67
|
+
sizes.push(`${sorted[sorted.length - 1].width}px`);
|
|
68
|
+
return sizes.join(", ");
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vividwebau/react-static-images",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "React Server Component for static image optimization",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./manifest": {
|
|
19
|
+
"import": "./dist/manifest.js",
|
|
20
|
+
"types": "./dist/manifest.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./types": {
|
|
23
|
+
"import": "./dist/types.js",
|
|
24
|
+
"types": "./dist/types.d.ts"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "tsc --watch",
|
|
29
|
+
"build": "tsc -p tsconfig.json",
|
|
30
|
+
"prepare": "tsc -p tsconfig.json",
|
|
31
|
+
"test": "node --test dist/**/*.test.js || true",
|
|
32
|
+
"lint": "eslint src --ext .ts,.tsx || true",
|
|
33
|
+
"clean": "rm -rf dist"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"react": "^19.0.0",
|
|
37
|
+
"react-dom": "^19.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^20.0.0",
|
|
41
|
+
"@types/react": "^19.0.0",
|
|
42
|
+
"@types/react-dom": "^19.0.0",
|
|
43
|
+
"eslint": "^8.55.0",
|
|
44
|
+
"typescript": "^5.3.0"
|
|
45
|
+
}
|
|
46
|
+
}
|