@lonik/oh-image 2.1.3 → 2.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.
@@ -4,7 +4,7 @@ interface BaseLoaderOptions<T> {
4
4
  transforms?: T;
5
5
  }
6
6
  interface BaseGlobalLoaderOptions<T> extends BaseLoaderOptions<T> {
7
- placeholderTransforms?: T;
7
+ placeholder?: T;
8
8
  }
9
9
  interface BaseLoaderTransforms {
10
10
  [futureKey: string]: any;
package/dist/client.d.ts CHANGED
@@ -1,17 +1,31 @@
1
- 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
- }
1
+ declare module "*&oh" {
2
+ export interface StaticImageProps extends Partial<
3
+ Pick<
4
+ ImgHTMLAttributes<HTMLImageElement>,
5
+ | "fetchPriority"
6
+ | "decoding"
7
+ | "loading"
8
+ | "srcSet"
9
+ | "className"
10
+ | "sizes"
11
+ | "style"
12
+ >
13
+ > {
14
+ /** Alternative text for the image, required for accessibility. Use an empty string for decorative images. */
15
+ alt: string;
16
+
17
+ /** Configures the Image component to load the image immediately. */
18
+ priority?: boolean;
19
+
20
+ /**
21
+ * Sets the image to "fill mode", which eliminates the height/width requirement and adds
22
+ * styles such that the image fills its containing element.
23
+ */
24
+ fill?: boolean;
25
+
26
+ breakpoints?: number[];
27
+ }
13
28
 
14
- declare module "*?oh" {
15
- const imageSrc: any;
16
- export default imageSrc;
29
+ const component: React.FC<StaticImageProps>;
30
+ export default component;
17
31
  }
@@ -1,9 +1,9 @@
1
- import { o as ImageLoaderOptions } from "./index-BLvefiKI.js";
2
- import { n as BaseLoaderOptions, r as BaseLoaderTransforms, t as BaseGlobalLoaderOptions } from "./base-loader-options-DHja8Cql.js";
1
+ import { s as ImageLoaderOptions } from "./index-DG8i2dGY.js";
2
+ import { n as BaseLoaderOptions, r as BaseLoaderTransforms, t as BaseGlobalLoaderOptions } from "./base-loader-options-C1EZVxmE.js";
3
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
4
4
 
5
5
  //#region src/loaders/cloudflare/cloudflare-options.d.ts
6
- interface CloudflareTransforms extends BaseLoaderTransforms {
6
+ type CloudflareTransforms = BaseLoaderTransforms & Partial<{
7
7
  anim?: boolean;
8
8
  background?: string;
9
9
  blur?: number;
@@ -25,7 +25,7 @@ interface CloudflareTransforms extends BaseLoaderTransforms {
25
25
  rotate?: number;
26
26
  sharpen?: number;
27
27
  trim?: string;
28
- }
28
+ }>;
29
29
  type CloudflareOptions = BaseLoaderOptions<CloudflareTransforms>;
30
30
  type CloudflareGlobalOptions = BaseGlobalLoaderOptions<CloudflareTransforms>;
31
31
  //#endregion
@@ -35,6 +35,6 @@ declare const useCloudflareContext: () => CloudflareGlobalOptions, CloudflareLoa
35
35
  ...props
36
36
  }: {
37
37
  children: React.ReactNode;
38
- } & Partial<CloudflareGlobalOptions>) => react_jsx_runtime0.JSX.Element, useCloudflareLoader: (options?: CloudflareGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string), useCloudflarePlaceholder: (options?: CloudflareGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string);
38
+ } & Partial<CloudflareGlobalOptions>) => react_jsx_runtime0.JSX.Element, useCloudflareLoader: (options?: CloudflareGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string);
39
39
  //#endregion
40
- export { CloudflareGlobalOptions, CloudflareLoaderProvider, CloudflareOptions, CloudflareTransforms, useCloudflareContext, useCloudflareLoader, useCloudflarePlaceholder };
40
+ export { CloudflareGlobalOptions, CloudflareLoaderProvider, CloudflareOptions, CloudflareTransforms, useCloudflareContext, useCloudflareLoader };
@@ -1,9 +1,9 @@
1
- import { t as loaderFactory } from "./loader-factory-CPgnRdhT.js";
1
+ import { t as loaderFactory } from "./loader-factory-dkIeg239.js";
2
2
 
3
3
  //#region src/loaders/cloudflare/cloudflare-loader.tsx
4
- const { useLoaderContext: useCloudflareContext, LoaderProvider: CloudflareLoaderProvider, useLoader: useCloudflareLoader, usePlaceholder: useCloudflarePlaceholder } = loaderFactory({
4
+ const { useLoaderContext: useCloudflareContext, LoaderProvider: CloudflareLoaderProvider, useLoader: useCloudflareLoader } = loaderFactory({
5
5
  transforms: { format: "auto" },
6
- placeholderTransforms: {
6
+ placeholder: {
7
7
  quality: 10,
8
8
  format: "auto"
9
9
  }
@@ -13,4 +13,4 @@ const { useLoaderContext: useCloudflareContext, LoaderProvider: CloudflareLoader
13
13
  }, ({ path, params, imageOptions }) => `${path}/cdn-cgi/image/${params}/${imageOptions.src}`);
14
14
 
15
15
  //#endregion
16
- export { CloudflareLoaderProvider, useCloudflareContext, useCloudflareLoader, useCloudflarePlaceholder };
16
+ export { CloudflareLoaderProvider, useCloudflareContext, useCloudflareLoader };
@@ -1,6 +1,6 @@
1
- import { o as ImageLoaderOptions } from "./index-BLvefiKI.js";
2
- import { n as BaseLoaderOptions, r as BaseLoaderTransforms, t as BaseGlobalLoaderOptions } from "./base-loader-options-DHja8Cql.js";
3
- import * as react_jsx_runtime1 from "react/jsx-runtime";
1
+ import { s as ImageLoaderOptions } from "./index-DG8i2dGY.js";
2
+ import { n as BaseLoaderOptions, r as BaseLoaderTransforms, t as BaseGlobalLoaderOptions } from "./base-loader-options-C1EZVxmE.js";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
4
 
5
5
  //#region src/loaders/cloudinary/cloudinary-options.d.ts
6
6
  type BACKGROUND_MODE = "border" | "predominant" | "border_contrast" | "predominant_contrast" | "predominant_gradient" | "predominant_gradient_contrast" | "border_gradient" | "border_gradient_contrast";
@@ -9,7 +9,7 @@ type CROP_MODE = "auto" | "auto_pad" | "crop" | "fill" | "fill_pad" | "fit" | "i
9
9
  type COLOR_SPACE = "sRGB" | "tinysrgb" | "cmyk" | "no_cmyk" | "keep_cmyk" | "truecolor";
10
10
  type ART_FILTER = "al_dente" | "athena" | "audrey" | "aurora" | "daguerre" | "eucalyptus" | "fes" | "frost" | "hairspray" | "hokusai" | "incognito" | "linen" | "peacock" | "primavera" | "quartz" | "red_rock" | "refresh" | "sizzle" | "sonnet" | "ukulele" | "zorro";
11
11
  type FORMAT_TYPE = "3ds" | "ai" | "avif" | "bmp" | "bw" | "djvu" | "dng" | "eps" | "fbx" | "flif" | "gif" | "glb" | "gltf" | "heif" | "heic" | "ico" | "indd" | "jp2" | "jpg" | "jpeg" | "jxl" | "obj" | "pdf" | "ply" | "png" | "psd" | "raw" | "svg" | "tga" | "tif" | "tiff" | "u3ma" | "usdz" | "wdp" | "webp";
12
- interface CloudinaryTransforms extends BaseLoaderTransforms {
12
+ type CloudinaryTransforms = BaseLoaderTransforms & Partial<{
13
13
  a?: number | ANGLE_MODE | string;
14
14
  mode?: string;
15
15
  ar?: string | number;
@@ -96,7 +96,7 @@ interface CloudinaryTransforms extends BaseLoaderTransforms {
96
96
  x?: number | string;
97
97
  y?: number | string;
98
98
  z?: number;
99
- }
99
+ }>;
100
100
  type CloudinaryOptions = BaseLoaderOptions<CloudinaryTransforms>;
101
101
  type CloudinaryGlobalOptions = BaseGlobalLoaderOptions<CloudinaryTransforms>;
102
102
  //#endregion
@@ -106,6 +106,6 @@ declare const useCloudinaryContext: () => CloudinaryGlobalOptions, CloudinaryLoa
106
106
  ...props
107
107
  }: {
108
108
  children: React.ReactNode;
109
- } & Partial<CloudinaryGlobalOptions>) => react_jsx_runtime1.JSX.Element, useCloudinaryLoader: (options?: CloudinaryGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string), useCloudinaryPlaceholder: (options?: CloudinaryGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string);
109
+ } & Partial<CloudinaryGlobalOptions>) => react_jsx_runtime0.JSX.Element, useCloudinaryLoader: (options?: CloudinaryGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string);
110
110
  //#endregion
111
- export { CloudinaryGlobalOptions, CloudinaryLoaderProvider, CloudinaryOptions, CloudinaryTransforms, useCloudinaryContext, useCloudinaryLoader, useCloudinaryPlaceholder };
111
+ export { CloudinaryGlobalOptions, CloudinaryLoaderProvider, CloudinaryOptions, CloudinaryTransforms, useCloudinaryContext, useCloudinaryLoader };
@@ -1,19 +1,21 @@
1
- import { t as loaderFactory } from "./loader-factory-CPgnRdhT.js";
1
+ import { t as loaderFactory } from "./loader-factory-dkIeg239.js";
2
2
 
3
3
  //#region src/loaders/cloudinary/cloudinary-loader.tsx
4
4
  function customResolver(key, value) {
5
5
  if (typeof value === "boolean") return value ? key : void 0;
6
6
  return `${key}:${value}`;
7
7
  }
8
- const { useLoaderContext: useCloudinaryContext, LoaderProvider: CloudinaryLoaderProvider, useLoader: useCloudinaryLoader, usePlaceholder: useCloudinaryPlaceholder } = loaderFactory({
8
+ const { useLoaderContext: useCloudinaryContext, LoaderProvider: CloudinaryLoaderProvider, useLoader: useCloudinaryLoader } = loaderFactory({
9
9
  transforms: { f: "webp" },
10
- placeholderTransforms: {
10
+ placeholder: {
11
11
  q: 10,
12
12
  f: "webp"
13
13
  }
14
14
  }, {
15
15
  optionSeparator: "_",
16
16
  paramSeparator: ",",
17
+ widthKey: "w",
18
+ heightKey: "h",
17
19
  orders: {
18
20
  b_auto: [
19
21
  "mode",
@@ -71,4 +73,4 @@ const { useLoaderContext: useCloudinaryContext, LoaderProvider: CloudinaryLoader
71
73
  }, ({ path, params, imageOptions }) => `${path}/image/upload/${params}/${imageOptions.src}`);
72
74
 
73
75
  //#endregion
74
- export { CloudinaryLoaderProvider, useCloudinaryContext, useCloudinaryLoader, useCloudinaryPlaceholder };
76
+ export { CloudinaryLoaderProvider, useCloudinaryContext, useCloudinaryLoader };
@@ -1,6 +1,6 @@
1
- import { o as ImageLoaderOptions } from "./index-BLvefiKI.js";
2
- import { n as BaseLoaderOptions, t as BaseGlobalLoaderOptions } from "./base-loader-options-DHja8Cql.js";
3
- import * as react_jsx_runtime0 from "react/jsx-runtime";
1
+ import { s as ImageLoaderOptions } from "./index-DG8i2dGY.js";
2
+ import { n as BaseLoaderOptions, r as BaseLoaderTransforms, t as BaseGlobalLoaderOptions } from "./base-loader-options-C1EZVxmE.js";
3
+ import * as react_jsx_runtime1 from "react/jsx-runtime";
4
4
 
5
5
  //#region src/loaders/imgproxy/imgproxy-options.d.ts
6
6
  type ResizeType = "fit" | "fill" | "fill-down" | "force" | "auto";
@@ -99,7 +99,7 @@ interface PngOptions {
99
99
  quantize?: boolean;
100
100
  quantization_colors?: number;
101
101
  }
102
- interface ImgproxyTransforms {
102
+ type ImgproxyTransforms = BaseLoaderTransforms & Partial<{
103
103
  /**
104
104
  * Defines the resizing type, width, height, enlarge, and extend.
105
105
  * All arguments are optional and can be omitted to use their default values.
@@ -361,7 +361,7 @@ interface ImgproxyTransforms {
361
361
  * Default: empty
362
362
  */
363
363
  preset?: string[];
364
- }
364
+ }>;
365
365
  type ImgproxyOptions = BaseLoaderOptions<ImgproxyTransforms>;
366
366
  type ImgproxyGlobalOptions = BaseGlobalLoaderOptions<ImgproxyTransforms>;
367
367
  //#endregion
@@ -371,6 +371,6 @@ declare const useImgproxyContext: () => ImgproxyGlobalOptions, ImgproxyLoaderPro
371
371
  ...props
372
372
  }: {
373
373
  children: React.ReactNode;
374
- } & Partial<ImgproxyGlobalOptions>) => react_jsx_runtime0.JSX.Element, useImgproxyLoader: (options?: ImgproxyGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string), useImgproxyPlaceholder: (options?: ImgproxyGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string);
374
+ } & Partial<ImgproxyGlobalOptions>) => react_jsx_runtime1.JSX.Element, useImgproxyLoader: (options?: ImgproxyGlobalOptions | undefined) => (() => undefined) | ((imageOptions: ImageLoaderOptions) => string);
375
375
  //#endregion
376
- export { ImgproxyGlobalOptions, ImgproxyLoaderProvider, ImgproxyOptions, ImgproxyTransforms, useImgproxyContext, useImgproxyLoader, useImgproxyPlaceholder };
376
+ export { ImgproxyGlobalOptions, ImgproxyLoaderProvider, ImgproxyOptions, ImgproxyTransforms, useImgproxyContext, useImgproxyLoader };
package/dist/imgproxy.js CHANGED
@@ -1,9 +1,9 @@
1
- import { t as loaderFactory } from "./loader-factory-CPgnRdhT.js";
1
+ import { t as loaderFactory } from "./loader-factory-dkIeg239.js";
2
2
 
3
3
  //#region src/loaders/imgproxy/imgproxy-loader.tsx
4
- const { useLoaderContext: useImgproxyContext, LoaderProvider: ImgproxyLoaderProvider, useLoader: useImgproxyLoader, usePlaceholder: useImgproxyPlaceholder } = loaderFactory({
4
+ const { useLoaderContext: useImgproxyContext, LoaderProvider: ImgproxyLoaderProvider, useLoader: useImgproxyLoader } = loaderFactory({
5
5
  transforms: { format: "webp" },
6
- placeholderTransforms: {
6
+ placeholder: {
7
7
  quality: 10,
8
8
  format: "webp"
9
9
  }
@@ -97,4 +97,4 @@ const { useLoaderContext: useImgproxyContext, LoaderProvider: ImgproxyLoaderProv
97
97
  }, ({ path, params, imageOptions }) => `${path}/${params}/plain/${imageOptions.src}`);
98
98
 
99
99
  //#endregion
100
- export { ImgproxyLoaderProvider, useImgproxyContext, useImgproxyLoader, useImgproxyPlaceholder };
100
+ export { ImgproxyLoaderProvider, useImgproxyContext, useImgproxyLoader };
@@ -6,20 +6,18 @@ interface ImageLoaderOptions {
6
6
  src: string;
7
7
  width?: number | null | undefined;
8
8
  height?: number | null | undefined;
9
+ isPlaceholder?: boolean;
9
10
  }
10
11
  type ImageLoader = (options: ImageLoaderOptions) => string | undefined;
11
- type ImageSrcType = string | ImageSrc;
12
12
  interface ImageProps extends Partial<Pick<ImgHTMLAttributes<HTMLImageElement>, "fetchPriority" | "decoding" | "loading" | "srcSet" | "className" | "sizes" | "style">> {
13
13
  /** Alternative text for the image, required for accessibility. Use an empty string for decorative images. */
14
14
  alt: string;
15
- /** @deprecated Use `priority` instead. */
16
- asap?: boolean;
17
15
  /** Configures the Image component to load the image immediately. */
18
16
  priority?: boolean;
19
17
  /** */
20
- src: ImageSrcType;
18
+ src: string;
21
19
  /** The URL of the placeholder image to display while loading. */
22
- placeholder?: string | undefined | ImageLoader | null;
20
+ placeholder?: string | undefined | boolean | null;
23
21
  /**
24
22
  * Sets the image to "fill mode", which eliminates the height/width requirement and adds
25
23
  * styles such that the image fills its containing element.
@@ -34,6 +32,9 @@ interface ImageProps extends Partial<Pick<ImgHTMLAttributes<HTMLImageElement>, "
34
32
  //#region src/react/image.d.ts
35
33
  declare function Image(props: ImageProps): react_jsx_runtime3.JSX.Element;
36
34
  //#endregion
35
+ //#region src/react/image-factory.d.ts
36
+ declare function __imageFactory(defaultProps: any): (props: any) => react_jsx_runtime3.JSX.Element;
37
+ //#endregion
37
38
  //#region src/react/use-img-loaded.d.ts
38
39
  /**
39
40
  * A hook that tracks whether an image element has finished loading.
@@ -64,7 +65,7 @@ declare function Image(props: ImageProps): react_jsx_runtime3.JSX.Element;
64
65
  declare function useImgLoaded(src: string | undefined): [(img: HTMLImageElement | null) => void, boolean];
65
66
  //#endregion
66
67
  //#region src/react/image-context.d.ts
67
- interface ImageContextValue extends Pick<ImageProps, "loading"> {
68
+ interface ImageContextValue extends Pick<ImageProps, "placeholder" | "breakpoints" | "loader"> {
68
69
  breakpoints: number[];
69
70
  loader: ImageLoader | null;
70
71
  }
@@ -76,4 +77,4 @@ declare function ImageProvider({
76
77
  children: React.ReactNode;
77
78
  } & Partial<ImageContextValue>): react_jsx_runtime3.JSX.Element;
78
79
  //#endregion
79
- export { ImageLoader as a, ImageSrcType as c, Image as i, useImageContext as n, ImageLoaderOptions as o, useImgLoaded as r, ImageProps as s, ImageProvider as t };
80
+ export { Image as a, ImageProps as c, __imageFactory as i, useImageContext as n, ImageLoader as o, useImgLoaded as r, ImageLoaderOptions as s, ImageProvider as t };
@@ -58,21 +58,29 @@ function loaderFactory(defaults, config, urlResolver) {
58
58
  children
59
59
  });
60
60
  }
61
- const loader = (isPlaceholder) => (options) => {
61
+ const loader = () => (options) => {
62
62
  const context = useLoaderContext();
63
63
  const path = options?.path || context.path;
64
- const transforms = {
65
- ...isPlaceholder ? context.placeholderTransforms : context.transforms,
66
- ...options?.transforms
67
- };
68
64
  if (!path) {
69
65
  console.warn("Path is not provided");
70
66
  return () => void 0;
71
67
  }
72
68
  return (imageOptions) => {
69
+ const defaultTransform = imageOptions.isPlaceholder ? context.placeholder : context.transforms;
70
+ const optionTransforms = imageOptions.isPlaceholder ? options?.placeholder : options?.transforms;
71
+ const transforms = {
72
+ ...defaultTransform,
73
+ ...optionTransforms
74
+ };
73
75
  const params = [];
74
- if (imageOptions.width) params.push("width" + config.optionSeparator + imageOptions.width);
75
- if (imageOptions.height) params.push("height" + config.optionSeparator + imageOptions.height);
76
+ if (imageOptions.width) {
77
+ const widthKey = config.widthKey ?? "width";
78
+ params.push(widthKey + config.optionSeparator + imageOptions.width);
79
+ }
80
+ if (imageOptions.height) {
81
+ const heightKey = config.heightKey ?? "height";
82
+ params.push(heightKey + config.optionSeparator + imageOptions.height);
83
+ }
76
84
  const resolvedTransforms = resolveTransform(transforms, config);
77
85
  return urlResolver({
78
86
  imageOptions,
@@ -85,8 +93,7 @@ function loaderFactory(defaults, config, urlResolver) {
85
93
  LoaderProvider,
86
94
  loaderContext,
87
95
  useLoaderContext,
88
- useLoader: loader(false),
89
- usePlaceholder: loader(true)
96
+ useLoader: loader()
90
97
  };
91
98
  }
92
99
 
package/dist/plugin.js CHANGED
@@ -202,7 +202,7 @@ const DEFAULT_CONFIGS = {
202
202
  format: "webp",
203
203
  placeholder: true
204
204
  };
205
- const PROCESS_KEY = "oh";
205
+ const PROCESS_KEY = "$oh";
206
206
  const SUPPORTED_IMAGE_FORMATS = /\.(jpe?g|png|webp|avif|gif|svg)(\?.*)?$/i;
207
207
  const DEV_DIR = "/@oh-images/";
208
208
  function ohImage(options) {
@@ -290,7 +290,7 @@ function ohImage(options) {
290
290
  width: metadata.width,
291
291
  height: metadata.height,
292
292
  src: mainIdentifier,
293
- srcSets: ""
293
+ srcSet: ""
294
294
  };
295
295
  if (mergedOptions.placeholder) {
296
296
  const placeholderIdentifier = identifier.placeholder(DEFAULT_IMAGE_FORMAT);
@@ -309,7 +309,7 @@ function ohImage(options) {
309
309
  normalize: mergedOptions.normalize,
310
310
  threshold: mergedOptions.threshold
311
311
  });
312
- src.placeholderUrl = placeholderIdentifier;
312
+ src.placeholder = placeholderIdentifier;
313
313
  }
314
314
  if (mergedOptions.breakpoints) {
315
315
  const srcSets = [];
@@ -332,9 +332,20 @@ function ohImage(options) {
332
332
  });
333
333
  srcSets.push(`${srcSetIdentifier} ${breakpoint}w`);
334
334
  }
335
- src.srcSets = srcSets.join(", ");
335
+ src.srcSet = srcSets.join(", ");
336
336
  }
337
- return `export default ${JSON.stringify(src)};`;
337
+ return `
338
+ import { __imageFactory } from "@lonik/oh-image/react";
339
+
340
+ export default __imageFactory(${JSON.stringify({
341
+ width: src.width,
342
+ height: src.height,
343
+ src: src.src,
344
+ srcSet: src.srcSet,
345
+ placeholder: src.placeholder,
346
+ alt: ""
347
+ })})
348
+ `;
338
349
  } catch (err) {
339
350
  console.error(`Couldn't load image with id: ${id} error:${err}`);
340
351
  return null;
package/dist/react.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as ImageLoader, c as ImageSrcType, i as Image, n as useImageContext, o as ImageLoaderOptions, r as useImgLoaded, s as ImageProps, t as ImageProvider } from "./index-BLvefiKI.js";
2
- export { Image, ImageLoader, ImageLoaderOptions, ImageProps, ImageProvider, ImageSrcType, useImageContext, useImgLoaded };
1
+ import { a as Image, c as ImageProps, i as __imageFactory, n as useImageContext, o as ImageLoader, r as useImgLoaded, s as ImageLoaderOptions, t as ImageProvider } from "./index-DG8i2dGY.js";
2
+ export { Image, ImageLoader, ImageLoaderOptions, ImageProps, ImageProvider, __imageFactory, useImageContext, useImgLoaded };
package/dist/react.js CHANGED
@@ -1,4 +1,3 @@
1
- import { t as assertProps } from "./prop-asserts-ZcucnyC7.js";
2
1
  import * as ReactDOM from "react-dom";
3
2
  import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
4
3
  import { jsx } from "react/jsx-runtime";
@@ -85,7 +84,7 @@ function useImgLoaded(src) {
85
84
  * RegExpr to determine whether a src in a srcset is using width descriptors.
86
85
  * Should match something like: "100w, 200w".
87
86
  */
88
- const VALID_WIDTH_DESCRIPTOR_SRCSET = /^((\s*\d+w\s*(,|$)){1,})$/;
87
+ const VALID_WIDTH_DESCRIPTOR_SRCSET = /^(\s*\S+\s+\d+w\s*(,|$)\s*)+$/;
89
88
  function resolveOptions(prop, defaultOptions) {
90
89
  const resolved = {
91
90
  ...defaultOptions,
@@ -103,15 +102,14 @@ function resolveOptions(prop, defaultOptions) {
103
102
  return resolved;
104
103
  }
105
104
  function resolveDecoding(prop) {
106
- return prop.priority || prop.asap ? "async" : prop.decoding;
105
+ return prop.priority ? "async" : prop.decoding;
107
106
  }
108
107
  function resolveFetchPriority(prop) {
109
- if (prop.priority || prop.asap) return "high";
108
+ if (prop.priority) return "high";
110
109
  return prop.fetchPriority ?? "auto";
111
110
  }
112
111
  function resolveSrcSet(prop) {
113
112
  if (prop.srcSet) return prop.srcSet;
114
- if (typeof prop.src === "object") return prop.src.srcSets;
115
113
  if (!prop.breakpoints) return;
116
114
  const baseSrc = prop.src;
117
115
  const entries = [];
@@ -124,7 +122,7 @@ function resolveSrcSet(prop) {
124
122
  return entries.join(", ");
125
123
  }
126
124
  function resolveLoading(prop) {
127
- const priority = prop.priority || prop.asap;
125
+ const priority = prop.priority;
128
126
  if (!priority && prop.loading !== void 0) return prop.loading;
129
127
  return priority ? "eager" : "lazy";
130
128
  }
@@ -139,7 +137,6 @@ function resolveSizes(prop, resolvedSrcSet, resolvedLoading) {
139
137
  return sizes;
140
138
  }
141
139
  function resolveSrc(prop) {
142
- if (typeof prop.src === "object") return prop.src.src;
143
140
  if (prop.loader) return prop.loader({
144
141
  src: prop.src,
145
142
  width: prop.width,
@@ -149,23 +146,55 @@ function resolveSrc(prop) {
149
146
  }
150
147
  function resolveWidth(prop) {
151
148
  if (prop.width) return prop.width;
152
- if (typeof prop.src === "object") return prop.src.width;
153
149
  }
154
150
  function resolveHeight(prop) {
155
151
  if (prop.height) return prop.height;
156
- if (typeof prop.src === "object") return prop.src.height;
157
152
  }
158
153
  function resolvePlaceholder(prop, src) {
159
154
  if (!prop.placeholder) return null;
160
155
  if (typeof prop.placeholder === "string") return prop.placeholder;
161
- if (typeof prop.placeholder === "function") return prop.placeholder({
156
+ if (prop.loader) return prop.loader({
162
157
  src,
158
+ isPlaceholder: true,
163
159
  width: prop.width,
164
160
  height: prop.height
165
161
  });
166
162
  return null;
167
163
  }
168
164
 
165
+ //#endregion
166
+ //#region src/react/prop-asserts.ts
167
+ function assertProps(prop) {
168
+ try {
169
+ assertLoadingProp(prop);
170
+ assertDecodingProp(prop);
171
+ assertFetchPriorityProp(prop);
172
+ assertFillProp(prop);
173
+ assertDimensionsProp(prop);
174
+ } catch (err) {
175
+ const message = err instanceof Error ? err.message : err;
176
+ console.warn(message);
177
+ }
178
+ }
179
+ function assert(assertion, message) {
180
+ if (assertion()) throw new Error(message || void 0);
181
+ }
182
+ function assertLoadingProp(prop) {
183
+ assert(() => prop.loading && prop.priority, `Do not use \`loading\` on a priority image — priority images are always eagerly loaded.`);
184
+ }
185
+ function assertDecodingProp(prop) {
186
+ assert(() => prop.decoding && prop.priority, `Do not use \`decoding\` on a priority image — priority images always use async decoding.`);
187
+ }
188
+ function assertFetchPriorityProp(prop) {
189
+ assert(() => prop.fetchPriority && prop.priority, `Do not use \`fetchPriority\` on a priority image — priority images always use high fetch priority.`);
190
+ }
191
+ function assertFillProp(prop) {
192
+ assert(() => prop.fill && (prop.width !== void 0 || prop.height !== void 0), `Do not use \`width\` or \`height\` with \`fill\` — fill mode makes the image fill its container.`);
193
+ }
194
+ function assertDimensionsProp(prop) {
195
+ assert(() => typeof prop.src === "string" && !prop.fill && prop.width === void 0 && prop.height === void 0, `Image is missing \`width\` and \`height\` props. Either provide dimensions, use \`fill\`, or use an imported image source.`);
196
+ }
197
+
169
198
  //#endregion
170
199
  //#region src/react/image-context.tsx
171
200
  const ImageContext = createContext({
@@ -182,8 +211,8 @@ const ImageContext = createContext({
182
211
  1200,
183
212
  1920
184
213
  ],
185
- loading: "lazy",
186
- loader: null
214
+ loader: null,
215
+ placeholder: true
187
216
  });
188
217
  function useImageContext() {
189
218
  return useContext(ImageContext);
@@ -230,7 +259,7 @@ function Image(props) {
230
259
  ...fillStyles,
231
260
  ...props.style
232
261
  };
233
- if (preload && options.asap) preload(options.src, {
262
+ if (preload && options.priority) preload(options.src, {
234
263
  as: "image",
235
264
  fetchPriority: "high"
236
265
  });
@@ -251,4 +280,15 @@ function Image(props) {
251
280
  }
252
281
 
253
282
  //#endregion
254
- export { Image, ImageProvider, useImageContext, useImgLoaded };
283
+ //#region src/react/image-factory.tsx
284
+ function __imageFactory(defaultProps) {
285
+ return (props) => {
286
+ return /* @__PURE__ */ jsx(Image, {
287
+ ...defaultProps,
288
+ ...props
289
+ });
290
+ };
291
+ }
292
+
293
+ //#endregion
294
+ export { Image, ImageProvider, __imageFactory, useImageContext, useImgLoaded };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lonik/oh-image",
3
3
  "type": "module",
4
- "version": "2.1.3",
4
+ "version": "2.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",
@@ -95,6 +95,8 @@
95
95
  "typescript": "^5.9.3",
96
96
  "typescript-eslint": "^8.54.0",
97
97
  "vite": "^7.3.0",
98
+ "vite-plugin-inspect": "^11.3.3",
99
+ "vite-tsconfig-paths": "^6.1.1",
98
100
  "vitest": "^4.0.16"
99
101
  },
100
102
  "dependencies": {
@@ -1,40 +0,0 @@
1
- //#region src/react/prop-asserts.ts
2
- function assertProps(prop) {
3
- try {
4
- if (prop.asap !== void 0) console.warn("The `asap` prop is deprecated and will be removed in a future version. Please use `priority` instead.");
5
- assertLoadingProp(prop);
6
- assertDecodingProp(prop);
7
- assertFetchPriorityProp(prop);
8
- assertBreakpointsProp(prop);
9
- assertFillProp(prop);
10
- assertDimensionsProp(prop);
11
- } catch (err) {
12
- const message = err instanceof Error ? err.message : err;
13
- console.warn(message);
14
- }
15
- }
16
- function assert(assertion, message) {
17
- if (assertion()) throw new Error(message || void 0);
18
- }
19
- function assertLoadingProp(prop) {
20
- assert(() => prop.loading && (prop.priority || prop.asap), `Do not use \`loading\` on a priority image — priority images are always eagerly loaded.`);
21
- }
22
- function assertDecodingProp(prop) {
23
- assert(() => prop.decoding && (prop.priority || prop.asap), `Do not use \`decoding\` on a priority image — priority images always use async decoding.`);
24
- }
25
- function assertFetchPriorityProp(prop) {
26
- assert(() => prop.fetchPriority && (prop.priority || prop.asap), `Do not use \`fetchPriority\` on a priority image — priority images always use high fetch priority.`);
27
- }
28
- function assertBreakpointsProp(prop) {
29
- assert(() => prop.breakpoints && typeof prop.src === "object", `Do not use \`breakpoints\` when \`src\` is an imported image — the image's built-in srcSets are used instead.`);
30
- assert(() => prop.breakpoints && typeof prop.src === "string" && !prop.loader, `Do not use \`breakpoints\` without a \`loader\` — breakpoints require a loader to generate srcSet entries.`);
31
- }
32
- function assertFillProp(prop) {
33
- assert(() => prop.fill && (prop.width !== void 0 || prop.height !== void 0), `Do not use \`width\` or \`height\` with \`fill\` — fill mode makes the image fill its container.`);
34
- }
35
- function assertDimensionsProp(prop) {
36
- assert(() => typeof prop.src === "string" && !prop.fill && prop.width === void 0 && prop.height === void 0, `Image is missing \`width\` and \`height\` props. Either provide dimensions, use \`fill\`, or use an imported image source.`);
37
- }
38
-
39
- //#endregion
40
- export { assertProps as t };