@webstudio-is/image 0.1.0 → 0.15.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.
Files changed (44) hide show
  1. package/lib/__generated__/image.props.json +573 -573
  2. package/lib/cjs/__generated__/image.props.json +573 -573
  3. package/lib/cjs/image-loaders.cjs +48 -33
  4. package/lib/cjs/image-optimize.cjs +101 -171
  5. package/lib/cjs/image.cjs +54 -22
  6. package/lib/cjs/index.cjs +31 -31
  7. package/lib/image-loaders.js +24 -27
  8. package/lib/image-optimize.js +83 -169
  9. package/lib/image.js +30 -15
  10. package/lib/index.js +8 -3
  11. package/package.json +9 -16
  12. package/src/__generated__/image.props.json +575 -0
  13. package/src/image-dev.stories.tsx +128 -0
  14. package/src/image-loaders.ts +47 -0
  15. package/{lib/image-optimize.test.js → src/image-optimize.test.ts} +122 -103
  16. package/{lib/cjs/image-optimize.d.ts → src/image-optimize.ts} +172 -19
  17. package/src/image.tsx +74 -0
  18. package/{lib/cjs/index.d.ts → src/index.ts} +0 -1
  19. package/lib/cjs/image-dev.stories.cjs +0 -77
  20. package/lib/cjs/image-dev.stories.d.ts +0 -35
  21. package/lib/cjs/image-dev.stories.d.ts.map +0 -1
  22. package/lib/cjs/image-loaders.d.ts +0 -14
  23. package/lib/cjs/image-loaders.d.ts.map +0 -1
  24. package/lib/cjs/image-optimize.d.ts.map +0 -1
  25. package/lib/cjs/image-optimize.test.cjs +0 -157
  26. package/lib/cjs/image-optimize.test.d.ts +0 -2
  27. package/lib/cjs/image-optimize.test.d.ts.map +0 -1
  28. package/lib/cjs/image.d.ts +0 -11
  29. package/lib/cjs/image.d.ts.map +0 -1
  30. package/lib/cjs/index.d.ts.map +0 -1
  31. package/lib/image-dev.stories.d.ts +0 -35
  32. package/lib/image-dev.stories.d.ts.map +0 -1
  33. package/lib/image-dev.stories.js +0 -65
  34. package/lib/image-loaders.d.ts +0 -14
  35. package/lib/image-loaders.d.ts.map +0 -1
  36. package/lib/image-optimize.d.ts +0 -107
  37. package/lib/image-optimize.d.ts.map +0 -1
  38. package/lib/image-optimize.test.d.ts +0 -2
  39. package/lib/image-optimize.test.d.ts.map +0 -1
  40. package/lib/image.d.ts +0 -11
  41. package/lib/image.d.ts.map +0 -1
  42. package/lib/index.d.ts +0 -5
  43. package/lib/index.d.ts.map +0 -1
  44. package/lib/tsconfig.tsbuildinfo +0 -1
@@ -1,35 +0,0 @@
1
- import React from "react";
2
- import type { ComponentMeta, ComponentStory } from "@storybook/react";
3
- declare const _default: ComponentMeta<React.ForwardRefExoticComponent<Pick<React.ClassAttributes<HTMLImageElement> & React.ImgHTMLAttributes<HTMLImageElement> & {
4
- quality?: number | undefined;
5
- optimize?: boolean | undefined;
6
- loader: import("./image-optimize").ImageLoader;
7
- }, "quality" | "loader" | "key" | keyof React.ImgHTMLAttributes<HTMLImageElement> | "optimize"> & React.RefAttributes<HTMLImageElement>>>;
8
- export default _default;
9
- /**
10
- * Load images depending on image width and device per pixel ratio.
11
- **/
12
- export declare const FixedWidthImage: ComponentStory<React.FunctionComponent>;
13
- /**
14
- * Preserve ratio using object-fit: cover. Load images depending on image width and device per pixel ratio.
15
- **/
16
- export declare const FixedWidthImageCover: ComponentStory<React.FunctionComponent>;
17
- /**
18
- * Load images depending on the viewport width.
19
- **/
20
- export declare const UnknownWidthImage: ComponentStory<React.FunctionComponent>;
21
- /**
22
- * Fit width of the parent container, has own aspect-ratio and object-fit=cover.
23
- * Load images depending on the viewport width.
24
- **/
25
- export declare const AspectRatioImage: ComponentStory<React.FunctionComponent>;
26
- /**
27
- * Fill width and height of the relative parent container, object-fit=cover. Load images depending on the viewport width.
28
- **/
29
- export declare const FillParentImage: ComponentStory<React.FunctionComponent>;
30
- /**
31
- * "sizes" attribute explicitly equal to 100vw allowing to skip the default behavior.
32
- * See DEFAULT_SIZES in the Image component. Load images depending on the viewport width.
33
- **/
34
- export declare const HeroImage: ComponentStory<React.FunctionComponent>;
35
- //# sourceMappingURL=image-dev.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-dev.stories.d.ts","sourceRoot":"","sources":["../../src/image-dev.stories.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;;;;;;AAQtE,wBAE0C;AA0C1C;;IAEI;AACJ,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAEnE,CAAC;AAEF;;IAEI;AACJ,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAC/C,KAAK,CAAC,iBAAiB,CAQxB,CAAC;AAEF;;IAEI;AACJ,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAC5C,KAAK,CAAC,iBAAiB,CACa,CAAC;AAEvC;;;IAGI;AACJ,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAOpE,CAAC;AAEF;;IAEI;AACJ,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAYnE,CAAC;AAEF;;;IAGI;AACJ,eAAO,MAAM,SAAS,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAU7D,CAAC"}
@@ -1,14 +0,0 @@
1
- import { type ImageLoader } from "./image-optimize";
2
- export declare type CloudflareImageLoaderOptions = {
3
- resizeOrigin?: string | null;
4
- };
5
- /**
6
- * Default image loader in case of no loader provided
7
- * https://developers.cloudflare.com/images/image-resizing/url-format/
8
- **/
9
- export declare const cloudflareImageLoader: (ops: CloudflareImageLoaderOptions | null) => ImageLoader;
10
- /**
11
- * Fake pseudo loader for local testing purposes
12
- **/
13
- export declare const localImageLoader: () => ImageLoader;
14
- //# sourceMappingURL=image-loaders.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-loaders.d.ts","sourceRoot":"","sources":["../../src/image-loaders.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE9D,oBAAY,4BAA4B,GAAG;IACzC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF;;;IAGI;AACJ,eAAO,MAAM,qBAAqB,EAAE,CAClC,GAAG,EAAE,4BAA4B,GAAG,IAAI,KACrC,WAoBF,CAAC;AAEJ;;IAEI;AACJ,eAAO,MAAM,gBAAgB,EAAE,MAAM,WAQlC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-optimize.d.ts","sourceRoot":"","sources":["../../src/image-optimize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAsFI;AAEJ,oBAAY,WAAW,GAAG,CAAC,KAAK,EAAE;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,KAAK,MAAM,CAAC;AAQb,eAAO,MAAM,QAAQ,UAAkC,CAAC;AA4GxD,eAAO,MAAM,kBAAkB,UAAW;IACxC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB,KAAG;IACF,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAuCH,CAAC"}
@@ -1,157 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const image_optimize_1 = require("./image-optimize");
4
- const image_loaders_1 = require("./image-loaders");
5
- describe("Image optimizations applied", () => {
6
- test("width is number, create pixel density descriptor 'x'", () => {
7
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
8
- optimize: true,
9
- width: 100,
10
- src: "https://webstudio.is/logo.webp",
11
- srcSet: undefined,
12
- sizes: undefined,
13
- quality: 100,
14
- loader: (0, image_loaders_1.cloudflareImageLoader)({ resizeOrigin: null }),
15
- });
16
- expect(imgAttr).toMatchInlineSnapshot(`
17
- {
18
- "sizes": undefined,
19
- "src": "/cdn-cgi/image/width=256,quality=100,format=auto/https://webstudio.is/logo.webp",
20
- "srcSet": "/cdn-cgi/image/width=128,quality=100,format=auto/https://webstudio.is/logo.webp 1x, /cdn-cgi/image/width=256,quality=100,format=auto/https://webstudio.is/logo.webp 2x",
21
- }
22
- `);
23
- });
24
- test("width is undefined, create 'w' descriptor and sizes prop", () => {
25
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
26
- optimize: true,
27
- width: undefined,
28
- src: "https://webstudio.is/logo.webp",
29
- srcSet: undefined,
30
- sizes: undefined,
31
- quality: 90,
32
- loader: (0, image_loaders_1.cloudflareImageLoader)({ resizeOrigin: null }),
33
- });
34
- expect(imgAttr).toMatchInlineSnapshot(`
35
- {
36
- "sizes": "(min-width: 1280px) 50vw, 100vw",
37
- "src": "/cdn-cgi/image/width=3840,quality=90,format=auto/https://webstudio.is/logo.webp",
38
- "srcSet": "/cdn-cgi/image/width=384,quality=90,format=auto/https://webstudio.is/logo.webp 384w, /cdn-cgi/image/width=640,quality=90,format=auto/https://webstudio.is/logo.webp 640w, /cdn-cgi/image/width=750,quality=90,format=auto/https://webstudio.is/logo.webp 750w, /cdn-cgi/image/width=828,quality=90,format=auto/https://webstudio.is/logo.webp 828w, /cdn-cgi/image/width=1080,quality=90,format=auto/https://webstudio.is/logo.webp 1080w, /cdn-cgi/image/width=1200,quality=90,format=auto/https://webstudio.is/logo.webp 1200w, /cdn-cgi/image/width=1920,quality=90,format=auto/https://webstudio.is/logo.webp 1920w, /cdn-cgi/image/width=2048,quality=90,format=auto/https://webstudio.is/logo.webp 2048w, /cdn-cgi/image/width=3840,quality=90,format=auto/https://webstudio.is/logo.webp 3840w",
39
- }
40
- `);
41
- });
42
- test("width is undefined and size defined, creates 'w' descriptor and use input sizes props", () => {
43
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
44
- optimize: true,
45
- width: undefined,
46
- src: "https://webstudio.is/logo.webp",
47
- srcSet: undefined,
48
- sizes: "100vw",
49
- quality: 70,
50
- loader: (0, image_loaders_1.cloudflareImageLoader)({ resizeOrigin: null }),
51
- });
52
- expect(imgAttr).toMatchInlineSnapshot(`
53
- {
54
- "sizes": "100vw",
55
- "src": "/cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp",
56
- "srcSet": "/cdn-cgi/image/width=640,quality=70,format=auto/https://webstudio.is/logo.webp 640w, /cdn-cgi/image/width=750,quality=70,format=auto/https://webstudio.is/logo.webp 750w, /cdn-cgi/image/width=828,quality=70,format=auto/https://webstudio.is/logo.webp 828w, /cdn-cgi/image/width=1080,quality=70,format=auto/https://webstudio.is/logo.webp 1080w, /cdn-cgi/image/width=1200,quality=70,format=auto/https://webstudio.is/logo.webp 1200w, /cdn-cgi/image/width=1920,quality=70,format=auto/https://webstudio.is/logo.webp 1920w, /cdn-cgi/image/width=2048,quality=70,format=auto/https://webstudio.is/logo.webp 2048w, /cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp 3840w",
57
- }
58
- `);
59
- });
60
- test("width is undefined and size defined, creates 'w' descriptor and use input sizes props, resizeOrigin defined", () => {
61
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
62
- optimize: true,
63
- width: undefined,
64
- src: "https://webstudio.is/logo.webp",
65
- srcSet: undefined,
66
- sizes: "100vw",
67
- quality: 70,
68
- loader: (0, image_loaders_1.cloudflareImageLoader)({
69
- resizeOrigin: "https://resize-origin.is",
70
- }),
71
- });
72
- expect(imgAttr).toMatchInlineSnapshot(`
73
- {
74
- "sizes": "100vw",
75
- "src": "https://resize-origin.is/cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp",
76
- "srcSet": "https://resize-origin.is/cdn-cgi/image/width=640,quality=70,format=auto/https://webstudio.is/logo.webp 640w, https://resize-origin.is/cdn-cgi/image/width=750,quality=70,format=auto/https://webstudio.is/logo.webp 750w, https://resize-origin.is/cdn-cgi/image/width=828,quality=70,format=auto/https://webstudio.is/logo.webp 828w, https://resize-origin.is/cdn-cgi/image/width=1080,quality=70,format=auto/https://webstudio.is/logo.webp 1080w, https://resize-origin.is/cdn-cgi/image/width=1200,quality=70,format=auto/https://webstudio.is/logo.webp 1200w, https://resize-origin.is/cdn-cgi/image/width=1920,quality=70,format=auto/https://webstudio.is/logo.webp 1920w, https://resize-origin.is/cdn-cgi/image/width=2048,quality=70,format=auto/https://webstudio.is/logo.webp 2048w, https://resize-origin.is/cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp 3840w",
77
- }
78
- `);
79
- });
80
- test("custom loader", () => {
81
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
82
- optimize: true,
83
- width: undefined,
84
- src: "https://webstudio.is/logo.webp",
85
- srcSet: undefined,
86
- sizes: "100vw",
87
- quality: 70,
88
- loader: ({ width, src, quality }) => `${new URL(src).pathname}?w=${width}&q=${quality}`,
89
- });
90
- expect(imgAttr).toMatchInlineSnapshot(`
91
- {
92
- "sizes": "100vw",
93
- "src": "/logo.webp?w=3840&q=70",
94
- "srcSet": "/logo.webp?w=640&q=70 640w, /logo.webp?w=750&q=70 750w, /logo.webp?w=828&q=70 828w, /logo.webp?w=1080&q=70 1080w, /logo.webp?w=1200&q=70 1200w, /logo.webp?w=1920&q=70 1920w, /logo.webp?w=2048&q=70 2048w, /logo.webp?w=3840&q=70 3840w",
95
- }
96
- `);
97
- });
98
- });
99
- describe("Image optimizations not applied", () => {
100
- test("optimize is false", () => {
101
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
102
- optimize: false,
103
- width: 100,
104
- src: "https://webstudio.is/logo.webp",
105
- srcSet: undefined,
106
- sizes: undefined,
107
- quality: 100,
108
- loader: (0, image_loaders_1.cloudflareImageLoader)({ resizeOrigin: null }),
109
- });
110
- expect(imgAttr).toMatchInlineSnapshot(`
111
- {
112
- "src": "https://webstudio.is/logo.webp",
113
- }
114
- `);
115
- });
116
- test("srcSet is defined", () => {
117
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
118
- optimize: true,
119
- width: 100,
120
- src: "https://webstudio.is/logo.webp",
121
- srcSet: "user-defined-srcset",
122
- sizes: undefined,
123
- quality: 100,
124
- loader: (0, image_loaders_1.cloudflareImageLoader)({ resizeOrigin: null }),
125
- });
126
- expect(imgAttr).toMatchInlineSnapshot(`
127
- {
128
- "src": "https://webstudio.is/logo.webp",
129
- "srcSet": "user-defined-srcset",
130
- }
131
- `);
132
- });
133
- test("src is empty", () => {
134
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
135
- optimize: true,
136
- width: 100,
137
- src: "",
138
- srcSet: undefined,
139
- sizes: undefined,
140
- quality: 100,
141
- loader: (0, image_loaders_1.cloudflareImageLoader)({ resizeOrigin: null }),
142
- });
143
- expect(imgAttr).toMatchInlineSnapshot(`null`);
144
- });
145
- test("src is undefined", () => {
146
- const imgAttr = (0, image_optimize_1.getImageAttributes)({
147
- optimize: true,
148
- width: 100,
149
- src: undefined,
150
- srcSet: undefined,
151
- sizes: undefined,
152
- quality: 100,
153
- loader: (0, image_loaders_1.cloudflareImageLoader)({ resizeOrigin: null }),
154
- });
155
- expect(imgAttr).toMatchInlineSnapshot(`null`);
156
- });
157
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=image-optimize.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-optimize.test.d.ts","sourceRoot":"","sources":["../../src/image-optimize.test.ts"],"names":[],"mappings":""}
@@ -1,11 +0,0 @@
1
- import { type ComponentProps } from "react";
2
- import { type ImageLoader } from "./image-optimize";
3
- declare const defaultTag = "img";
4
- declare type ImageProps = ComponentProps<typeof defaultTag> & {
5
- quality?: number;
6
- optimize?: boolean;
7
- loader: ImageLoader;
8
- };
9
- export declare const Image: import("react").ForwardRefExoticComponent<Pick<ImageProps, "quality" | "loader" | "key" | keyof import("react").ImgHTMLAttributes<HTMLImageElement> | "optimize"> & import("react").RefAttributes<HTMLImageElement>>;
10
- export {};
11
- //# sourceMappingURL=image.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/image.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AACzE,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAExE,QAAA,MAAM,UAAU,QAAQ,CAAC;AAEzB,aAAK,UAAU,GAAG,cAAc,CAAC,OAAO,UAAU,CAAC,GAAG;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,KAAK,sNAmBjB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kCAAkC,CAAC"}
@@ -1,35 +0,0 @@
1
- import React from "react";
2
- import type { ComponentMeta, ComponentStory } from "@storybook/react";
3
- declare const _default: ComponentMeta<React.ForwardRefExoticComponent<Pick<React.ClassAttributes<HTMLImageElement> & React.ImgHTMLAttributes<HTMLImageElement> & {
4
- quality?: number | undefined;
5
- optimize?: boolean | undefined;
6
- loader: import("./image-optimize").ImageLoader;
7
- }, "quality" | "loader" | "key" | keyof React.ImgHTMLAttributes<HTMLImageElement> | "optimize"> & React.RefAttributes<HTMLImageElement>>>;
8
- export default _default;
9
- /**
10
- * Load images depending on image width and device per pixel ratio.
11
- **/
12
- export declare const FixedWidthImage: ComponentStory<React.FunctionComponent>;
13
- /**
14
- * Preserve ratio using object-fit: cover. Load images depending on image width and device per pixel ratio.
15
- **/
16
- export declare const FixedWidthImageCover: ComponentStory<React.FunctionComponent>;
17
- /**
18
- * Load images depending on the viewport width.
19
- **/
20
- export declare const UnknownWidthImage: ComponentStory<React.FunctionComponent>;
21
- /**
22
- * Fit width of the parent container, has own aspect-ratio and object-fit=cover.
23
- * Load images depending on the viewport width.
24
- **/
25
- export declare const AspectRatioImage: ComponentStory<React.FunctionComponent>;
26
- /**
27
- * Fill width and height of the relative parent container, object-fit=cover. Load images depending on the viewport width.
28
- **/
29
- export declare const FillParentImage: ComponentStory<React.FunctionComponent>;
30
- /**
31
- * "sizes" attribute explicitly equal to 100vw allowing to skip the default behavior.
32
- * See DEFAULT_SIZES in the Image component. Load images depending on the viewport width.
33
- **/
34
- export declare const HeroImage: ComponentStory<React.FunctionComponent>;
35
- //# sourceMappingURL=image-dev.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-dev.stories.d.ts","sourceRoot":"","sources":["../src/image-dev.stories.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;;;;;;AAQtE,wBAE0C;AA0C1C;;IAEI;AACJ,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAEnE,CAAC;AAEF;;IAEI;AACJ,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAC/C,KAAK,CAAC,iBAAiB,CAQxB,CAAC;AAEF;;IAEI;AACJ,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAC5C,KAAK,CAAC,iBAAiB,CACa,CAAC;AAEvC;;;IAGI;AACJ,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAOpE,CAAC;AAEF;;IAEI;AACJ,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAYnE,CAAC;AAEF;;;IAGI;AACJ,eAAO,MAAM,SAAS,EAAE,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAU7D,CAAC"}
@@ -1,65 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Image as ImagePrimitive, loaders } from "./";
3
- // to not allow include local assets everywhere, just enable it for this file
4
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5
- // @ts-ignore
6
- import localLogoImage from "../storybook-assets/logo.webp";
7
- export default {
8
- title: "Components/ImageDev",
9
- };
10
- /**
11
- * In case you need to test img with real cloudflare trasforms
12
- * set USE_CLOUDFLARE_IMAGE_TRANSFORM = true
13
- **/
14
- const USE_CLOUDFLARE_IMAGE_TRANSFORM = false;
15
- // For cloudflare image transform testing, logo should be the most consistent image on the site
16
- const REMOTE_SELF_DOMAIN_IMAGE = "https://webstudio.is/logo.webp";
17
- const imageSrc = USE_CLOUDFLARE_IMAGE_TRANSFORM
18
- ? REMOTE_SELF_DOMAIN_IMAGE
19
- : localLogoImage;
20
- const imageLoader = USE_CLOUDFLARE_IMAGE_TRANSFORM
21
- ? loaders.cloudflareImageLoader({ resizeOrigin: "https://webstudio.is" })
22
- : loaders.localImageLoader();
23
- const ImageBase = (args) => {
24
- const style = {
25
- maxWidth: "100%",
26
- display: "block",
27
- ...args.style,
28
- };
29
- return (_jsx(ImagePrimitive, { ...args, optimize: true, loader: imageLoader, style: style }));
30
- };
31
- /**
32
- * Load images depending on image width and device per pixel ratio.
33
- **/
34
- export const FixedWidthImage = () => (_jsx(ImageBase, { src: imageSrc, width: "300", height: "400" }));
35
- /**
36
- * Preserve ratio using object-fit: cover. Load images depending on image width and device per pixel ratio.
37
- **/
38
- export const FixedWidthImageCover = () => (_jsx(ImageBase, { src: imageSrc, width: "300", height: "400", style: { objectFit: "cover" } }));
39
- /**
40
- * Load images depending on the viewport width.
41
- **/
42
- export const UnknownWidthImage = () => _jsx(ImageBase, { src: imageSrc });
43
- /**
44
- * Fit width of the parent container, has own aspect-ratio and object-fit=cover.
45
- * Load images depending on the viewport width.
46
- **/
47
- export const AspectRatioImage = () => (_jsx("div", { style: { width: "50%" }, children: _jsx(ImageBase, { src: imageSrc, style: { aspectRatio: "2/1", objectFit: "cover", width: "100%" } }) }));
48
- /**
49
- * Fill width and height of the relative parent container, object-fit=cover. Load images depending on the viewport width.
50
- **/
51
- export const FillParentImage = () => (_jsx("div", { style: { width: "50%", aspectRatio: "2/1", position: "relative" }, children: _jsx(ImageBase, { src: imageSrc, style: {
52
- objectFit: "cover",
53
- position: "absolute",
54
- width: "100%",
55
- height: "100%",
56
- } }) }));
57
- /**
58
- * "sizes" attribute explicitly equal to 100vw allowing to skip the default behavior.
59
- * See DEFAULT_SIZES in the Image component. Load images depending on the viewport width.
60
- **/
61
- export const HeroImage = () => (_jsx(ImageBase, { src: imageSrc, sizes: "100vw", style: {
62
- aspectRatio: "3/1",
63
- objectFit: "cover",
64
- width: "100%",
65
- } }));
@@ -1,14 +0,0 @@
1
- import { type ImageLoader } from "./image-optimize";
2
- export declare type CloudflareImageLoaderOptions = {
3
- resizeOrigin?: string | null;
4
- };
5
- /**
6
- * Default image loader in case of no loader provided
7
- * https://developers.cloudflare.com/images/image-resizing/url-format/
8
- **/
9
- export declare const cloudflareImageLoader: (ops: CloudflareImageLoaderOptions | null) => ImageLoader;
10
- /**
11
- * Fake pseudo loader for local testing purposes
12
- **/
13
- export declare const localImageLoader: () => ImageLoader;
14
- //# sourceMappingURL=image-loaders.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-loaders.d.ts","sourceRoot":"","sources":["../src/image-loaders.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE9D,oBAAY,4BAA4B,GAAG;IACzC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF;;;IAGI;AACJ,eAAO,MAAM,qBAAqB,EAAE,CAClC,GAAG,EAAE,4BAA4B,GAAG,IAAI,KACrC,WAoBF,CAAC;AAEJ;;IAEI;AACJ,eAAO,MAAM,gBAAgB,EAAE,MAAM,WAQlC,CAAC"}
@@ -1,107 +0,0 @@
1
- /**
2
- * # Responsive Image component helpers.
3
- *
4
- * ## Quick summary about img srcset and sizes attributes:
5
- *
6
- * There are 2 ways to define what image will be loaded in the img property srcset.
7
- *
8
- * 1. via pixel density descriptor 'x', like `srcset="photo-small.jpg 1x, photo-medium.jpg 1.5x, photo-huge.jpg 2x"`
9
- * src will be selected depending on `device-pixel-ratio`.
10
- *
11
- * 2. via viewport width descriptor 'w' and sizes property containing source size descriptors, like
12
- * `srcset="photo-small.jpg 320w, photo-medium.jpg 640w, photo-huge.jpg 1280w"`
13
- * `sizes="(max-width: 600px) 400px, (max-width: 1200px) 70vw, 50vw"`
14
- *
15
- * The browser finds the first matching media query from source size descriptors,
16
- * then use source size value to generate internally srcset
17
- * with pixel density descriptors dividing width descriptor value by source size value.
18
- *
19
- * Using the example above for viewport width 800px.
20
- * The first matching media query is (max-width: 1200px)
21
- * source size value is 70vw equal to 800px * 0,7 = 560px
22
- *
23
- * browser internal srcset will be (we divide `w` descriptor by source size value):
24
- * photo-small.jpg 320/560x, photo-medium.jpg 640/560x, photo-huge.jpg 1280/560x =>
25
- * photo-small.jpg 0.57x, photo-medium.jpg 1.14x, photo-huge.jpg 2.28x
26
- *
27
- * Finally same rules as for pixel density descriptor 'x' are applied.
28
- *
29
- * ## Algorithm (without optimizations):
30
- *
31
- * We have a predefined array of all supported image sizes allSizes, this is the real width of an image in pixels.
32
- * This is good for caching, as we can cache image with specific width and then use it for different devices.
33
- *
34
- * > allSizes array is a tradeoff between cache and the best possible image size you deliver to the user.
35
- * > If allSizes.length is too small, you will deliver too big images to the user,
36
- * > if allSizes.length is too big, you will have many caches misses.
37
- *
38
- * If img has a defined width property.
39
- * 1. find the first value from allSizes which is greater or equal to the width property
40
- * 2. use found value to generate srcset with pixel density descriptor 'x'
41
- *
42
- *
43
- * If img has no defined width property.
44
- * 1. Generate srcset = allSizes.map((w) => `${getImageSrcAtWidth(w)} ${w}w`)
45
- * 2. Use sizes property, or if it is not defined use opinionated DEFAULT_SIZES = "(min-width: 1280px) 50vw, 100vw";
46
- *
47
- * Optimizations applied now:
48
- *
49
- * - If the sizes property is defined, we can exclude from `srcsets` all images
50
- * which are smaller than the `smallestRatio * smallesDeviceSize`
51
- *
52
- * Future (not implemented) optimizations and improvements:
53
- *
54
- * - Knowing image size on different viewport widths we can provide nondefault sizes property
55
- * - Knowledge of Image aspect-ratio would allow cropping images serverside.
56
- * - Early hints for high priority images https://blog.cloudflare.com/early-hints/
57
- * - Slow networks optimizations
58
- * - 404 etc processing with CSS - https://bitsofco.de/styling-broken-images/ (has some opinionated issues) or js solution with custom user fallback.
59
- *
60
- * # Attributions
61
- *
62
- * The MIT License (MIT)
63
- *
64
- * applies to:
65
- *
66
- * - https://github.com/vercel/next.js, Copyright (c) 2022 Vercel, Inc.
67
- *
68
- * The MIT License (MIT)
69
- *
70
- * Copyright (c) 2022 Vercel, Inc.
71
- *
72
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
73
- * and associated documentation files (the "Software"), to deal in the Software without restriction,
74
- * including without limitation the rights to use, copy, modify, merge, publish, distribute,
75
- * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
76
- * is furnished to do so, subject to the following conditions:
77
- *
78
- * The above copyright notice and this permission notice shall be included in all copies
79
- * or substantial portions of the Software.
80
- *
81
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
82
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
83
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
84
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
85
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
86
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
87
- **/
88
- export declare type ImageLoader = (props: {
89
- width: number;
90
- quality: number;
91
- src: string;
92
- }) => string;
93
- export declare const allSizes: number[];
94
- export declare const getImageAttributes: (props: {
95
- src: string | undefined;
96
- srcSet: string | undefined;
97
- sizes: string | undefined;
98
- width: string | number | undefined;
99
- quality: string | number | undefined;
100
- loader: ImageLoader;
101
- optimize: boolean;
102
- }) => {
103
- src: string;
104
- srcSet?: string;
105
- sizes?: string;
106
- } | null;
107
- //# sourceMappingURL=image-optimize.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-optimize.d.ts","sourceRoot":"","sources":["../src/image-optimize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAsFI;AAEJ,oBAAY,WAAW,GAAG,CAAC,KAAK,EAAE;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,KAAK,MAAM,CAAC;AAQb,eAAO,MAAM,QAAQ,UAAkC,CAAC;AA4GxD,eAAO,MAAM,kBAAkB,UAAW;IACxC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB,KAAG;IACF,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAuCH,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=image-optimize.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-optimize.test.d.ts","sourceRoot":"","sources":["../src/image-optimize.test.ts"],"names":[],"mappings":""}
package/lib/image.d.ts DELETED
@@ -1,11 +0,0 @@
1
- import { type ComponentProps } from "react";
2
- import { type ImageLoader } from "./image-optimize";
3
- declare const defaultTag = "img";
4
- declare type ImageProps = ComponentProps<typeof defaultTag> & {
5
- quality?: number;
6
- optimize?: boolean;
7
- loader: ImageLoader;
8
- };
9
- export declare const Image: import("react").ForwardRefExoticComponent<Pick<ImageProps, "quality" | "loader" | "key" | keyof import("react").ImgHTMLAttributes<HTMLImageElement> | "optimize"> & import("react").RefAttributes<HTMLImageElement>>;
10
- export {};
11
- //# sourceMappingURL=image.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/image.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AACzE,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAExE,QAAA,MAAM,UAAU,QAAQ,CAAC;AAEzB,aAAK,UAAU,GAAG,cAAc,CAAC,OAAO,UAAU,CAAC,GAAG;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,KAAK,sNAmBjB,CAAC"}
package/lib/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export { Image } from "./image";
2
- export type { ImageLoader } from "./image-optimize";
3
- export * as loaders from "./image-loaders";
4
- export { default as imageProps } from "./__generated__/image.props.json";
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kCAAkC,CAAC"}