@tarunachyutuni/images 2.0.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/.turbo/turbo-build.log +4 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/package.json +28 -0
- package/src/index.ts +101 -0
- package/tsconfig.json +5 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface ImageProps {
|
|
2
|
+
src: string;
|
|
3
|
+
alt: string;
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
loading?: "lazy" | "eager";
|
|
7
|
+
decoding?: "async" | "sync";
|
|
8
|
+
className?: string;
|
|
9
|
+
sizes?: string;
|
|
10
|
+
srcSet?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ImageOptimization {
|
|
13
|
+
format: "webp" | "avif" | "jpeg" | "png";
|
|
14
|
+
quality: number;
|
|
15
|
+
width: number;
|
|
16
|
+
height?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ResponsiveImageSet {
|
|
19
|
+
breakpoints: {
|
|
20
|
+
width: number;
|
|
21
|
+
src: string;
|
|
22
|
+
}[];
|
|
23
|
+
alt: string;
|
|
24
|
+
sizes: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const IMAGE_FORMATS: {
|
|
27
|
+
readonly webp: {
|
|
28
|
+
readonly mime: "image/webp";
|
|
29
|
+
readonly ext: ".webp";
|
|
30
|
+
};
|
|
31
|
+
readonly avif: {
|
|
32
|
+
readonly mime: "image/avif";
|
|
33
|
+
readonly ext: ".avif";
|
|
34
|
+
};
|
|
35
|
+
readonly jpeg: {
|
|
36
|
+
readonly mime: "image/jpeg";
|
|
37
|
+
readonly ext: ".jpg";
|
|
38
|
+
};
|
|
39
|
+
readonly png: {
|
|
40
|
+
readonly mime: "image/png";
|
|
41
|
+
readonly ext: ".png";
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare class ImageAgent {
|
|
45
|
+
generateSrcSet(baseUrl: string, widths?: number[]): string;
|
|
46
|
+
generateSizes(breakpoints: {
|
|
47
|
+
minWidth: string;
|
|
48
|
+
size: string;
|
|
49
|
+
}[]): string;
|
|
50
|
+
generateAltText(imageUrl: string, context?: string): Promise<string>;
|
|
51
|
+
optimizeImage(src: string, optimization: ImageOptimization): string;
|
|
52
|
+
generatePlaceholder(width: number, height: number, text?: string): string;
|
|
53
|
+
generateBlurHash(width: number, height: number): string;
|
|
54
|
+
validateImageProps(props: ImageProps): {
|
|
55
|
+
valid: boolean;
|
|
56
|
+
issues: string[];
|
|
57
|
+
};
|
|
58
|
+
responsiveSet(baseUrl: string, aspectRatio?: string): ResponsiveImageSet;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;CAKhB,CAAC;AAEX,qBAAa,UAAU;IACrB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,EAAsC,GAAG,MAAM;IAI7F,aAAa,CAAC,WAAW,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,MAAM;IAIlE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1E,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,iBAAiB,GAAG,MAAM;IAMnE,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAQzE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IASvD,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAc3E,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,MAAe,GAAG,kBAAkB;CAajF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// @tarunachyutuni/images — Intelligent Image Handling
|
|
3
|
+
// =============================================================================
|
|
4
|
+
export const IMAGE_FORMATS = {
|
|
5
|
+
webp: { mime: "image/webp", ext: ".webp" },
|
|
6
|
+
avif: { mime: "image/avif", ext: ".avif" },
|
|
7
|
+
jpeg: { mime: "image/jpeg", ext: ".jpg" },
|
|
8
|
+
png: { mime: "image/png", ext: ".png" },
|
|
9
|
+
};
|
|
10
|
+
export class ImageAgent {
|
|
11
|
+
generateSrcSet(baseUrl, widths = [320, 640, 768, 1024, 1280, 1920]) {
|
|
12
|
+
return widths.map((w) => `${baseUrl}?w=${w} ${w}w`).join(", ");
|
|
13
|
+
}
|
|
14
|
+
generateSizes(breakpoints) {
|
|
15
|
+
return breakpoints.map((b) => `${b.minWidth} ${b.size}`).join(", ");
|
|
16
|
+
}
|
|
17
|
+
async generateAltText(imageUrl, context) {
|
|
18
|
+
return context ?? "Image description";
|
|
19
|
+
}
|
|
20
|
+
optimizeImage(src, optimization) {
|
|
21
|
+
const { format, quality, width } = optimization;
|
|
22
|
+
if (src.includes("?"))
|
|
23
|
+
return `${src}&fm=${format === "jpeg" ? "jpg" : format}&q=${quality}&w=${width}`;
|
|
24
|
+
return `${src}?fm=${format === "jpeg" ? "jpg" : format}&q=${quality}&w=${width}`;
|
|
25
|
+
}
|
|
26
|
+
generatePlaceholder(width, height, text) {
|
|
27
|
+
return `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" fill="%23f5f5f5">
|
|
28
|
+
<text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" font-family="system-ui" font-size="14" fill="%23999">${text ?? `${width}×${height}`}</text>
|
|
29
|
+
</svg>`)}`;
|
|
30
|
+
}
|
|
31
|
+
generateBlurHash(width, height) {
|
|
32
|
+
return `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
|
|
33
|
+
<filter id="blur"><feGaussianBlur stdDeviation="20"/></filter>
|
|
34
|
+
<rect width="100%" height="100%" fill="#e2e8f0" filter="url(#blur)"/>
|
|
35
|
+
</svg>`)}`;
|
|
36
|
+
}
|
|
37
|
+
validateImageProps(props) {
|
|
38
|
+
const issues = [];
|
|
39
|
+
if (!props.alt || props.alt.length < 5) {
|
|
40
|
+
issues.push("Alt text too short — should be descriptive");
|
|
41
|
+
}
|
|
42
|
+
if (!props.width || !props.height) {
|
|
43
|
+
issues.push("Missing width/height — causes layout shift (CLS)");
|
|
44
|
+
}
|
|
45
|
+
if (!props.loading || props.loading !== "lazy") {
|
|
46
|
+
issues.push("Consider loading='lazy' for below-fold images");
|
|
47
|
+
}
|
|
48
|
+
return { valid: issues.length === 0, issues };
|
|
49
|
+
}
|
|
50
|
+
responsiveSet(baseUrl, aspectRatio = "16/9") {
|
|
51
|
+
return {
|
|
52
|
+
breakpoints: [
|
|
53
|
+
{ width: 320, src: `${baseUrl}?w=320` },
|
|
54
|
+
{ width: 640, src: `${baseUrl}?w=640` },
|
|
55
|
+
{ width: 768, src: `${baseUrl}?w=768` },
|
|
56
|
+
{ width: 1024, src: `${baseUrl}?w=1024` },
|
|
57
|
+
{ width: 1280, src: `${baseUrl}?w=1280` },
|
|
58
|
+
],
|
|
59
|
+
alt: "",
|
|
60
|
+
sizes: "(max-width: 320px) 320px, (max-width: 640px) 640px, (max-width: 768px) 768px, (max-width: 1024px) 1024px, 1280px",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tarunachyutuni/images",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Images package for Lumina",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist-index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@tarunachyutuni/types": "2.0.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "^5.5.0"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// @tarunachyutuni/images — Intelligent Image Handling
|
|
3
|
+
// =============================================================================
|
|
4
|
+
|
|
5
|
+
export interface ImageProps {
|
|
6
|
+
src: string;
|
|
7
|
+
alt: string;
|
|
8
|
+
width?: number;
|
|
9
|
+
height?: number;
|
|
10
|
+
loading?: "lazy" | "eager";
|
|
11
|
+
decoding?: "async" | "sync";
|
|
12
|
+
className?: string;
|
|
13
|
+
sizes?: string;
|
|
14
|
+
srcSet?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ImageOptimization {
|
|
18
|
+
format: "webp" | "avif" | "jpeg" | "png";
|
|
19
|
+
quality: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ResponsiveImageSet {
|
|
25
|
+
breakpoints: { width: number; src: string }[];
|
|
26
|
+
alt: string;
|
|
27
|
+
sizes: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const IMAGE_FORMATS = {
|
|
31
|
+
webp: { mime: "image/webp", ext: ".webp" },
|
|
32
|
+
avif: { mime: "image/avif", ext: ".avif" },
|
|
33
|
+
jpeg: { mime: "image/jpeg", ext: ".jpg" },
|
|
34
|
+
png: { mime: "image/png", ext: ".png" },
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
export class ImageAgent {
|
|
38
|
+
generateSrcSet(baseUrl: string, widths: number[] = [320, 640, 768, 1024, 1280, 1920]): string {
|
|
39
|
+
return widths.map((w) => `${baseUrl}?w=${w} ${w}w`).join(", ");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
generateSizes(breakpoints: { minWidth: string; size: string }[]): string {
|
|
43
|
+
return breakpoints.map((b) => `${b.minWidth} ${b.size}`).join(", ");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async generateAltText(imageUrl: string, context?: string): Promise<string> {
|
|
47
|
+
return context ?? "Image description";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
optimizeImage(src: string, optimization: ImageOptimization): string {
|
|
51
|
+
const { format, quality, width } = optimization;
|
|
52
|
+
if (src.includes("?")) return `${src}&fm=${format === "jpeg" ? "jpg" : format}&q=${quality}&w=${width}`;
|
|
53
|
+
return `${src}?fm=${format === "jpeg" ? "jpg" : format}&q=${quality}&w=${width}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
generatePlaceholder(width: number, height: number, text?: string): string {
|
|
57
|
+
return `data:image/svg+xml,${encodeURIComponent(
|
|
58
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" fill="%23f5f5f5">
|
|
59
|
+
<text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" font-family="system-ui" font-size="14" fill="%23999">${text ?? `${width}×${height}`}</text>
|
|
60
|
+
</svg>`
|
|
61
|
+
)}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
generateBlurHash(width: number, height: number): string {
|
|
65
|
+
return `data:image/svg+xml,${encodeURIComponent(
|
|
66
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
|
|
67
|
+
<filter id="blur"><feGaussianBlur stdDeviation="20"/></filter>
|
|
68
|
+
<rect width="100%" height="100%" fill="#e2e8f0" filter="url(#blur)"/>
|
|
69
|
+
</svg>`
|
|
70
|
+
)}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
validateImageProps(props: ImageProps): { valid: boolean; issues: string[] } {
|
|
74
|
+
const issues: string[] = [];
|
|
75
|
+
if (!props.alt || props.alt.length < 5) {
|
|
76
|
+
issues.push("Alt text too short — should be descriptive");
|
|
77
|
+
}
|
|
78
|
+
if (!props.width || !props.height) {
|
|
79
|
+
issues.push("Missing width/height — causes layout shift (CLS)");
|
|
80
|
+
}
|
|
81
|
+
if (!props.loading || props.loading !== "lazy") {
|
|
82
|
+
issues.push("Consider loading='lazy' for below-fold images");
|
|
83
|
+
}
|
|
84
|
+
return { valid: issues.length === 0, issues };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
responsiveSet(baseUrl: string, aspectRatio: string = "16/9"): ResponsiveImageSet {
|
|
88
|
+
return {
|
|
89
|
+
breakpoints: [
|
|
90
|
+
{ width: 320, src: `${baseUrl}?w=320` },
|
|
91
|
+
{ width: 640, src: `${baseUrl}?w=640` },
|
|
92
|
+
{ width: 768, src: `${baseUrl}?w=768` },
|
|
93
|
+
{ width: 1024, src: `${baseUrl}?w=1024` },
|
|
94
|
+
{ width: 1280, src: `${baseUrl}?w=1280` },
|
|
95
|
+
],
|
|
96
|
+
alt: "",
|
|
97
|
+
sizes: "(max-width: 320px) 320px, (max-width: 640px) 640px, (max-width: 768px) 768px, (max-width: 1024px) 1024px, 1280px",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|