@azerion/bunosaurus-plugin-ideal-image 0.0.0-stage → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +6 -2
  2. package/lib/index.d.ts +10 -0
  3. package/lib/index.js +75 -0
  4. package/lib/theme/IdealImage/index.d.ts +9 -0
  5. package/lib/theme/IdealImage/index.js +96 -0
  6. package/lib/theme/IdealImageLegacy/LICENSE +20 -0
  7. package/lib/theme/IdealImageLegacy/README.md +13 -0
  8. package/lib/theme/IdealImageLegacy/components/Icon/Download.d.ts +2 -0
  9. package/lib/theme/IdealImageLegacy/components/Icon/Download.js +14 -0
  10. package/lib/theme/IdealImageLegacy/components/Icon/Loading.d.ts +2 -0
  11. package/lib/theme/IdealImageLegacy/components/Icon/Loading.js +14 -0
  12. package/lib/theme/IdealImageLegacy/components/Icon/Offline.d.ts +2 -0
  13. package/lib/theme/IdealImageLegacy/components/Icon/Offline.js +14 -0
  14. package/lib/theme/IdealImageLegacy/components/Icon/Warning.d.ts +2 -0
  15. package/lib/theme/IdealImageLegacy/components/Icon/Warning.js +14 -0
  16. package/lib/theme/IdealImageLegacy/components/Icon/index.d.ts +7 -0
  17. package/lib/theme/IdealImageLegacy/components/Icon/index.js +24 -0
  18. package/lib/theme/IdealImageLegacy/components/IdealImage/index.d.ts +46 -0
  19. package/lib/theme/IdealImageLegacy/components/IdealImage/index.js +352 -0
  20. package/lib/theme/IdealImageLegacy/components/IdealImage/waypoint.d.ts +10 -0
  21. package/lib/theme/IdealImageLegacy/components/IdealImage/waypoint.js +188 -0
  22. package/lib/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.d.ts +32 -0
  23. package/lib/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.js +11 -0
  24. package/lib/theme/IdealImageLegacy/components/Media/index.d.ts +20 -0
  25. package/lib/theme/IdealImageLegacy/components/Media/index.js +169 -0
  26. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/README.md +89 -0
  27. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/index.d.ts +32 -0
  28. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/index.js +11 -0
  29. package/lib/theme/IdealImageLegacy/components/composeStyle.d.ts +23 -0
  30. package/lib/theme/IdealImageLegacy/components/composeStyle.js +37 -0
  31. package/lib/theme/IdealImageLegacy/components/constants.d.ts +14 -0
  32. package/lib/theme/IdealImageLegacy/components/constants.js +24 -0
  33. package/lib/theme/IdealImageLegacy/components/helpers.d.ts +22 -0
  34. package/lib/theme/IdealImageLegacy/components/helpers.js +141 -0
  35. package/lib/theme/IdealImageLegacy/components/icons.d.ts +14 -0
  36. package/lib/theme/IdealImageLegacy/components/icons.js +16 -0
  37. package/lib/theme/IdealImageLegacy/components/loaders.d.ts +11 -0
  38. package/lib/theme/IdealImageLegacy/components/loaders.js +112 -0
  39. package/lib/theme/IdealImageLegacy/components/theme.d.ts +26 -0
  40. package/lib/theme/IdealImageLegacy/components/theme.js +26 -0
  41. package/lib/theme/IdealImageLegacy/components/theme.module.css +35 -0
  42. package/lib/theme/IdealImageLegacy/components/unfetch.d.ts +8 -0
  43. package/lib/theme/IdealImageLegacy/components/unfetch.js +74 -0
  44. package/lib/theme/IdealImageLegacy/index.d.ts +2 -0
  45. package/lib/theme/IdealImageLegacy/index.js +2 -0
  46. package/package.json +46 -4
  47. package/src/index.ts +94 -0
  48. package/src/plugin-ideal-image.d.ts +199 -0
  49. package/src/theme/IdealImage/index.tsx +108 -0
  50. package/src/theme/IdealImageLegacy/LICENSE +20 -0
  51. package/src/theme/IdealImageLegacy/README.md +13 -0
  52. package/src/theme/IdealImageLegacy/components/Icon/Download.js +14 -0
  53. package/src/theme/IdealImageLegacy/components/Icon/Loading.js +14 -0
  54. package/src/theme/IdealImageLegacy/components/Icon/Offline.js +14 -0
  55. package/src/theme/IdealImageLegacy/components/Icon/Warning.js +14 -0
  56. package/src/theme/IdealImageLegacy/components/Icon/index.js +24 -0
  57. package/src/theme/IdealImageLegacy/components/IdealImage/index.js +352 -0
  58. package/src/theme/IdealImageLegacy/components/IdealImage/waypoint.tsx +254 -0
  59. package/src/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.js +11 -0
  60. package/src/theme/IdealImageLegacy/components/Media/index.js +169 -0
  61. package/src/theme/IdealImageLegacy/components/MediaWithDefaults/README.md +89 -0
  62. package/src/theme/IdealImageLegacy/components/MediaWithDefaults/index.js +11 -0
  63. package/src/theme/IdealImageLegacy/components/composeStyle.js +37 -0
  64. package/src/theme/IdealImageLegacy/components/constants.js +24 -0
  65. package/src/theme/IdealImageLegacy/components/helpers.js +141 -0
  66. package/src/theme/IdealImageLegacy/components/icons.js +16 -0
  67. package/src/theme/IdealImageLegacy/components/loaders.js +112 -0
  68. package/src/theme/IdealImageLegacy/components/theme.js +26 -0
  69. package/src/theme/IdealImageLegacy/components/theme.module.css +35 -0
  70. package/src/theme/IdealImageLegacy/components/unfetch.js +74 -0
  71. package/src/theme/IdealImageLegacy/index.tsx +3 -0
@@ -0,0 +1,112 @@
1
+ // There is an issue with cancelable interface
2
+ // It is not obvious that
3
+ // `image(src)` has `cancel` function
4
+ // but `image(src).then()` doesn't
5
+
6
+ import {unfetch, UnfetchAbortController} from './unfetch';
7
+
8
+ /**
9
+ * returns new "promise" with cancel function combined
10
+ *
11
+ * @param {Promise} p1 - first "promise" with cancel
12
+ * @param {Promise} p2 - second "promise" with cancel
13
+ * @returns {Promise} - new "promise" with cancel
14
+ */
15
+ export const combineCancel = (p1, p2) => {
16
+ if (!p2) return p1;
17
+ const result = p1.then(
18
+ (x) => x,
19
+ (x) => x,
20
+ );
21
+ result.cancel = () => {
22
+ p1.cancel();
23
+ p2.cancel();
24
+ };
25
+ return result;
26
+ };
27
+
28
+ export const timeout = (threshold) => {
29
+ let timerId;
30
+ const result = new Promise((resolve) => {
31
+ timerId = setTimeout(resolve, threshold);
32
+ });
33
+ result.cancel = () => {
34
+ // there is a bug with cancel somewhere in the code
35
+ // if (!timerId) throw new Error('Already canceled')
36
+ clearTimeout(timerId);
37
+ timerId = undefined;
38
+ };
39
+ return result;
40
+ };
41
+
42
+ // Caveat: image loader can not cancel download in some browsers
43
+ export const imageLoader = (src) => {
44
+ let img = new Image();
45
+ const result = new Promise((resolve, reject) => {
46
+ img.onload = resolve;
47
+ // eslint-disable-next-line no-multi-assign
48
+ img.onabort = img.onerror = () => reject({});
49
+ img.src = src;
50
+ });
51
+ result.cancel = () => {
52
+ if (!img) throw new Error('Already canceled');
53
+ // eslint-disable-next-line no-multi-assign
54
+ img.onload = img.onabort = img.onerror = undefined;
55
+ img.src = '';
56
+ img = undefined;
57
+ };
58
+ return result;
59
+ };
60
+
61
+ // Caveat: XHR loader can cause errors because of 'Access-Control-Allow-Origin'
62
+ // Caveat: we still need imageLoader to do actual decoding,
63
+ // but if images are uncachable this will lead to two requests
64
+ export const xhrLoader = (url, options) => {
65
+ let controller = new UnfetchAbortController();
66
+ const signal = controller.signal;
67
+ const result = new Promise((resolve, reject) =>
68
+ unfetch(url, {...options, signal}).then((response) => {
69
+ if (response.ok) {
70
+ response
71
+ .blob()
72
+ .then(() => imageLoader(url))
73
+ .then(resolve);
74
+ } else {
75
+ reject({status: response.status});
76
+ }
77
+ }, reject),
78
+ );
79
+ result.cancel = () => {
80
+ if (!controller) throw new Error('Already canceled');
81
+ controller.abort();
82
+ controller = undefined;
83
+ };
84
+ return result;
85
+ };
86
+
87
+ // Caveat: AbortController only supported in Chrome 66+
88
+ // Caveat: we still need imageLoader to do actual decoding,
89
+ // but if images are uncachable this will lead to two requests
90
+ // export const fetchLoader = (url, options) => {
91
+ // let controller = new AbortController()
92
+ // const signal = controller.signal
93
+ // const result = new Promise((resolve, reject) =>
94
+ // fetch(url, {...options, signal}).then(response => {
95
+ // if (response.ok) {
96
+ // options && options.onMeta && options.onMeta(response.headers)
97
+ // response
98
+ // .blob()
99
+ // .then(() => imageLoader(url))
100
+ // .then(resolve)
101
+ // } else {
102
+ // reject({status: response.status})
103
+ // }
104
+ // }, reject),
105
+ // )
106
+ // result.cancel = () => {
107
+ // if (!controller) throw new Error('Already canceled')
108
+ // controller.abort()
109
+ // controller = undefined
110
+ // }
111
+ // return result
112
+ // }
@@ -0,0 +1,26 @@
1
+ declare const _default: {
2
+ placeholder: {
3
+ backgroundSize: string;
4
+ backgroundRepeat: string;
5
+ position: string;
6
+ };
7
+ img: {
8
+ width: string;
9
+ height: string;
10
+ maxWidth: string;
11
+ marginBottom: string;
12
+ };
13
+ icon: {
14
+ position: string;
15
+ top: string;
16
+ left: string;
17
+ transform: string;
18
+ textAlign: string;
19
+ };
20
+ noscript: {
21
+ position: string;
22
+ top: number;
23
+ left: number;
24
+ };
25
+ };
26
+ export default _default;
@@ -0,0 +1,26 @@
1
+ export default {
2
+ placeholder: {
3
+ backgroundSize: 'cover',
4
+ backgroundRepeat: 'no-repeat',
5
+ position: 'relative',
6
+ },
7
+ img: {
8
+ width: '100%',
9
+ height: 'auto',
10
+ maxWidth: '100%',
11
+ /* TODO: fix bug in styles */
12
+ marginBottom: '-4px',
13
+ },
14
+ icon: {
15
+ position: 'absolute',
16
+ top: '50%',
17
+ left: '50%',
18
+ transform: 'translate(-50%, -50%)',
19
+ textAlign: 'center',
20
+ },
21
+ noscript: {
22
+ position: 'absolute',
23
+ top: 0,
24
+ left: 0,
25
+ },
26
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ .placeholder {
9
+ background-size: cover;
10
+ background-repeat: no-repeat;
11
+ position: relative;
12
+ }
13
+
14
+ .img {
15
+ width: 100%;
16
+ height: auto;
17
+ max-width: 100%;
18
+ /* TODO: fix bug in styles */
19
+ margin-bottom: -4px;
20
+ transform: translate3d(0, 0, 0);
21
+ }
22
+
23
+ .icon {
24
+ position: absolute;
25
+ top: 50%;
26
+ left: 50%;
27
+ transform: translate(-50%, -50%);
28
+ text-align: center;
29
+ }
30
+
31
+ .noscript {
32
+ position: absolute;
33
+ top: 0;
34
+ left: 0;
35
+ }
@@ -0,0 +1,8 @@
1
+ export declare class UnfetchAbortController {
2
+ signal: {
3
+ onabort: () => void;
4
+ };
5
+ abort: () => void;
6
+ constructor();
7
+ }
8
+ export declare const unfetch: (url: any, options: any) => Promise<any>;
@@ -0,0 +1,74 @@
1
+ export class UnfetchAbortController {
2
+ constructor() {
3
+ this.signal = {onabort: () => {}};
4
+ this.abort = () => this.signal.onabort();
5
+ }
6
+ }
7
+
8
+ // modified version of https://github.com/developit/unfetch
9
+ // - ponyfill instead of polyfill
10
+ // - add support for AbortController
11
+ export const unfetch = (url, options) => {
12
+ options = options || {};
13
+ return new Promise((resolve, reject) => {
14
+ const request = new XMLHttpRequest();
15
+
16
+ request.open(options.method || 'get', url, true);
17
+
18
+ // eslint-disable-next-line guard-for-in
19
+ for (const i in options.headers) {
20
+ request.setRequestHeader(i, options.headers[i]);
21
+ }
22
+
23
+ request.withCredentials = options.credentials === 'include';
24
+
25
+ request.onload = () => {
26
+ resolve(response());
27
+ };
28
+
29
+ request.onerror = reject;
30
+
31
+ if (options.signal)
32
+ options.signal.onabort = () => {
33
+ // eslint-disable-next-line no-multi-assign
34
+ request.onerror = request.onload = undefined;
35
+ request.abort();
36
+ };
37
+
38
+ request.send(options.body);
39
+
40
+ function response() {
41
+ const keys = [];
42
+ const all = [];
43
+ const headers = {};
44
+ let header;
45
+
46
+ request
47
+ .getAllResponseHeaders()
48
+ .replace(/^(.*?):\s*?([\s\S]*?)$/gm, (m, key, value) => {
49
+ keys.push((key = key.toLowerCase()));
50
+ all.push([key, value]);
51
+ header = headers[key];
52
+ headers[key] = header ? `${header},${value}` : value;
53
+ });
54
+
55
+ return {
56
+ // eslint-disable-next-line no-bitwise
57
+ ok: ((request.status / 100) | 0) === 2, // 200-299
58
+ status: request.status,
59
+ statusText: request.statusText,
60
+ url: request.responseURL,
61
+ clone: response,
62
+ text: () => Promise.resolve(request.responseText),
63
+ json: () => Promise.resolve(request.responseText).then(JSON.parse),
64
+ blob: () => Promise.resolve(new Blob([request.response])),
65
+ headers: {
66
+ keys: () => keys,
67
+ entries: () => all,
68
+ get: (n) => headers[n.toLowerCase()],
69
+ has: (n) => n.toLowerCase() in headers,
70
+ },
71
+ };
72
+ }
73
+ });
74
+ };
@@ -0,0 +1,2 @@
1
+ import IdealImageWithDefaults from './components/IdealImageWithDefaults';
2
+ export default IdealImageWithDefaults;
@@ -0,0 +1,2 @@
1
+ import IdealImageWithDefaults from './components/IdealImageWithDefaults';
2
+ export default IdealImageWithDefaults;
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@azerion/bunosaurus-plugin-ideal-image",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "4.0.0",
4
+ "description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).",
5
+ "main": "lib/index.js",
6
+ "types": "src/plugin-ideal-image.d.ts",
7
+ "scripts": {
8
+ "build": "tsc --build && copy-untyped-files && oxfmt \"lib/theme/**/*.js\"",
9
+ "watch": "run-p -c copy:watch build:watch",
10
+ "build:watch": "tsc --build --watch",
11
+ "copy:watch": "copy-untyped-files --watch"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/azerion/bunosaurus.git",
19
+ "directory": "packages/docusaurus-plugin-ideal-image"
20
+ },
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "@docusaurus/core": "npm:@azerion/bunosaurus-core@4.0.0",
24
+ "@docusaurus/lqip-loader": "npm:@azerion/bunosaurus-lqip-loader@4.0.0",
25
+ "@docusaurus/responsive-loader": "^1.7.1",
26
+ "@docusaurus/theme-translations": "npm:@azerion/bunosaurus-theme-translations@4.0.0",
27
+ "@docusaurus/types": "npm:@azerion/bunosaurus-types@4.0.0",
28
+ "@docusaurus/utils-validation": "npm:@azerion/bunosaurus-utils-validation@4.0.0",
29
+ "sharp": "^0.35.1",
30
+ "tslib": "^2.8.1"
31
+ },
32
+ "devDependencies": {
33
+ "@docusaurus/module-type-aliases": "npm:@azerion/bunosaurus-module-type-aliases@4.0.0"
34
+ },
35
+ "peerDependencies": {
36
+ "jimp": "^1.6.1",
37
+ "react": "^19.3.0",
38
+ "react-dom": "^19.3.0"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "jimp": {
42
+ "optional": true
43
+ }
44
+ },
45
+ "engines": {
46
+ "bun": ">=1.4.1"
47
+ }
48
+ }
package/src/index.ts ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import {Joi} from '@docusaurus/utils-validation';
9
+ import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
10
+ import type {
11
+ LoadContext,
12
+ Plugin,
13
+ OptionValidationContext,
14
+ } from '@docusaurus/types';
15
+ import type {PluginOptions} from '@docusaurus/plugin-ideal-image';
16
+
17
+ export default function pluginIdealImage(
18
+ context: LoadContext,
19
+ options: PluginOptions,
20
+ ): Plugin<void> {
21
+ const {
22
+ i18n: {currentLocale},
23
+ } = context;
24
+
25
+ return {
26
+ name: 'docusaurus-plugin-ideal-image',
27
+
28
+ getThemePath() {
29
+ return '../lib/theme';
30
+ },
31
+
32
+ getTypeScriptThemePath() {
33
+ return '../src/theme';
34
+ },
35
+
36
+ getDefaultCodeTranslationMessages() {
37
+ return readDefaultCodeTranslationMessages({
38
+ locale: currentLocale,
39
+ name: 'plugin-ideal-image',
40
+ });
41
+ },
42
+
43
+ configureWebpack(_config, isServer) {
44
+ const {disableInDev, ...loaderOptions} = options;
45
+ if (disableInDev && process.env.NODE_ENV !== 'production') {
46
+ return {};
47
+ }
48
+
49
+ return {
50
+ mergeStrategy: {
51
+ 'module.rules': 'prepend',
52
+ },
53
+ module: {
54
+ rules: [
55
+ {
56
+ test: /\.(?:png|jpe?g)$/i,
57
+ with: {type: {not: 'text'}},
58
+ // We don't want to use the image loader for non-React source code
59
+ // ie we don't want to use ideal image loader for CSS files...
60
+ // See https://github.com/facebook/docusaurus/issues/10862
61
+ issuer: {
62
+ and: [/\.(?:tsx?|jsx?|mdx?)$/i],
63
+ },
64
+ use: [
65
+ require.resolve('@docusaurus/lqip-loader'),
66
+ {
67
+ loader: require.resolve('@docusaurus/responsive-loader'),
68
+ options: {
69
+ // Don't emit for server-side rendering
70
+ emitFile: !isServer,
71
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
72
+ adapter: require('@docusaurus/responsive-loader/sharp'),
73
+ name: 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]',
74
+ ...loaderOptions,
75
+ },
76
+ },
77
+ ],
78
+ },
79
+ ],
80
+ },
81
+ };
82
+ },
83
+ };
84
+ }
85
+
86
+ export function validateOptions({
87
+ validate,
88
+ options,
89
+ }: OptionValidationContext<PluginOptions, PluginOptions>): PluginOptions {
90
+ const pluginOptionsSchema = Joi.object<PluginOptions>({
91
+ disableInDev: Joi.boolean().default(true),
92
+ }).unknown();
93
+ return validate(pluginOptionsSchema, options);
94
+ }
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /// <reference types="@docusaurus/module-type-aliases" />
9
+
10
+ declare module '@docusaurus/plugin-ideal-image' {
11
+ export type PluginOptions = {
12
+ /**
13
+ * Filename template for output files.
14
+ */
15
+ name?: string;
16
+ /**
17
+ * Specify all widths you want to use; if a specified size exceeds the
18
+ * original image's width, the latter will be used (i.e. images won't be
19
+ * scaled up).
20
+ */
21
+ sizes?: number[];
22
+ /**
23
+ * Specify one width you want to use; if the specified size exceeds the
24
+ * original image's width, the latter will be used (i.e. images won't be
25
+ * scaled up)
26
+ */
27
+ size?: number;
28
+ /**
29
+ * As an alternative to manually specifying `sizes`, you can specify `min`,
30
+ * `max` and `steps`, and the `sizes` will be generated for you.
31
+ */
32
+ min?: number;
33
+ /**
34
+ * @see {@link PluginOptions.min}
35
+ */
36
+ max?: number;
37
+ /**
38
+ * Configure the number of images generated between `min` and `max`
39
+ * (inclusive)
40
+ */
41
+ steps?: number;
42
+ /**
43
+ * JPEG compression quality
44
+ */
45
+ quality?: number;
46
+ /**
47
+ * You can test ideal image behavior in dev mode by setting this to `false`.
48
+ * Tip: use network throttling in your browser to simulate slow networks.
49
+ */
50
+ disableInDev?: boolean;
51
+ };
52
+
53
+ export type Options = Partial<PluginOptions>;
54
+ }
55
+
56
+ declare module '@theme/IdealImage' {
57
+ import type {ComponentProps, ReactNode} from 'react';
58
+
59
+ export type SrcType = {
60
+ width: number;
61
+ path?: string;
62
+ size?: number;
63
+ format?: 'webp' | 'jpeg' | 'png' | 'gif';
64
+ };
65
+
66
+ export type SrcImage = {
67
+ height?: number;
68
+ width?: number;
69
+ preSrc: string;
70
+ src: string;
71
+ images: SrcType[];
72
+ };
73
+
74
+ export interface Props extends ComponentProps<'img'> {
75
+ readonly img: {default: string} | {src: SrcImage; preSrc: string} | string;
76
+ }
77
+ export default function IdealImage(props: Props): ReactNode;
78
+ }
79
+
80
+ declare module '@theme/IdealImageLegacy' {
81
+ /**
82
+ * @see https://github.com/endiliey/react-ideal-image/blob/master/index.d.ts
83
+ * Note: the original type definition is WRONG. getIcon & getMessage receive
84
+ * full state object.
85
+ */
86
+
87
+ import type {
88
+ ComponentProps,
89
+ ComponentType,
90
+ CSSProperties,
91
+ ReactNode,
92
+ } from 'react';
93
+
94
+ export type LoadingState = 'initial' | 'loading' | 'loaded' | 'error';
95
+
96
+ export type State = {
97
+ pickedSrc: {
98
+ size: number;
99
+ };
100
+ loadInfo: 404 | null;
101
+ loadState: LoadingState;
102
+ };
103
+
104
+ export type IconKey =
105
+ | 'load'
106
+ | 'loading'
107
+ | 'loaded'
108
+ | 'error'
109
+ | 'noicon'
110
+ | 'offline';
111
+
112
+ export type SrcType = {
113
+ width: number;
114
+ src?: string;
115
+ size?: number;
116
+ format?: 'webp' | 'jpeg' | 'png' | 'gif';
117
+ };
118
+
119
+ type ThemeKey = 'placeholder' | 'img' | 'icon' | 'noscript';
120
+
121
+ export interface ImageProps extends Omit<
122
+ ComponentProps<'img'>,
123
+ 'srcSet' | 'placeholder'
124
+ > {
125
+ /**
126
+ * This function decides what icon to show based on the current state of the
127
+ * component.
128
+ */
129
+ getIcon?: (state: State) => IconKey;
130
+ /**
131
+ * This function decides what message to show based on the icon (returned
132
+ * from `getIcon` prop) and the current state of the component.
133
+ */
134
+ getMessage?: (icon: IconKey, state: State) => string | null;
135
+ /**
136
+ * This function is called as soon as the component enters the viewport and
137
+ * is used to generate urls based on width and format if `props.srcSet`
138
+ * doesn't provide `src` field.
139
+ */
140
+ getUrl?: (srcType: SrcType) => string;
141
+ /**
142
+ * The Height of the image in px.
143
+ */
144
+ height: number;
145
+ /**
146
+ * This provides a map of the icons. By default, the component uses icons
147
+ * from material design, Implemented as React components with the SVG
148
+ * element. You can customize icons
149
+ */
150
+ icons?: Partial<{[icon in IconKey]: ComponentType}>;
151
+ /**
152
+ * This prop takes one of the 2 options, xhr and image.
153
+ * Read more about it:
154
+ * https://github.com/stereobooster/react-ideal-image/blob/master/introduction.md#cancel-download
155
+ */
156
+ loader?: 'xhr' | 'image';
157
+ /**
158
+ * https://github.com/stereobooster/react-ideal-image/blob/master/introduction.md#lqip
159
+ */
160
+ placeholder: {color: string} | {lqip: string};
161
+ /**
162
+ * This function decides if image should be downloaded automatically. The
163
+ * default function returns false for a 2g network, for a 3g network it
164
+ * decides based on `props.threshold` and for a 4g network it returns true
165
+ * by default.
166
+ */
167
+ shouldAutoDownload?: (options: {
168
+ connection?: 'slow-2g' | '2g' | '3g' | '4g';
169
+ size?: number;
170
+ threshold?: number;
171
+ possiblySlowNetwork?: boolean;
172
+ }) => boolean;
173
+ /**
174
+ * This provides an array of sources of different format and size of the
175
+ * image. Read more about it:
176
+ * https://github.com/stereobooster/react-ideal-image/blob/master/introduction.md#srcset
177
+ */
178
+ srcSet: SrcType[];
179
+ /**
180
+ * This provides a theme to the component. By default, the component uses
181
+ * inline styles, but it is also possible to use CSS modules and override
182
+ * all styles.
183
+ */
184
+ theme?: Partial<{[key in ThemeKey]: string | CSSProperties}>;
185
+ /**
186
+ * Tells how much to wait in milliseconds until consider the download to be
187
+ * slow.
188
+ */
189
+ threshold?: number;
190
+ /**
191
+ * Width of the image in px.
192
+ */
193
+ width: number;
194
+ }
195
+
196
+ export interface Props extends ImageProps {}
197
+
198
+ export default function IdealImageLegacy(props: ImageProps): ReactNode;
199
+ }