@docusaurus/plugin-ideal-image 2.0.0-beta.ff31de0ff → 2.0.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/lib/index.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import { LoadContext, Plugin } from '@docusaurus/types';
8
- import { PluginOptions } from './types';
9
- export default function (_context: LoadContext, options: PluginOptions): Plugin<void>;
7
+ import type { LoadContext, Plugin, OptionValidationContext } from '@docusaurus/types';
8
+ import type { PluginOptions } from '@docusaurus/plugin-ideal-image';
9
+ export default function pluginIdealImage(context: LoadContext, options: PluginOptions): Plugin<void>;
10
+ export declare function validateOptions({ validate, options, }: OptionValidationContext<PluginOptions, PluginOptions>): PluginOptions;
package/lib/index.js CHANGED
@@ -1,15 +1,35 @@
1
1
  "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
2
8
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const path_1 = tslib_1.__importDefault(require("path"));
5
- function default_1(_context, options) {
6
- const isProd = process.env.NODE_ENV === 'production';
9
+ exports.validateOptions = void 0;
10
+ const utils_validation_1 = require("@docusaurus/utils-validation");
11
+ const theme_translations_1 = require("@docusaurus/theme-translations");
12
+ function pluginIdealImage(context, options) {
13
+ const { i18n: { currentLocale }, } = context;
7
14
  return {
8
15
  name: 'docusaurus-plugin-ideal-image',
9
16
  getThemePath() {
10
- return path_1.default.resolve(__dirname, './theme');
17
+ return '../lib/theme';
18
+ },
19
+ getTypeScriptThemePath() {
20
+ return '../src/theme';
21
+ },
22
+ getDefaultCodeTranslationMessages() {
23
+ return (0, theme_translations_1.readDefaultCodeTranslationMessages)({
24
+ locale: currentLocale,
25
+ name: 'plugin-ideal-image',
26
+ });
11
27
  },
12
28
  configureWebpack(_config, isServer) {
29
+ const { disableInDev, ...loaderOptions } = options;
30
+ if (disableInDev && process.env.NODE_ENV !== 'production') {
31
+ return {};
32
+ }
13
33
  return {
14
34
  mergeStrategy: {
15
35
  'module.rules': 'prepend',
@@ -17,19 +37,18 @@ function default_1(_context, options) {
17
37
  module: {
18
38
  rules: [
19
39
  {
20
- test: /\.(png|jpe?g|gif)$/i,
40
+ test: /\.(?:png|jpe?g)$/i,
21
41
  use: [
22
42
  require.resolve('@docusaurus/lqip-loader'),
23
43
  {
24
44
  loader: require.resolve('@docusaurus/responsive-loader'),
25
45
  options: {
46
+ // Don't emit for server-side rendering
26
47
  emitFile: !isServer,
27
- disable: !isProd,
48
+ // eslint-disable-next-line global-require
28
49
  adapter: require('@docusaurus/responsive-loader/sharp'),
29
- name: isProd
30
- ? 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]'
31
- : 'assets/ideal-img/[name].[width].[ext]',
32
- ...options,
50
+ name: 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]',
51
+ ...loaderOptions,
33
52
  },
34
53
  },
35
54
  ],
@@ -40,4 +59,11 @@ function default_1(_context, options) {
40
59
  },
41
60
  };
42
61
  }
43
- exports.default = default_1;
62
+ exports.default = pluginIdealImage;
63
+ function validateOptions({ validate, options, }) {
64
+ const pluginOptionsSchema = utils_validation_1.Joi.object({
65
+ disableInDev: utils_validation_1.Joi.boolean().default(true),
66
+ }).unknown();
67
+ return validate(pluginOptionsSchema, options);
68
+ }
69
+ exports.validateOptions = validateOptions;
@@ -1,8 +1,9 @@
1
- "use strict";
2
1
  /**
3
2
  * Copyright (c) Facebook, Inc. and its affiliates.
4
3
  *
5
4
  * This source code is licensed under the MIT license found in the
6
5
  * LICENSE file in the root directory of this source tree.
7
6
  */
8
- Object.defineProperty(exports, "__esModule", { value: true });
7
+ /// <reference types="react" />
8
+ import type { Props } from '@theme/IdealImage';
9
+ export default function IdealImage(props: Props): JSX.Element;
@@ -0,0 +1,103 @@
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
+ import React from 'react';
8
+ import ReactIdealImage from '@endiliey/react-ideal-image';
9
+ import {translate} from '@docusaurus/Translate';
10
+ // Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/helpers.js#L59-L65
11
+ function bytesToSize(bytes) {
12
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
13
+ if (bytes === 0) {
14
+ return 'n/a';
15
+ }
16
+ const scale = Math.floor(Math.log(bytes) / Math.log(1024));
17
+ if (scale === 0) {
18
+ return `${bytes} ${sizes[scale]}`;
19
+ }
20
+ return `${(bytes / 1024 ** scale).toFixed(1)} ${sizes[scale]}`;
21
+ }
22
+ // Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/IdealImage/index.js#L43-L75
23
+ function getMessage(icon, state) {
24
+ switch (icon) {
25
+ case 'noicon':
26
+ case 'loaded':
27
+ return null;
28
+ case 'loading':
29
+ return translate({
30
+ id: 'theme.IdealImageMessage.loading',
31
+ message: 'Loading...',
32
+ description: 'When the full-scale image is loading',
33
+ });
34
+ case 'load': {
35
+ // We can show `alt` here
36
+ const {pickedSrc} = state;
37
+ const {size} = pickedSrc;
38
+ const sizeMessage = size ? ` (${bytesToSize(size)})` : '';
39
+ return translate(
40
+ {
41
+ id: 'theme.IdealImageMessage.load',
42
+ message: 'Click to load{sizeMessage}',
43
+ description:
44
+ 'To prompt users to load the full image. sizeMessage is a parenthesized size figure.',
45
+ },
46
+ {sizeMessage},
47
+ );
48
+ }
49
+ case 'offline':
50
+ return translate({
51
+ id: 'theme.IdealImageMessage.offline',
52
+ message: 'Your browser is offline. Image not loaded',
53
+ description: 'When the user is viewing an offline document',
54
+ });
55
+ case 'error': {
56
+ const {loadInfo} = state;
57
+ if (loadInfo === 404) {
58
+ return translate({
59
+ id: 'theme.IdealImageMessage.404error',
60
+ message: '404. Image not found',
61
+ description: 'When the image is not found',
62
+ });
63
+ }
64
+ return translate({
65
+ id: 'theme.IdealImageMessage.error',
66
+ message: 'Error. Click to reload',
67
+ description: 'When the image fails to load for unknown error',
68
+ });
69
+ }
70
+ default:
71
+ throw new Error(`Wrong icon: ${icon}`);
72
+ }
73
+ }
74
+ export default function IdealImage(props) {
75
+ const {alt, className, img} = props;
76
+ // In dev env just use regular img with original file
77
+ if (typeof img === 'string' || 'default' in img) {
78
+ return (
79
+ <img
80
+ src={typeof img === 'string' ? img : img.default}
81
+ className={className}
82
+ alt={alt}
83
+ {...props}
84
+ />
85
+ );
86
+ }
87
+ return (
88
+ <ReactIdealImage
89
+ {...props}
90
+ alt={alt}
91
+ className={className}
92
+ height={img.src.height ?? 100}
93
+ width={img.src.width ?? 100}
94
+ placeholder={{lqip: img.preSrc}}
95
+ src={img.src.src}
96
+ srcSet={img.src.images.map((image) => ({
97
+ ...image,
98
+ src: image.path,
99
+ }))}
100
+ getMessage={getMessage}
101
+ />
102
+ );
103
+ }
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-ideal-image",
3
- "version": "2.0.0-beta.ff31de0ff",
3
+ "version": "2.0.1",
4
4
  "description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).",
5
5
  "main": "lib/index.js",
6
+ "types": "src/plugin-ideal-image.d.ts",
6
7
  "scripts": {
7
- "build": "tsc && node copyUntypedFiles.js",
8
- "watch": "node copyUntypedFiles.js && tsc --watch"
8
+ "build": "tsc --build && node ../../admin/scripts/copyUntypedFiles.js && prettier --config ../../.prettierrc --write \"lib/theme/**/*.js\"",
9
+ "watch": "run-p -c copy:watch build:watch",
10
+ "build:watch": "tsc --build --watch",
11
+ "copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
9
12
  },
10
13
  "publishConfig": {
11
14
  "access": "public"
@@ -16,26 +19,36 @@
16
19
  "directory": "packages/docusaurus-plugin-ideal-image"
17
20
  },
18
21
  "license": "MIT",
19
- "devDependencies": {
20
- "fs-extra": "^9.1.0"
21
- },
22
22
  "dependencies": {
23
- "@docusaurus/core": "2.0.0-beta.ff31de0ff",
24
- "@docusaurus/lqip-loader": "2.0.0-beta.ff31de0ff",
25
- "@docusaurus/responsive-loader": "1.4.0",
26
- "@docusaurus/types": "2.0.0-beta.ff31de0ff",
23
+ "@docusaurus/core": "2.0.1",
24
+ "@docusaurus/lqip-loader": "2.0.1",
25
+ "@docusaurus/responsive-loader": "^1.7.0",
26
+ "@docusaurus/theme-translations": "2.0.1",
27
+ "@docusaurus/types": "2.0.1",
28
+ "@docusaurus/utils-validation": "2.0.1",
27
29
  "@endiliey/react-ideal-image": "^0.0.11",
28
- "react-waypoint": "^9.0.2",
29
- "sharp": "^0.28.2",
30
- "tslib": "^2.1.0",
31
- "webpack": "^5.28.0"
30
+ "react-waypoint": "^10.3.0",
31
+ "sharp": "^0.30.7",
32
+ "tslib": "^2.4.0",
33
+ "webpack": "^5.73.0"
34
+ },
35
+ "devDependencies": {
36
+ "@docusaurus/module-type-aliases": "2.0.1",
37
+ "@docusaurus/types": "2.0.0-beta.21",
38
+ "fs-extra": "^10.1.0"
32
39
  },
33
40
  "peerDependencies": {
41
+ "jimp": "*",
34
42
  "react": "^16.8.4 || ^17.0.0",
35
43
  "react-dom": "^16.8.4 || ^17.0.0"
36
44
  },
45
+ "peerDependenciesMeta": {
46
+ "jimp": {
47
+ "optional": true
48
+ }
49
+ },
37
50
  "engines": {
38
- "node": ">=12.13.0"
51
+ "node": ">=16.14"
39
52
  },
40
- "gitHead": "6cacb313da4a21283fe08176097df89df836ee23"
53
+ "gitHead": "1ddee1c29cabf9bb52e4d78af6ebfaaabb1bc1f9"
41
54
  }
package/src/deps.d.ts ADDED
@@ -0,0 +1,119 @@
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
+ /**
11
+ * @see https://github.com/endiliey/react-ideal-image/blob/master/index.d.ts
12
+ * Note: the original type definition is WRONG. getIcon & getMessage receive
13
+ * full state object.
14
+ */
15
+ declare module '@endiliey/react-ideal-image' {
16
+ import type {ComponentProps, ComponentType, CSSProperties} from 'react';
17
+
18
+ export type LoadingState = 'initial' | 'loading' | 'loaded' | 'error';
19
+
20
+ export type State = {
21
+ pickedSrc: {
22
+ size: number;
23
+ };
24
+ loadInfo: 404 | null;
25
+ loadState: LoadingState;
26
+ };
27
+
28
+ export type IconKey =
29
+ | 'load'
30
+ | 'loading'
31
+ | 'loaded'
32
+ | 'error'
33
+ | 'noicon'
34
+ | 'offline';
35
+
36
+ export type SrcType = {
37
+ width: number;
38
+ src?: string;
39
+ size?: number;
40
+ format?: 'webp' | 'jpeg' | 'png' | 'gif';
41
+ };
42
+
43
+ type ThemeKey = 'placeholder' | 'img' | 'icon' | 'noscript';
44
+
45
+ export interface ImageProps
46
+ extends Omit<ComponentProps<'img'>, 'srcSet' | 'placeholder'> {
47
+ /**
48
+ * This function decides what icon to show based on the current state of the
49
+ * component.
50
+ */
51
+ getIcon?: (state: State) => IconKey;
52
+ /**
53
+ * This function decides what message to show based on the icon (returned
54
+ * from `getIcon` prop) and the current state of the component.
55
+ */
56
+ getMessage?: (icon: IconKey, state: State) => string | null;
57
+ /**
58
+ * This function is called as soon as the component enters the viewport and
59
+ * is used to generate urls based on width and format if `props.srcSet`
60
+ * doesn't provide `src` field.
61
+ */
62
+ getUrl?: (srcType: SrcType) => string;
63
+ /**
64
+ * The Height of the image in px.
65
+ */
66
+ height: number;
67
+ /**
68
+ * This provides a map of the icons. By default, the component uses icons
69
+ * from material design, Implemented as React components with the SVG
70
+ * element. You can customize icons
71
+ */
72
+ icons?: Partial<{[icon in IconKey]: ComponentType}>;
73
+ /**
74
+ * This prop takes one of the 2 options, xhr and image.
75
+ * Read more about it:
76
+ * https://github.com/stereobooster/react-ideal-image/blob/master/introduction.md#cancel-download
77
+ */
78
+ loader?: 'xhr' | 'image';
79
+ /**
80
+ * https://github.com/stereobooster/react-ideal-image/blob/master/introduction.md#lqip
81
+ */
82
+ placeholder: {color: string} | {lqip: string};
83
+ /**
84
+ * This function decides if image should be downloaded automatically. The
85
+ * default function returns false for a 2g network, for a 3g network it
86
+ * decides based on `props.threshold` and for a 4g network it returns true
87
+ * by default.
88
+ */
89
+ shouldAutoDownload?: (options: {
90
+ connection?: 'slow-2g' | '2g' | '3g' | '4g';
91
+ size?: number;
92
+ threshold?: number;
93
+ possiblySlowNetwork?: boolean;
94
+ }) => boolean;
95
+ /**
96
+ * This provides an array of sources of different format and size of the
97
+ * image. Read more about it:
98
+ * https://github.com/stereobooster/react-ideal-image/blob/master/introduction.md#srcset
99
+ */
100
+ srcSet: SrcType[];
101
+ /**
102
+ * This provides a theme to the component. By default, the component uses
103
+ * inline styles, but it is also possible to use CSS modules and override
104
+ * all styles.
105
+ */
106
+ theme?: Partial<{[key in ThemeKey]: string | CSSProperties}>;
107
+ /**
108
+ * Tells how much to wait in milliseconds until consider the download to be
109
+ * slow.
110
+ */
111
+ threshold?: number;
112
+ /**
113
+ * Width of the image in px.
114
+ */
115
+ width: number;
116
+ }
117
+
118
+ export default function IdealImage(props: ImageProps): JSX.Element;
119
+ }
package/src/index.ts ADDED
@@ -0,0 +1,87 @@
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
+ use: [
58
+ require.resolve('@docusaurus/lqip-loader'),
59
+ {
60
+ loader: require.resolve('@docusaurus/responsive-loader'),
61
+ options: {
62
+ // Don't emit for server-side rendering
63
+ emitFile: !isServer,
64
+ // eslint-disable-next-line global-require
65
+ adapter: require('@docusaurus/responsive-loader/sharp'),
66
+ name: 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]',
67
+ ...loaderOptions,
68
+ },
69
+ },
70
+ ],
71
+ },
72
+ ],
73
+ },
74
+ };
75
+ },
76
+ };
77
+ }
78
+
79
+ export function validateOptions({
80
+ validate,
81
+ options,
82
+ }: OptionValidationContext<PluginOptions, PluginOptions>): PluginOptions {
83
+ const pluginOptionsSchema = Joi.object<PluginOptions>({
84
+ disableInDev: Joi.boolean().default(true),
85
+ }).unknown();
86
+ return validate(pluginOptionsSchema, options);
87
+ }
@@ -0,0 +1,74 @@
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
+ declare module '@docusaurus/plugin-ideal-image' {
9
+ export type PluginOptions = {
10
+ /**
11
+ * Filename template for output files.
12
+ */
13
+ name?: string;
14
+ /**
15
+ * Specify all widths you want to use; if a specified size exceeds the
16
+ * original image's width, the latter will be used (i.e. images won't be
17
+ * scaled up).
18
+ */
19
+ sizes?: number[];
20
+ /**
21
+ * Specify one width you want to use; if the specified size exceeds the
22
+ * original image's width, the latter will be used (i.e. images won't be
23
+ * scaled up)
24
+ */
25
+ size?: number;
26
+ /**
27
+ * As an alternative to manually specifying `sizes`, you can specify `min`,
28
+ * `max` and `steps`, and the `sizes` will be generated for you.
29
+ */
30
+ min?: number;
31
+ /**
32
+ * @see {@link PluginOptions.min}
33
+ */
34
+ max?: number;
35
+ /**
36
+ * Configure the number of images generated between `min` and `max`
37
+ * (inclusive)
38
+ */
39
+ steps?: number;
40
+ /**
41
+ * JPEG compression quality
42
+ */
43
+ quality?: number;
44
+ /**
45
+ * You can test ideal image behavior in dev mode by setting this to `false`.
46
+ * Tip: use network throttling in your browser to simulate slow networks.
47
+ */
48
+ disableInDev?: boolean;
49
+ };
50
+ }
51
+
52
+ declare module '@theme/IdealImage' {
53
+ import type {ComponentProps} from 'react';
54
+
55
+ export type SrcType = {
56
+ width: number;
57
+ path?: string;
58
+ size?: number;
59
+ format?: 'webp' | 'jpeg' | 'png' | 'gif';
60
+ };
61
+
62
+ export type SrcImage = {
63
+ height?: number;
64
+ width?: number;
65
+ preSrc: string;
66
+ src: string;
67
+ images: SrcType[];
68
+ };
69
+
70
+ export interface Props extends ComponentProps<'img'> {
71
+ readonly img: {default: string} | {src: SrcImage; preSrc: string} | string;
72
+ }
73
+ export default function IdealImage(props: Props): JSX.Element;
74
+ }
@@ -0,0 +1,114 @@
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 React from 'react';
9
+ import ReactIdealImage, {
10
+ type IconKey,
11
+ type State,
12
+ } from '@endiliey/react-ideal-image';
13
+ import {translate} from '@docusaurus/Translate';
14
+
15
+ import type {Props} from '@theme/IdealImage';
16
+
17
+ // Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/helpers.js#L59-L65
18
+ function bytesToSize(bytes: number) {
19
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
20
+ if (bytes === 0) {
21
+ return 'n/a';
22
+ }
23
+ const scale = Math.floor(Math.log(bytes) / Math.log(1024));
24
+ if (scale === 0) {
25
+ return `${bytes} ${sizes[scale]!}`;
26
+ }
27
+ return `${(bytes / 1024 ** scale).toFixed(1)} ${sizes[scale]!}`;
28
+ }
29
+
30
+ // Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/IdealImage/index.js#L43-L75
31
+ function getMessage(icon: IconKey, state: State) {
32
+ switch (icon) {
33
+ case 'noicon':
34
+ case 'loaded':
35
+ return null;
36
+ case 'loading':
37
+ return translate({
38
+ id: 'theme.IdealImageMessage.loading',
39
+ message: 'Loading...',
40
+ description: 'When the full-scale image is loading',
41
+ });
42
+ case 'load': {
43
+ // We can show `alt` here
44
+ const {pickedSrc} = state;
45
+ const {size} = pickedSrc;
46
+ const sizeMessage = size ? ` (${bytesToSize(size)})` : '';
47
+ return translate(
48
+ {
49
+ id: 'theme.IdealImageMessage.load',
50
+ message: 'Click to load{sizeMessage}',
51
+ description:
52
+ 'To prompt users to load the full image. sizeMessage is a parenthesized size figure.',
53
+ },
54
+ {sizeMessage},
55
+ );
56
+ }
57
+ case 'offline':
58
+ return translate({
59
+ id: 'theme.IdealImageMessage.offline',
60
+ message: 'Your browser is offline. Image not loaded',
61
+ description: 'When the user is viewing an offline document',
62
+ });
63
+ case 'error': {
64
+ const {loadInfo} = state;
65
+ if (loadInfo === 404) {
66
+ return translate({
67
+ id: 'theme.IdealImageMessage.404error',
68
+ message: '404. Image not found',
69
+ description: 'When the image is not found',
70
+ });
71
+ }
72
+ return translate({
73
+ id: 'theme.IdealImageMessage.error',
74
+ message: 'Error. Click to reload',
75
+ description: 'When the image fails to load for unknown error',
76
+ });
77
+ }
78
+ default:
79
+ throw new Error(`Wrong icon: ${icon}`);
80
+ }
81
+ }
82
+
83
+ export default function IdealImage(props: Props): JSX.Element {
84
+ const {alt, className, img} = props;
85
+
86
+ // In dev env just use regular img with original file
87
+ if (typeof img === 'string' || 'default' in img) {
88
+ return (
89
+ <img
90
+ src={typeof img === 'string' ? img : img.default}
91
+ className={className}
92
+ alt={alt}
93
+ {...props}
94
+ />
95
+ );
96
+ }
97
+
98
+ return (
99
+ <ReactIdealImage
100
+ {...props}
101
+ alt={alt}
102
+ className={className}
103
+ height={img.src.height ?? 100}
104
+ width={img.src.width ?? 100}
105
+ placeholder={{lqip: img.preSrc}}
106
+ src={img.src.src}
107
+ srcSet={img.src.images.map((image) => ({
108
+ ...image,
109
+ src: image.path,
110
+ }))}
111
+ getMessage={getMessage}
112
+ />
113
+ );
114
+ }