@lonik/oh-image 2.0.6 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react.d.ts +384 -15
- package/dist/react.js +256 -55
- package/package.json +10 -4
package/dist/react.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ interface ImageLoaderOptions {
|
|
|
6
6
|
src: string;
|
|
7
7
|
width?: number | null | undefined;
|
|
8
8
|
height?: number | null | undefined;
|
|
9
|
-
isPlaceholder?: boolean;
|
|
10
9
|
}
|
|
11
10
|
type ImageLoader = (options: ImageLoaderOptions) => string;
|
|
12
11
|
type ImageSrcType = string | ImageSrc;
|
|
@@ -20,7 +19,7 @@ interface ImageProps extends Partial<Pick<ImgHTMLAttributes<HTMLImageElement>, "
|
|
|
20
19
|
/** */
|
|
21
20
|
src: ImageSrcType;
|
|
22
21
|
/** The URL of the placeholder image to display while loading. */
|
|
23
|
-
|
|
22
|
+
placeholder?: string | undefined | ImageLoader | null;
|
|
24
23
|
/**
|
|
25
24
|
* Sets the image to "fill mode", which eliminates the height/width requirement and adds
|
|
26
25
|
* styles such that the image fills its containing element.
|
|
@@ -77,24 +76,394 @@ declare function ImageProvider({
|
|
|
77
76
|
children: React.ReactNode;
|
|
78
77
|
} & Partial<ImageContextValue>): react_jsx_runtime0.JSX.Element;
|
|
79
78
|
//#endregion
|
|
80
|
-
//#region src/react/loaders/
|
|
81
|
-
interface
|
|
82
|
-
path
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
params?:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
//#region src/react/loaders/base-loader-options.d.ts
|
|
80
|
+
interface BaseLoaderOptions<T> {
|
|
81
|
+
path?: string;
|
|
82
|
+
transforms?: T;
|
|
83
|
+
/** @deprecated Use `transforms` instead. */
|
|
84
|
+
params?: any;
|
|
85
|
+
}
|
|
86
|
+
interface BaseGlobalLoaderOptions<T> extends BaseLoaderOptions<T> {
|
|
87
|
+
placeholderTransforms?: T;
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/react/loaders/imgproxy/imgproxy-options.d.ts
|
|
91
|
+
type ResizeType = "fit" | "fill" | "fill-down" | "force" | "auto";
|
|
92
|
+
type ResizeAlgorithm = "nearest" | "linear" | "cubic" | "lanczos2" | "lanczos3";
|
|
93
|
+
type GravityType = "no" | "so" | "ea" | "we" | "noea" | "nowe" | "soea" | "sowe" | "ce";
|
|
94
|
+
interface ResizeOptions {
|
|
95
|
+
resizing_type?: ResizeType;
|
|
96
|
+
width?: number;
|
|
97
|
+
height?: number;
|
|
98
|
+
enlarge?: boolean;
|
|
99
|
+
extend?: boolean;
|
|
100
|
+
}
|
|
101
|
+
interface SizeOptions {
|
|
102
|
+
width?: number;
|
|
103
|
+
height?: number;
|
|
104
|
+
enlarge?: boolean;
|
|
105
|
+
extend?: boolean;
|
|
106
|
+
}
|
|
107
|
+
interface ExtendOptions {
|
|
108
|
+
extend?: boolean;
|
|
109
|
+
gravity?: GravityType;
|
|
110
|
+
}
|
|
111
|
+
interface GravityOptions {
|
|
112
|
+
type: GravityType;
|
|
113
|
+
x_offset?: number;
|
|
114
|
+
y_offset?: number;
|
|
115
|
+
}
|
|
116
|
+
interface CropOptions {
|
|
117
|
+
width: number;
|
|
118
|
+
height: number;
|
|
119
|
+
gravity?: GravityType;
|
|
120
|
+
}
|
|
121
|
+
interface TrimOptions {
|
|
122
|
+
threshold: number;
|
|
123
|
+
color?: string;
|
|
124
|
+
equal_hor?: boolean;
|
|
125
|
+
equal_ver?: boolean;
|
|
126
|
+
}
|
|
127
|
+
interface PaddingOptions {
|
|
128
|
+
top?: number;
|
|
129
|
+
right?: number;
|
|
130
|
+
bottom?: number;
|
|
131
|
+
left?: number;
|
|
132
|
+
}
|
|
133
|
+
interface BackgroundOptions {
|
|
134
|
+
r: number;
|
|
135
|
+
g: number;
|
|
136
|
+
b: number;
|
|
137
|
+
}
|
|
138
|
+
interface AdjustOptions {
|
|
139
|
+
brightness?: number;
|
|
140
|
+
contrast?: number;
|
|
141
|
+
saturation?: number;
|
|
142
|
+
}
|
|
143
|
+
interface BlurDetectionsOptions {
|
|
144
|
+
sigma: number;
|
|
145
|
+
class_names: string[];
|
|
89
146
|
}
|
|
90
|
-
|
|
147
|
+
interface DrawDetectionsOptions {
|
|
148
|
+
draw: boolean;
|
|
149
|
+
class_names: string[];
|
|
150
|
+
}
|
|
151
|
+
interface WatermarkOptions {
|
|
152
|
+
opacity: number;
|
|
153
|
+
position?: GravityType | "re";
|
|
154
|
+
x_offset?: number;
|
|
155
|
+
y_offset?: number;
|
|
156
|
+
scale?: number;
|
|
157
|
+
}
|
|
158
|
+
interface WatermarkSizeOptions {
|
|
159
|
+
width: number;
|
|
160
|
+
height: number;
|
|
161
|
+
}
|
|
162
|
+
interface UnsharpeningOptions {
|
|
163
|
+
mode?: string;
|
|
164
|
+
weight?: number;
|
|
165
|
+
dividor?: number;
|
|
166
|
+
}
|
|
167
|
+
interface AutoqualityOptions {
|
|
168
|
+
method?: string;
|
|
169
|
+
target?: number;
|
|
170
|
+
min_quality?: number;
|
|
171
|
+
max_quality?: number;
|
|
172
|
+
allowed_error?: number;
|
|
173
|
+
}
|
|
174
|
+
interface JpegOptions {
|
|
175
|
+
progressive?: boolean;
|
|
176
|
+
no_subsample?: boolean;
|
|
177
|
+
trellis_quant?: boolean;
|
|
178
|
+
overshoot_deringing?: boolean;
|
|
179
|
+
optimize_scans?: boolean;
|
|
180
|
+
quant_table?: number;
|
|
181
|
+
}
|
|
182
|
+
interface PngOptions {
|
|
183
|
+
interlaced?: boolean;
|
|
184
|
+
quantize?: boolean;
|
|
185
|
+
quantization_colors?: number;
|
|
186
|
+
}
|
|
187
|
+
interface ImgproxyTransforms {
|
|
188
|
+
/**
|
|
189
|
+
* Defines the resizing type, width, height, enlarge, and extend.
|
|
190
|
+
* All arguments are optional and can be omitted to use their default values.
|
|
191
|
+
*/
|
|
192
|
+
resize?: ResizeOptions;
|
|
193
|
+
/**
|
|
194
|
+
* Defines the width, height, enlarge, and extend.
|
|
195
|
+
* All arguments are optional and can be omitted to use their default values.
|
|
196
|
+
*/
|
|
197
|
+
size?: SizeOptions;
|
|
198
|
+
/**
|
|
199
|
+
* Defines how imgproxy will resize the source image.
|
|
200
|
+
* Default: fit
|
|
201
|
+
*/
|
|
202
|
+
resizing_type?: ResizeType;
|
|
203
|
+
/**
|
|
204
|
+
* Defines the algorithm that imgproxy will use for resizing.
|
|
205
|
+
* Default: lanczos3
|
|
206
|
+
*/
|
|
207
|
+
resizing_algorithm?: ResizeAlgorithm;
|
|
208
|
+
/**
|
|
209
|
+
* Defines the width of the resulting image.
|
|
210
|
+
* Default: 0
|
|
211
|
+
*/
|
|
212
|
+
width?: number;
|
|
213
|
+
/**
|
|
214
|
+
* Defines the height of the resulting image.
|
|
215
|
+
* Default: 0
|
|
216
|
+
*/
|
|
217
|
+
height?: number;
|
|
218
|
+
/**
|
|
219
|
+
* Defines the minimum width of the resulting image.
|
|
220
|
+
* Default: 0
|
|
221
|
+
*/
|
|
222
|
+
"min-width"?: number;
|
|
223
|
+
/**
|
|
224
|
+
* Defines the minimum height of the resulting image.
|
|
225
|
+
* Default: 0
|
|
226
|
+
*/
|
|
227
|
+
"min-height"?: number;
|
|
228
|
+
/**
|
|
229
|
+
* When set, imgproxy will multiply the image dimensions according to these factors.
|
|
230
|
+
* Default: 1
|
|
231
|
+
*/
|
|
232
|
+
zoom?: number | {
|
|
233
|
+
x: number;
|
|
234
|
+
y: number;
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* When set, imgproxy will multiply the image dimensions according to this factor for HiDPI (Retina) devices.
|
|
238
|
+
* Default: 1
|
|
239
|
+
*/
|
|
240
|
+
dpr?: number;
|
|
241
|
+
/**
|
|
242
|
+
* When set to true, imgproxy will enlarge the image if it is smaller than the given size.
|
|
243
|
+
* Default: false
|
|
244
|
+
*/
|
|
245
|
+
enlarge?: boolean;
|
|
246
|
+
/**
|
|
247
|
+
* When set to true, imgproxy will extend the image if it is smaller than the given size.
|
|
248
|
+
* Can also specify gravity.
|
|
249
|
+
* Default: false:ce:0:0
|
|
250
|
+
*/
|
|
251
|
+
extend?: boolean | ExtendOptions;
|
|
252
|
+
/**
|
|
253
|
+
* When imgproxy needs to cut some parts of the image, it is guided by the gravity option.
|
|
254
|
+
* Default: ce:0:0
|
|
255
|
+
*/
|
|
256
|
+
gravity?: GravityOptions;
|
|
257
|
+
/**
|
|
258
|
+
* Defines an area of the image to be processed (crop before resize).
|
|
259
|
+
*/
|
|
260
|
+
crop?: CropOptions;
|
|
261
|
+
/**
|
|
262
|
+
* Removes surrounding background.
|
|
263
|
+
*/
|
|
264
|
+
trim?: TrimOptions;
|
|
265
|
+
/**
|
|
266
|
+
* Defines padding size.
|
|
267
|
+
*/
|
|
268
|
+
padding?: PaddingOptions;
|
|
269
|
+
/**
|
|
270
|
+
* When set to true, imgproxy will automatically rotate images based on the EXIF Orientation parameter.
|
|
271
|
+
*/
|
|
272
|
+
auto_rotate?: boolean;
|
|
273
|
+
/**
|
|
274
|
+
* Rotates the image on the specified angle.
|
|
275
|
+
* Default: 0
|
|
276
|
+
*/
|
|
277
|
+
rotate?: number;
|
|
278
|
+
/**
|
|
279
|
+
* When set, imgproxy will fill the resulting image background with the specified color.
|
|
280
|
+
* Default: disabled
|
|
281
|
+
*/
|
|
282
|
+
background?: string | BackgroundOptions;
|
|
283
|
+
/**
|
|
284
|
+
* Adds an alpha channel to background.
|
|
285
|
+
* Default: 1
|
|
286
|
+
*/
|
|
287
|
+
background_alpha?: number;
|
|
288
|
+
/**
|
|
289
|
+
* Defines the brightness, contrast, and saturation.
|
|
290
|
+
*/
|
|
291
|
+
adjust?: AdjustOptions;
|
|
292
|
+
/**
|
|
293
|
+
* When set, imgproxy will adjust brightness of the resulting image.
|
|
294
|
+
* Default: 0
|
|
295
|
+
*/
|
|
296
|
+
brightness?: number;
|
|
297
|
+
/**
|
|
298
|
+
* When set, imgproxy will adjust the contrast of the resulting image.
|
|
299
|
+
* Default: 1
|
|
300
|
+
*/
|
|
301
|
+
contrast?: number;
|
|
302
|
+
/**
|
|
303
|
+
* When set, imgproxy will adjust saturation of the resulting image.
|
|
304
|
+
* Default: 1
|
|
305
|
+
*/
|
|
306
|
+
saturation?: number;
|
|
307
|
+
/**
|
|
308
|
+
* When set, imgproxy will apply a gaussian blur filter to the resulting image.
|
|
309
|
+
* Default: disabled
|
|
310
|
+
*/
|
|
311
|
+
blur?: number;
|
|
312
|
+
/**
|
|
313
|
+
* When set, imgproxy will apply the sharpen filter to the resulting image.
|
|
314
|
+
* Default: disabled
|
|
315
|
+
*/
|
|
316
|
+
sharpen?: number;
|
|
317
|
+
/**
|
|
318
|
+
* When set, imgproxy will apply the pixelate filter to the resulting image.
|
|
319
|
+
* Default: disabled
|
|
320
|
+
*/
|
|
321
|
+
pixelate?: number;
|
|
322
|
+
/**
|
|
323
|
+
* Allows redefining unsharpening options.
|
|
324
|
+
*/
|
|
325
|
+
unsharpening?: UnsharpeningOptions;
|
|
326
|
+
/**
|
|
327
|
+
* imgproxy detects objects of the provided classes and blurs them.
|
|
328
|
+
*/
|
|
329
|
+
blur_detections?: BlurDetectionsOptions;
|
|
330
|
+
/**
|
|
331
|
+
* When draw is set to true, imgproxy detects objects of the provided classes and draws their bounding boxes.
|
|
332
|
+
*/
|
|
333
|
+
draw_detections?: DrawDetectionsOptions;
|
|
334
|
+
/**
|
|
335
|
+
* Places a watermark on the processed image.
|
|
336
|
+
* Default: disabled
|
|
337
|
+
*/
|
|
338
|
+
watermark?: WatermarkOptions;
|
|
339
|
+
/**
|
|
340
|
+
* When set, imgproxy will use the image from the specified URL as a watermark.
|
|
341
|
+
* Default: blank
|
|
342
|
+
*/
|
|
343
|
+
watermark_url?: string;
|
|
344
|
+
/**
|
|
345
|
+
* When set, imgproxy will generate an image from the provided text and use it as a watermark.
|
|
346
|
+
* Default: blank
|
|
347
|
+
*/
|
|
348
|
+
watermark_text?: string;
|
|
349
|
+
/**
|
|
350
|
+
* Defines the desired width and height of the watermark.
|
|
351
|
+
* Default: 0:0
|
|
352
|
+
*/
|
|
353
|
+
watermark_size?: WatermarkSizeOptions;
|
|
354
|
+
/**
|
|
355
|
+
* When set, imgproxy will prepend a <style> node with the provided content to the <svg> node.
|
|
356
|
+
* Default: blank
|
|
357
|
+
*/
|
|
358
|
+
style?: string;
|
|
359
|
+
/**
|
|
360
|
+
* When set to true, imgproxy will strip the metadata (EXIF, IPTC, etc.) on JPEG and WebP output images.
|
|
361
|
+
*/
|
|
362
|
+
strip_metadata?: boolean;
|
|
363
|
+
/**
|
|
364
|
+
* When set to true, imgproxy will not remove copyright info while stripping metadata.
|
|
365
|
+
*/
|
|
366
|
+
keep_copyright?: boolean;
|
|
367
|
+
/**
|
|
368
|
+
* When set to true, imgproxy will transform the embedded color profile (ICC) to sRGB and remove it from the image.
|
|
369
|
+
*/
|
|
370
|
+
strip_color_profile?: boolean;
|
|
371
|
+
/**
|
|
372
|
+
* When set to true and the source image has an embedded thumbnail, imgproxy will always use the embedded thumbnail.
|
|
373
|
+
*/
|
|
374
|
+
enforce_thumbnail?: boolean;
|
|
375
|
+
/**
|
|
376
|
+
* When set to true, imgproxy will return attachment in the Content-Disposition header.
|
|
377
|
+
*/
|
|
378
|
+
return_attachment?: boolean;
|
|
379
|
+
/**
|
|
380
|
+
* Redefines quality of the resulting image, as a percentage.
|
|
381
|
+
* Default: 0
|
|
382
|
+
*/
|
|
383
|
+
quality?: number;
|
|
384
|
+
/**
|
|
385
|
+
* Adds or redefines IMGPROXY_FORMAT_QUALITY values.
|
|
386
|
+
*/
|
|
387
|
+
format_quality?: Record<string, number>;
|
|
388
|
+
/**
|
|
389
|
+
* Redefines autoquality settings.
|
|
390
|
+
*/
|
|
391
|
+
autoquality?: AutoqualityOptions;
|
|
392
|
+
/**
|
|
393
|
+
* When set, imgproxy automatically degrades the quality of the image until the image size is under the specified amount of bytes.
|
|
394
|
+
* Default: 0
|
|
395
|
+
*/
|
|
396
|
+
max_bytes?: number;
|
|
397
|
+
/**
|
|
398
|
+
* Allows redefining JPEG saving options.
|
|
399
|
+
*/
|
|
400
|
+
jpeg_options?: JpegOptions;
|
|
401
|
+
/**
|
|
402
|
+
* Allows redefining PNG saving options.
|
|
403
|
+
*/
|
|
404
|
+
png_options?: PngOptions;
|
|
405
|
+
/**
|
|
406
|
+
* Specifies the resulting image format.
|
|
407
|
+
* Default: jpg
|
|
408
|
+
*/
|
|
409
|
+
format?: string;
|
|
410
|
+
/**
|
|
411
|
+
* When a source image supports pagination or animation, this option allows specifying the page to use it on.
|
|
412
|
+
* Default: 0
|
|
413
|
+
*/
|
|
414
|
+
page?: number;
|
|
415
|
+
/**
|
|
416
|
+
* Allows redefining IMGPROXY_VIDEO_THUMBNAIL_SECOND config.
|
|
417
|
+
*/
|
|
418
|
+
video_thumbnail_second?: number;
|
|
419
|
+
/**
|
|
420
|
+
* You can use a custom fallback image by specifying its URL.
|
|
421
|
+
* Default: blank
|
|
422
|
+
*/
|
|
423
|
+
fallback_image_url?: string;
|
|
424
|
+
/**
|
|
425
|
+
* When set, imgproxy will skip the processing of the listed formats.
|
|
426
|
+
* Default: empty
|
|
427
|
+
*/
|
|
428
|
+
skip_processing?: string[];
|
|
429
|
+
/**
|
|
430
|
+
* Cache buster doesn't affect image processing but its changing allows for bypassing the CDN, proxy server and browser cache.
|
|
431
|
+
* Default: empty
|
|
432
|
+
*/
|
|
433
|
+
cachebuster?: string;
|
|
434
|
+
/**
|
|
435
|
+
* When set, imgproxy will check the provided unix timestamp and return 404 when expired.
|
|
436
|
+
* Default: empty
|
|
437
|
+
*/
|
|
438
|
+
expires?: number;
|
|
439
|
+
/**
|
|
440
|
+
* Defines a filename for the Content-Disposition header.
|
|
441
|
+
* Default: empty
|
|
442
|
+
*/
|
|
443
|
+
filename?: string;
|
|
444
|
+
/**
|
|
445
|
+
* Defines a list of presets to be used by imgproxy.
|
|
446
|
+
* Default: empty
|
|
447
|
+
*/
|
|
448
|
+
preset?: string[];
|
|
449
|
+
}
|
|
450
|
+
type ImgproxyOptions = BaseLoaderOptions<ImgproxyTransforms>;
|
|
451
|
+
type ImgproxyGlobalOptions = BaseGlobalLoaderOptions<ImgproxyTransforms>;
|
|
452
|
+
//#endregion
|
|
453
|
+
//#region src/react/loaders/imgproxy/use-imgproxy-loader.d.ts
|
|
454
|
+
declare function useImgproxyLoader(options?: ImgproxyOptions): (imageOptions: ImageLoaderOptions) => string;
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region src/react/loaders/imgproxy/imgproxy-context.d.ts
|
|
457
|
+
declare function useImgproxyContext(): ImgproxyGlobalOptions;
|
|
91
458
|
declare function ImgproxyLoaderProvider({
|
|
92
459
|
children,
|
|
93
460
|
...props
|
|
94
461
|
}: {
|
|
95
462
|
children: React.ReactNode;
|
|
96
|
-
} & Partial<
|
|
97
|
-
|
|
463
|
+
} & Partial<ImgproxyOptions>): react_jsx_runtime0.JSX.Element;
|
|
464
|
+
//#endregion
|
|
465
|
+
//#region src/react/loaders/imgproxy/use-imgproxy-placeholder.d.ts
|
|
466
|
+
declare function useImgproxyPlaceholder(options?: ImgproxyOptions): (imageOptions: ImageLoaderOptions) => string;
|
|
98
467
|
//#endregion
|
|
99
468
|
//#region src/react/loaders/cloudflare-loader.d.ts
|
|
100
469
|
interface CloudflareLoaderOptions {
|
|
@@ -132,4 +501,4 @@ declare function CloudinaryLoaderProvider({
|
|
|
132
501
|
} & Partial<CloudinaryLoaderOptions>): react_jsx_runtime0.JSX.Element;
|
|
133
502
|
declare function useCloudinaryLoader(options?: Partial<CloudinaryLoaderOptions>): ImageLoader;
|
|
134
503
|
//#endregion
|
|
135
|
-
export { type CloudflareLoaderOptions, CloudflareLoaderProvider, type CloudinaryLoaderOptions, CloudinaryLoaderProvider, Image, type ImageLoader, type ImageLoaderOptions, type ImageProps, ImageProvider, type ImageSrcType, type
|
|
504
|
+
export { type CloudflareLoaderOptions, CloudflareLoaderProvider, type CloudinaryLoaderOptions, CloudinaryLoaderProvider, Image, type ImageLoader, type ImageLoaderOptions, type ImageProps, ImageProvider, type ImageSrcType, type ImgproxyGlobalOptions, ImgproxyLoaderProvider, type ImgproxyOptions, type ImgproxyTransforms, useCloudflareContext, useCloudflareLoader, useCloudinaryContext, useCloudinaryLoader, useImageContext, useImgLoaded, useImgproxyContext, useImgproxyLoader, useImgproxyPlaceholder };
|
package/dist/react.js
CHANGED
|
@@ -95,7 +95,7 @@ function resolveOptions(prop, defaultOptions) {
|
|
|
95
95
|
resolved.loading = resolveLoading(resolved);
|
|
96
96
|
resolved.srcSet = resolveSrcSet(resolved);
|
|
97
97
|
resolved.sizes = resolveSizes(resolved, resolved.srcSet, resolved.loading);
|
|
98
|
-
resolved.
|
|
98
|
+
resolved.placeholder = resolvePlaceholder(resolved, resolved.src);
|
|
99
99
|
resolved.height = resolveHeight(resolved);
|
|
100
100
|
resolved.width = resolveWidth(resolved);
|
|
101
101
|
resolved.src = resolveSrc(resolved);
|
|
@@ -117,8 +117,7 @@ function resolveSrcSet(prop) {
|
|
|
117
117
|
for (const breakpoint of prop.breakpoints) if (prop.loader) entries.push(`${prop.loader({
|
|
118
118
|
src: baseSrc,
|
|
119
119
|
width: breakpoint,
|
|
120
|
-
height: prop.height
|
|
121
|
-
isPlaceholder: false
|
|
120
|
+
height: prop.height
|
|
122
121
|
})} ${breakpoint}w`);
|
|
123
122
|
if (entries.length === 0) return;
|
|
124
123
|
return entries.join(", ");
|
|
@@ -155,15 +154,15 @@ function resolveHeight(prop) {
|
|
|
155
154
|
if (prop.height) return prop.height;
|
|
156
155
|
if (typeof prop.src === "object") return prop.src.height;
|
|
157
156
|
}
|
|
158
|
-
function
|
|
159
|
-
if (prop.
|
|
160
|
-
if (typeof prop.
|
|
161
|
-
if (prop.
|
|
162
|
-
|
|
163
|
-
src: prop.src,
|
|
157
|
+
function resolvePlaceholder(prop, src) {
|
|
158
|
+
if (!prop.placeholder) return null;
|
|
159
|
+
if (typeof prop.placeholder === "string") return prop.placeholder;
|
|
160
|
+
if (typeof prop.placeholder === "function") return prop.placeholder({
|
|
161
|
+
src,
|
|
164
162
|
width: prop.width,
|
|
165
163
|
height: prop.height
|
|
166
164
|
});
|
|
165
|
+
return null;
|
|
167
166
|
}
|
|
168
167
|
|
|
169
168
|
//#endregion
|
|
@@ -242,11 +241,11 @@ function ImageProvider({ children, ...props }) {
|
|
|
242
241
|
//#region src/react/image.tsx
|
|
243
242
|
const preload = "preload" in ReactDOM && typeof ReactDOM.preload === "function" ? ReactDOM.preload : null;
|
|
244
243
|
function getPlaceholderStyles(props) {
|
|
245
|
-
if (!props.
|
|
244
|
+
if (!props.placeholder) return {};
|
|
246
245
|
return {
|
|
247
246
|
backgroundPosition: "50% 50%",
|
|
248
247
|
backgroundRepeat: "no-repeat",
|
|
249
|
-
backgroundImage: `url(${props.
|
|
248
|
+
backgroundImage: `url(${props.placeholder})`,
|
|
250
249
|
backgroundSize: "cover"
|
|
251
250
|
};
|
|
252
251
|
}
|
|
@@ -290,32 +289,216 @@ function Image(props) {
|
|
|
290
289
|
}
|
|
291
290
|
|
|
292
291
|
//#endregion
|
|
293
|
-
//#region src/react/loaders/
|
|
294
|
-
function
|
|
295
|
-
return
|
|
296
|
-
}
|
|
297
|
-
function
|
|
298
|
-
|
|
292
|
+
//#region src/react/loaders/loader-utils.ts
|
|
293
|
+
function resolveOption(key, value, separator) {
|
|
294
|
+
return `${key}${separator}${value}`;
|
|
295
|
+
}
|
|
296
|
+
function resolveDeprecatedParams(source, separator) {
|
|
297
|
+
const params = [];
|
|
298
|
+
for (const key of Object.keys(params)) {
|
|
299
|
+
const value = source[key];
|
|
300
|
+
if (value !== void 0) params.push(resolveOption(key, value, separator));
|
|
301
|
+
}
|
|
302
|
+
return params;
|
|
299
303
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
304
|
+
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region src/react/loaders/imgproxy/create-imgproxy-url.ts
|
|
307
|
+
const stringifyOptions = (opCode, values) => {
|
|
308
|
+
return [opCode, ...values.map((v) => v == null ? "" : encodeURIComponent(v))].join(":").replace(/:+$/, "");
|
|
309
|
+
};
|
|
310
|
+
const resolveObjectParam = (key, source) => {
|
|
311
|
+
if (source === void 0) return;
|
|
312
|
+
if (key === "size") {
|
|
313
|
+
const tSource = source;
|
|
314
|
+
if (!tSource) return;
|
|
315
|
+
return stringifyOptions(key, [
|
|
316
|
+
tSource.width,
|
|
317
|
+
tSource.height,
|
|
318
|
+
tSource.enlarge,
|
|
319
|
+
tSource.extend
|
|
320
|
+
]);
|
|
321
|
+
}
|
|
322
|
+
if (key === "resize") {
|
|
323
|
+
const tSource = source;
|
|
324
|
+
if (!tSource) return;
|
|
325
|
+
return stringifyOptions(key, [
|
|
326
|
+
tSource.resizing_type,
|
|
327
|
+
tSource.width,
|
|
328
|
+
tSource.height,
|
|
329
|
+
tSource.enlarge,
|
|
330
|
+
tSource.extend
|
|
331
|
+
]);
|
|
332
|
+
}
|
|
333
|
+
if (key === "extend") {
|
|
334
|
+
const tSource = source;
|
|
335
|
+
if (!tSource) return;
|
|
336
|
+
if (typeof tSource === "boolean") return stringifyOptions(key, [tSource]);
|
|
337
|
+
return stringifyOptions(key, [tSource.extend, tSource.gravity]);
|
|
338
|
+
}
|
|
339
|
+
if (key === "gravity") {
|
|
340
|
+
const tSource = source;
|
|
341
|
+
if (!tSource) return;
|
|
342
|
+
return stringifyOptions(key, [
|
|
343
|
+
tSource.type,
|
|
344
|
+
tSource.x_offset,
|
|
345
|
+
tSource.y_offset
|
|
346
|
+
]);
|
|
347
|
+
}
|
|
348
|
+
if (key === "crop") {
|
|
349
|
+
const tSource = source;
|
|
350
|
+
if (!tSource) return;
|
|
351
|
+
return stringifyOptions(key, [
|
|
352
|
+
tSource.width,
|
|
353
|
+
tSource.height,
|
|
354
|
+
tSource.gravity
|
|
355
|
+
]);
|
|
356
|
+
}
|
|
357
|
+
if (key === "trim") {
|
|
358
|
+
const tSource = source;
|
|
359
|
+
if (!tSource) return;
|
|
360
|
+
return stringifyOptions(key, [
|
|
361
|
+
tSource.threshold,
|
|
362
|
+
tSource.color,
|
|
363
|
+
tSource.equal_hor,
|
|
364
|
+
tSource.equal_ver
|
|
365
|
+
]);
|
|
366
|
+
}
|
|
367
|
+
if (key === "padding") {
|
|
368
|
+
const tSource = source;
|
|
369
|
+
if (!tSource) return;
|
|
370
|
+
return stringifyOptions(key, [
|
|
371
|
+
tSource.top,
|
|
372
|
+
tSource.right,
|
|
373
|
+
tSource.bottom,
|
|
374
|
+
tSource.left
|
|
375
|
+
]);
|
|
376
|
+
}
|
|
377
|
+
if (key === "background") {
|
|
378
|
+
const tSource = source;
|
|
379
|
+
if (!tSource) return;
|
|
380
|
+
if (typeof tSource === "string") return stringifyOptions(key, [tSource]);
|
|
381
|
+
return stringifyOptions(key, [
|
|
382
|
+
tSource.r,
|
|
383
|
+
tSource.g,
|
|
384
|
+
tSource.b
|
|
385
|
+
]);
|
|
386
|
+
}
|
|
387
|
+
if (key === "adjust") {
|
|
388
|
+
const tSource = source;
|
|
389
|
+
if (!tSource) return;
|
|
390
|
+
return stringifyOptions(key, [
|
|
391
|
+
tSource.brightness,
|
|
392
|
+
tSource.contrast,
|
|
393
|
+
tSource.saturation
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
if (key === "blur_detections") {
|
|
397
|
+
const tSource = source;
|
|
398
|
+
if (!tSource) return;
|
|
399
|
+
return stringifyOptions(key, [tSource.sigma, ...tSource.class_names]);
|
|
400
|
+
}
|
|
401
|
+
if (key === "draw_detections") {
|
|
402
|
+
const tSource = source;
|
|
403
|
+
if (!tSource) return;
|
|
404
|
+
return stringifyOptions(key, [tSource.draw, ...tSource.class_names]);
|
|
405
|
+
}
|
|
406
|
+
if (key === "watermark") {
|
|
407
|
+
const tSource = source;
|
|
408
|
+
if (!tSource) return;
|
|
409
|
+
return stringifyOptions(key, [
|
|
410
|
+
tSource.opacity,
|
|
411
|
+
tSource.position,
|
|
412
|
+
tSource.x_offset,
|
|
413
|
+
tSource.y_offset,
|
|
414
|
+
tSource.scale
|
|
415
|
+
]);
|
|
416
|
+
}
|
|
417
|
+
if (key === "watermark_size") {
|
|
418
|
+
const tSource = source;
|
|
419
|
+
if (!tSource) return;
|
|
420
|
+
return stringifyOptions(key, [tSource.width, tSource.height]);
|
|
421
|
+
}
|
|
422
|
+
if (key === "unsharpening") {
|
|
423
|
+
const tSource = source;
|
|
424
|
+
if (!tSource) return;
|
|
425
|
+
return stringifyOptions(key, [
|
|
426
|
+
tSource.mode,
|
|
427
|
+
tSource.weight,
|
|
428
|
+
tSource.dividor
|
|
429
|
+
]);
|
|
430
|
+
}
|
|
431
|
+
if (key === "autoquality") {
|
|
432
|
+
const tSource = source;
|
|
433
|
+
if (!tSource) return;
|
|
434
|
+
return stringifyOptions(key, [
|
|
435
|
+
tSource.method,
|
|
436
|
+
tSource.target,
|
|
437
|
+
tSource.min_quality,
|
|
438
|
+
tSource.max_quality,
|
|
439
|
+
tSource.allowed_error
|
|
440
|
+
]);
|
|
441
|
+
}
|
|
442
|
+
if (key === "jpeg_options") {
|
|
443
|
+
const tSource = source;
|
|
444
|
+
if (!tSource) return;
|
|
445
|
+
return stringifyOptions(key, [
|
|
446
|
+
tSource.progressive,
|
|
447
|
+
tSource.no_subsample,
|
|
448
|
+
tSource.trellis_quant,
|
|
449
|
+
tSource.overshoot_deringing,
|
|
450
|
+
tSource.optimize_scans,
|
|
451
|
+
tSource.quant_table
|
|
452
|
+
]);
|
|
453
|
+
}
|
|
454
|
+
if (key === "png_options") {
|
|
455
|
+
const tSource = source;
|
|
456
|
+
if (!tSource) return;
|
|
457
|
+
return stringifyOptions(key, [
|
|
458
|
+
tSource.interlaced,
|
|
459
|
+
tSource.quantize,
|
|
460
|
+
tSource.quantization_colors
|
|
461
|
+
]);
|
|
462
|
+
}
|
|
463
|
+
if (key === "zoom") {
|
|
464
|
+
const tSource = source;
|
|
465
|
+
if (!tSource) return;
|
|
466
|
+
if (typeof tSource === "number") return stringifyOptions(key, [tSource]);
|
|
467
|
+
return stringifyOptions(key, [tSource.x, tSource.y]);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
const resolveTransforms = (transforms) => {
|
|
471
|
+
if (!transforms) return "";
|
|
472
|
+
const params = [];
|
|
473
|
+
for (const key of Object.keys(transforms)) {
|
|
474
|
+
const value = transforms[key];
|
|
475
|
+
const keyCast = key;
|
|
476
|
+
if (value === void 0) continue;
|
|
477
|
+
if (typeof value === "object") {
|
|
478
|
+
const objectParams = resolveObjectParam(keyCast, value);
|
|
479
|
+
if (objectParams) params.push(objectParams);
|
|
480
|
+
} else params.push(stringifyOptions(key, [value]));
|
|
481
|
+
}
|
|
482
|
+
return params;
|
|
483
|
+
};
|
|
484
|
+
function createImgproxyUrl(path, transforms, imageOptions) {
|
|
485
|
+
if (!path) throw new Error("Path must be provided");
|
|
486
|
+
const params = [];
|
|
487
|
+
if (imageOptions.width) params.push(stringifyOptions("width", [imageOptions.width]));
|
|
488
|
+
if (imageOptions.height) params.push(stringifyOptions("height", [imageOptions.height]));
|
|
489
|
+
params.push(...resolveTransforms(transforms));
|
|
490
|
+
if (params) params.push(...resolveDeprecatedParams(params, ":"));
|
|
491
|
+
return `${path}/${params.join("/")}/plain/${imageOptions.src}`;
|
|
310
492
|
}
|
|
311
493
|
|
|
312
494
|
//#endregion
|
|
313
|
-
//#region src/react/loaders/imgproxy-
|
|
495
|
+
//#region src/react/loaders/imgproxy/imgproxy-context.tsx
|
|
314
496
|
const ImgproxyContext = createContext({
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
497
|
+
transforms: { format: "webp" },
|
|
498
|
+
placeholderTransforms: {
|
|
499
|
+
quality: 10,
|
|
500
|
+
format: "webp"
|
|
501
|
+
}
|
|
319
502
|
});
|
|
320
503
|
function useImgproxyContext() {
|
|
321
504
|
return useContext(ImgproxyContext);
|
|
@@ -330,31 +513,49 @@ function ImgproxyLoaderProvider({ children, ...props }) {
|
|
|
330
513
|
children
|
|
331
514
|
});
|
|
332
515
|
}
|
|
516
|
+
|
|
517
|
+
//#endregion
|
|
518
|
+
//#region src/react/loaders/imgproxy/use-imgproxy-loader.tsx
|
|
333
519
|
function useImgproxyLoader(options) {
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
520
|
+
const context = useImgproxyContext();
|
|
521
|
+
const path = options?.path || context.path;
|
|
522
|
+
const transforms = {
|
|
523
|
+
...context.transforms,
|
|
524
|
+
...options?.transforms
|
|
337
525
|
};
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
parts.push(...placeholderParams);
|
|
350
|
-
}
|
|
351
|
-
} else if (resolvedOptions.params) {
|
|
352
|
-
const params = normalizeLoaderParams(resolvedOptions.params, ":");
|
|
353
|
-
parts.push(...params);
|
|
354
|
-
}
|
|
355
|
-
const processingOptions = parts.join(paramsSeparator);
|
|
356
|
-
return `${resolvedOptions.path}/${processingOptions}/plain/${imageOptions.src}`;
|
|
526
|
+
return (imageOptions) => createImgproxyUrl(path, transforms, imageOptions);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
//#endregion
|
|
530
|
+
//#region src/react/loaders/imgproxy/use-imgproxy-placeholder.tsx
|
|
531
|
+
function useImgproxyPlaceholder(options) {
|
|
532
|
+
const context = useImgproxyContext();
|
|
533
|
+
const path = options?.path || context.path;
|
|
534
|
+
const transforms = {
|
|
535
|
+
...context.placeholderTransforms,
|
|
536
|
+
...options?.transforms
|
|
357
537
|
};
|
|
538
|
+
return (imageOptions) => createImgproxyUrl(path, transforms, imageOptions);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
//#endregion
|
|
542
|
+
//#region src/react/loaders/image-loader-utils.ts
|
|
543
|
+
function normalizeLoaderParams(params, separator) {
|
|
544
|
+
return Object.entries(params).map(([key, value]) => `${key}${separator}${value}`);
|
|
545
|
+
}
|
|
546
|
+
function isAbsoluteUrl(src) {
|
|
547
|
+
return /^https?:\/\//.test(src);
|
|
548
|
+
}
|
|
549
|
+
function assertPath(path) {
|
|
550
|
+
assert(() => !path?.trim(), import.meta.env.DEV && `Path is required`);
|
|
551
|
+
assert(() => {
|
|
552
|
+
try {
|
|
553
|
+
new URL(path);
|
|
554
|
+
return !isAbsoluteUrl(path);
|
|
555
|
+
} catch {
|
|
556
|
+
return true;
|
|
557
|
+
}
|
|
558
|
+
}, import.meta.env.DEV && `Path is invalid url: ${path}`);
|
|
358
559
|
}
|
|
359
560
|
|
|
360
561
|
//#endregion
|
|
@@ -457,4 +658,4 @@ function useCloudinaryLoader(options) {
|
|
|
457
658
|
}
|
|
458
659
|
|
|
459
660
|
//#endregion
|
|
460
|
-
export { CloudflareLoaderProvider, CloudinaryLoaderProvider, Image, ImageProvider, ImgproxyLoaderProvider, useCloudflareContext, useCloudflareLoader, useCloudinaryContext, useCloudinaryLoader, useImageContext, useImgLoaded, useImgproxyContext, useImgproxyLoader };
|
|
661
|
+
export { CloudflareLoaderProvider, CloudinaryLoaderProvider, Image, ImageProvider, ImgproxyLoaderProvider, useCloudflareContext, useCloudflareLoader, useCloudinaryContext, useCloudinaryLoader, useImageContext, useImgLoaded, useImgproxyContext, useImgproxyLoader, useImgproxyPlaceholder };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lonik/oh-image",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.1.1",
|
|
5
5
|
"description": "A React component library for optimized image handling.",
|
|
6
6
|
"author": "Luka Onikadze <lukonik@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"play": "vite",
|
|
41
41
|
"play:build": "vite build",
|
|
42
42
|
"play:preview": "vite preview",
|
|
43
|
+
"play:host": "vite --host",
|
|
43
44
|
"test": "vitest",
|
|
44
45
|
"coverage": "vitest --coverage",
|
|
45
46
|
"typecheck": "tsc --noEmit",
|
|
@@ -54,12 +55,15 @@
|
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@commitlint/config-conventional": "^20.4.1",
|
|
56
57
|
"@eslint/js": "^9.39.2",
|
|
58
|
+
"@tanstack/react-router": "^1.160.0",
|
|
59
|
+
"@tanstack/router-plugin": "^1.160.0",
|
|
57
60
|
"@testing-library/jest-dom": "^6.9.1",
|
|
58
61
|
"@testing-library/react": "^16.3.2",
|
|
59
62
|
"@tsconfig/strictest": "^2.0.8",
|
|
60
63
|
"@types/node": "^25.0.3",
|
|
61
64
|
"@types/react": "^18",
|
|
62
65
|
"@types/react-dom": "^18",
|
|
66
|
+
"@types/supertest": "^6.0.3",
|
|
63
67
|
"@vitejs/plugin-react": "^5.1.2",
|
|
64
68
|
"@vitest/coverage-v8": "4.0.18",
|
|
65
69
|
"bumpp": "^10.3.2",
|
|
@@ -70,14 +74,16 @@
|
|
|
70
74
|
"eslint-plugin-react-refresh": "^0.5.0",
|
|
71
75
|
"globals": "^17.3.0",
|
|
72
76
|
"happy-dom": "^20.6.0",
|
|
77
|
+
"memfs": "^4.56.10",
|
|
78
|
+
"supertest": "^7.2.2",
|
|
73
79
|
"tsdown": "^0.18.1",
|
|
74
80
|
"typescript": "^5.9.3",
|
|
75
81
|
"typescript-eslint": "^8.54.0",
|
|
76
82
|
"vite": "^7.3.0",
|
|
77
83
|
"vitest": "^4.0.16",
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
84
|
+
"tailwindcss": "^4.1.18",
|
|
85
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
86
|
+
"json-edit-react": "^1.29.0"
|
|
81
87
|
},
|
|
82
88
|
"dependencies": {
|
|
83
89
|
"p-limit": "^7.3.0",
|