@docusaurus/plugin-ideal-image 3.7.0 → 3.8.0-canary-6327

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 (69) hide show
  1. package/lib/index.js +6 -0
  2. package/lib/theme/IdealImage/index.js +1 -2
  3. package/lib/theme/IdealImageLegacy/LICENSE +20 -0
  4. package/lib/theme/IdealImageLegacy/README.md +13 -0
  5. package/lib/theme/IdealImageLegacy/components/Icon/Download.d.ts +3 -0
  6. package/lib/theme/IdealImageLegacy/components/Icon/Download.js +15 -0
  7. package/lib/theme/IdealImageLegacy/components/Icon/Loading.d.ts +3 -0
  8. package/lib/theme/IdealImageLegacy/components/Icon/Loading.js +15 -0
  9. package/lib/theme/IdealImageLegacy/components/Icon/Offline.d.ts +3 -0
  10. package/lib/theme/IdealImageLegacy/components/Icon/Offline.js +15 -0
  11. package/lib/theme/IdealImageLegacy/components/Icon/Warning.d.ts +3 -0
  12. package/lib/theme/IdealImageLegacy/components/Icon/Warning.js +15 -0
  13. package/lib/theme/IdealImageLegacy/components/Icon/index.d.ts +8 -0
  14. package/lib/theme/IdealImageLegacy/components/Icon/index.js +25 -0
  15. package/lib/theme/IdealImageLegacy/components/IdealImage/index.d.ts +42 -0
  16. package/lib/theme/IdealImageLegacy/components/IdealImage/index.js +352 -0
  17. package/lib/theme/IdealImageLegacy/components/IdealImage/waypoint.d.ts +10 -0
  18. package/lib/theme/IdealImageLegacy/components/IdealImage/waypoint.js +188 -0
  19. package/lib/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.d.ts +33 -0
  20. package/lib/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.js +12 -0
  21. package/lib/theme/IdealImageLegacy/components/Media/index.d.ts +20 -0
  22. package/lib/theme/IdealImageLegacy/components/Media/index.js +169 -0
  23. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/README.md +89 -0
  24. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/index.d.ts +33 -0
  25. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/index.js +12 -0
  26. package/lib/theme/IdealImageLegacy/components/composeStyle.d.ts +5 -0
  27. package/lib/theme/IdealImageLegacy/components/composeStyle.js +37 -0
  28. package/lib/theme/IdealImageLegacy/components/constants.d.ts +22 -0
  29. package/lib/theme/IdealImageLegacy/components/constants.js +24 -0
  30. package/lib/theme/IdealImageLegacy/components/helpers.d.ts +22 -0
  31. package/lib/theme/IdealImageLegacy/components/helpers.js +141 -0
  32. package/lib/theme/IdealImageLegacy/components/icons.d.ts +15 -0
  33. package/lib/theme/IdealImageLegacy/components/icons.js +16 -0
  34. package/lib/theme/IdealImageLegacy/components/loaders.d.ts +4 -0
  35. package/lib/theme/IdealImageLegacy/components/loaders.js +112 -0
  36. package/lib/theme/IdealImageLegacy/components/theme.d.ts +30 -0
  37. package/lib/theme/IdealImageLegacy/components/theme.js +26 -0
  38. package/lib/theme/IdealImageLegacy/components/theme.module.css +35 -0
  39. package/lib/theme/IdealImageLegacy/components/unfetch.d.ts +7 -0
  40. package/lib/theme/IdealImageLegacy/components/unfetch.js +74 -0
  41. package/lib/theme/IdealImageLegacy/index.d.ts +2 -0
  42. package/lib/theme/IdealImageLegacy/index.js +2 -0
  43. package/package.json +8 -10
  44. package/src/index.ts +6 -0
  45. package/src/plugin-ideal-image.d.ts +121 -0
  46. package/src/theme/IdealImage/index.tsx +2 -3
  47. package/src/theme/IdealImageLegacy/LICENSE +20 -0
  48. package/src/theme/IdealImageLegacy/README.md +13 -0
  49. package/src/theme/IdealImageLegacy/components/Icon/Download.js +15 -0
  50. package/src/theme/IdealImageLegacy/components/Icon/Loading.js +15 -0
  51. package/src/theme/IdealImageLegacy/components/Icon/Offline.js +15 -0
  52. package/src/theme/IdealImageLegacy/components/Icon/Warning.js +15 -0
  53. package/src/theme/IdealImageLegacy/components/Icon/index.js +25 -0
  54. package/src/theme/IdealImageLegacy/components/IdealImage/index.js +352 -0
  55. package/src/theme/IdealImageLegacy/components/IdealImage/waypoint.tsx +254 -0
  56. package/src/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.js +12 -0
  57. package/src/theme/IdealImageLegacy/components/Media/index.js +169 -0
  58. package/src/theme/IdealImageLegacy/components/MediaWithDefaults/README.md +89 -0
  59. package/src/theme/IdealImageLegacy/components/MediaWithDefaults/index.js +12 -0
  60. package/src/theme/IdealImageLegacy/components/composeStyle.js +37 -0
  61. package/src/theme/IdealImageLegacy/components/constants.js +24 -0
  62. package/src/theme/IdealImageLegacy/components/helpers.js +141 -0
  63. package/src/theme/IdealImageLegacy/components/icons.js +16 -0
  64. package/src/theme/IdealImageLegacy/components/loaders.js +112 -0
  65. package/src/theme/IdealImageLegacy/components/theme.js +26 -0
  66. package/src/theme/IdealImageLegacy/components/theme.module.css +35 -0
  67. package/src/theme/IdealImageLegacy/components/unfetch.js +74 -0
  68. package/src/theme/IdealImageLegacy/index.tsx +3 -0
  69. package/src/deps.d.ts +0 -124
package/lib/index.js CHANGED
@@ -39,6 +39,12 @@ function pluginIdealImage(context, options) {
39
39
  rules: [
40
40
  {
41
41
  test: /\.(?:png|jpe?g)$/i,
42
+ // We don't want to use the image loader for non-React source code
43
+ // ie we don't want to use ideal image loader for CSS files...
44
+ // See https://github.com/facebook/docusaurus/issues/10862
45
+ issuer: {
46
+ and: [/\.(?:tsx?|jsx?|mdx?)$/i],
47
+ },
42
48
  use: [
43
49
  require.resolve('@docusaurus/lqip-loader'),
44
50
  {
@@ -5,8 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import ReactIdealImage from '@slorber/react-ideal-image';
9
8
  import {translate} from '@docusaurus/Translate';
9
+ import ReactIdealImage from '@theme/IdealImageLegacy';
10
10
  // Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/helpers.js#L59-L65
11
11
  function bytesToSize(bytes) {
12
12
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
@@ -82,7 +82,6 @@ export default function IdealImage(props) {
82
82
  }
83
83
  return (
84
84
  <ReactIdealImage
85
- {...propsRest}
86
85
  height={img.src.height ?? 100}
87
86
  width={img.src.width ?? 100}
88
87
  placeholder={{lqip: img.preSrc}}
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2017 stereobooster
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -0,0 +1,13 @@
1
+ # Legacy React IdealImage lib
2
+
3
+ This is legacy code from an npm package we forked, then internalized
4
+
5
+ See also:
6
+
7
+ - https://github.com/slorber/docusaurus-react-ideal-image
8
+ - https://github.com/endiliey/react-ideal-image
9
+ - https://github.com/stereobooster/react-ideal-image
10
+
11
+ ---
12
+
13
+ TODO: we need to clean it up, remove what we don't need, and maintain it up to date
@@ -0,0 +1,3 @@
1
+ export default Download;
2
+ declare function Download(props: any): React.JSX.Element;
3
+ import React from 'react';
@@ -0,0 +1,15 @@
1
+ // This icon is from "material design icons"
2
+ // It is licensed under Apache License 2.0
3
+ // Full text is available here
4
+ // https://github.com/google/material-design-icons/blob/master/LICENSE
5
+ import React from 'react';
6
+ import Icon from './index';
7
+
8
+ const Download = (props) => (
9
+ <Icon
10
+ {...props}
11
+ path="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z"
12
+ />
13
+ );
14
+
15
+ export default Download;
@@ -0,0 +1,3 @@
1
+ export default Loading;
2
+ declare function Loading(props: any): React.JSX.Element;
3
+ import React from 'react';
@@ -0,0 +1,15 @@
1
+ // This icon is from "material design icons"
2
+ // It is licensed under Apache License 2.0
3
+ // Full text is available here
4
+ // https://github.com/google/material-design-icons/blob/master/LICENSE
5
+ import React from 'react';
6
+ import Icon from './index';
7
+
8
+ const Loading = (props) => (
9
+ <Icon
10
+ {...props}
11
+ path="M6,2V8H6V8L10,12L6,16V16H6V22H18V16H18V16L14,12L18,8V8H18V2H6M16,16.5V20H8V16.5L12,12.5L16,16.5M12,11.5L8,7.5V4H16V7.5L12,11.5Z"
12
+ />
13
+ );
14
+
15
+ export default Loading;
@@ -0,0 +1,3 @@
1
+ export default Offline;
2
+ declare function Offline(props: any): React.JSX.Element;
3
+ import React from 'react';
@@ -0,0 +1,15 @@
1
+ // This icon is from "material design icons"
2
+ // It is licensed under Apache License 2.0
3
+ // Full text is available here
4
+ // https://github.com/google/material-design-icons/blob/master/LICENSE
5
+ import React from 'react';
6
+ import Icon from './index';
7
+
8
+ const Offline = (props) => (
9
+ <Icon
10
+ {...props}
11
+ path="M19.35 10.04C18.67 6.59 15.64 4 12 4c-1.48 0-2.85.43-4.01 1.17l1.46 1.46C10.21 6.23 11.08 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3 0 1.13-.64 2.11-1.56 2.62l1.45 1.45C23.16 18.16 24 16.68 24 15c0-2.64-2.05-4.78-4.65-4.96zM3 5.27l2.75 2.74C2.56 8.15 0 10.77 0 14c0 3.31 2.69 6 6 6h11.73l2 2L21 20.73 4.27 4 3 5.27zM7.73 10l8 8H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h1.73z"
12
+ />
13
+ );
14
+
15
+ export default Offline;
@@ -0,0 +1,3 @@
1
+ export default Warning;
2
+ declare function Warning(props: any): React.JSX.Element;
3
+ import React from 'react';
@@ -0,0 +1,15 @@
1
+ // This icon is from "material design icons"
2
+ // It is licensed under Apache License 2.0
3
+ // Full text is available here
4
+ // https://github.com/google/material-design-icons/blob/master/LICENSE
5
+ import React from 'react';
6
+ import Icon from './index';
7
+
8
+ const Warning = (props) => (
9
+ <Icon
10
+ {...props}
11
+ path="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"
12
+ />
13
+ );
14
+
15
+ export default Warning;
@@ -0,0 +1,8 @@
1
+ export default Icon;
2
+ declare function Icon({ size, fill, className, path }: {
3
+ size?: number | undefined;
4
+ fill?: string | undefined;
5
+ className: any;
6
+ path: any;
7
+ }): React.JSX.Element;
8
+ import React from 'react';
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ // import PropTypes from 'prop-types'
3
+
4
+ const Icon = ({size = 24, fill = '#000', className, path}) => (
5
+ <svg
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ width={size}
8
+ height={size}
9
+ viewBox="0 0 24 24"
10
+ className={className}>
11
+ <path d="M0 0h24v24H0z" fill="none" />
12
+ <path fill={fill} d={path} />
13
+ </svg>
14
+ );
15
+
16
+ /*
17
+ Icon.propTypes = {
18
+ size: PropTypes.number,
19
+ fill: PropTypes.string,
20
+ className: PropTypes.string,
21
+ path: PropTypes.string.isRequired,
22
+ }
23
+ */
24
+
25
+ export default Icon;
@@ -0,0 +1,42 @@
1
+ export default class IdealImage extends React.Component<any, any, any> {
2
+ static defaultProps: {
3
+ shouldAutoDownload: ({ connection, size, threshold, possiblySlowNetwork, }: {
4
+ connection: any;
5
+ size: any;
6
+ threshold: any;
7
+ possiblySlowNetwork: any;
8
+ }) => boolean;
9
+ getMessage: (icon: any, state: any) => "Loading..." | "Your browser is offline. Image not loaded" | "404. Image not found" | "Error. Click to reload" | (string | React.JSX.Element)[] | "Click to load" | null;
10
+ getIcon: (state: any) => string;
11
+ loader: string;
12
+ };
13
+ constructor(props: any);
14
+ state: {
15
+ loadState: string;
16
+ connection: {
17
+ downlink: any;
18
+ rtt: any;
19
+ effectiveType: any;
20
+ } | null;
21
+ onLine: boolean;
22
+ overThreshold: boolean;
23
+ inViewport: boolean;
24
+ userTriggered: boolean;
25
+ possiblySlowNetwork: boolean;
26
+ };
27
+ componentDidMount(): void;
28
+ updateConnection: (() => void) | undefined;
29
+ possiblySlowNetworkListener: ((e: any) => void) | undefined;
30
+ updateOnlineStatus: (() => void) | undefined;
31
+ componentWillUnmount(): void;
32
+ onClick: () => void;
33
+ clear(): void;
34
+ loader: Promise<any> | undefined;
35
+ cancel(userTriggered: any): void;
36
+ loadStateChange(loadState: any, userTriggered: any, loadInfo?: null): void;
37
+ load: (userTriggered: any) => void;
38
+ onEnter: () => void;
39
+ onLeave: () => void;
40
+ render(): React.JSX.Element;
41
+ }
42
+ import React from 'react';
@@ -0,0 +1,352 @@
1
+ import React, {Component} from 'react';
2
+ import {Waypoint} from './waypoint';
3
+ import Media from '../Media';
4
+ import {icons, loadStates} from '../constants';
5
+ import {xhrLoader, imageLoader, timeout, combineCancel} from '../loaders';
6
+ import {
7
+ guessMaxImageWidth,
8
+ bytesToSize,
9
+ supportsWebp,
10
+ ssr,
11
+ nativeConnection,
12
+ selectSrc,
13
+ fallbackParams,
14
+ } from '../helpers';
15
+
16
+ const {initial, loading, loaded, error} = loadStates;
17
+
18
+ const defaultShouldAutoDownload = ({
19
+ connection,
20
+ size,
21
+ threshold,
22
+ possiblySlowNetwork,
23
+ }) => {
24
+ if (possiblySlowNetwork) return false;
25
+ if (!connection) return true;
26
+ const {downlink, rtt, effectiveType} = connection;
27
+ switch (effectiveType) {
28
+ case 'slow-2g':
29
+ case '2g':
30
+ return false;
31
+ case '3g':
32
+ if (downlink && size && threshold) {
33
+ return (size * 8) / (downlink * 1000) + rtt < threshold;
34
+ }
35
+ return false;
36
+ case '4g':
37
+ default:
38
+ return true;
39
+ }
40
+ };
41
+
42
+ const defaultGetMessage = (icon, state) => {
43
+ switch (icon) {
44
+ case icons.noicon:
45
+ case icons.loaded:
46
+ return null;
47
+ case icons.loading:
48
+ return 'Loading...';
49
+ case icons.load:
50
+ // we can show `alt` here
51
+ const {pickedSrc} = state;
52
+ const {size} = pickedSrc;
53
+ if (size) {
54
+ return [
55
+ 'Click to load (',
56
+ <nobr key="nb">{bytesToSize(size)}</nobr>,
57
+ ')',
58
+ ];
59
+ } else {
60
+ return 'Click to load';
61
+ }
62
+ case icons.offline:
63
+ return 'Your browser is offline. Image not loaded';
64
+ case icons.error:
65
+ const {loadInfo} = state;
66
+ if (loadInfo === 404) {
67
+ return '404. Image not found';
68
+ } else {
69
+ return 'Error. Click to reload';
70
+ }
71
+ default:
72
+ throw new Error(`Wrong icon: ${icon}`);
73
+ }
74
+ };
75
+
76
+ const defaultGetIcon = (state) => {
77
+ const {loadState, onLine, overThreshold, userTriggered} = state;
78
+ if (ssr) return icons.noicon;
79
+ switch (loadState) {
80
+ case loaded:
81
+ return icons.loaded;
82
+ case loading:
83
+ return overThreshold ? icons.loading : icons.noicon;
84
+ case initial:
85
+ if (onLine) {
86
+ const {shouldAutoDownload} = state;
87
+ if (shouldAutoDownload === undefined) return icons.noicon;
88
+ return userTriggered || !shouldAutoDownload ? icons.load : icons.noicon;
89
+ } else {
90
+ return icons.offline;
91
+ }
92
+ case error:
93
+ return onLine ? icons.error : icons.offline;
94
+ default:
95
+ throw new Error(`Wrong state: ${loadState}`);
96
+ }
97
+ };
98
+
99
+ export default class IdealImage extends Component {
100
+ constructor(props) {
101
+ super(props);
102
+ // TODO: validate props.srcSet
103
+ this.state = {
104
+ loadState: initial,
105
+ connection: nativeConnection
106
+ ? {
107
+ downlink: navigator.connection.downlink, // megabits per second
108
+ rtt: navigator.connection.rtt, // ms
109
+ effectiveType: navigator.connection.effectiveType, // 'slow-2g', '2g', '3g', or '4g'
110
+ }
111
+ : null,
112
+ onLine: true,
113
+ overThreshold: false,
114
+ inViewport: false,
115
+ userTriggered: false,
116
+ possiblySlowNetwork: false,
117
+ };
118
+ }
119
+
120
+ /*
121
+ static propTypes = {
122
+ /!** how much to wait in ms until consider download to slow *!/
123
+ threshold: PropTypes.number,
124
+ /!** function to generate src based on width and format *!/
125
+ getUrl: PropTypes.func,
126
+ /!** array of sources *!/
127
+ srcSet: PropTypes.arrayOf(
128
+ PropTypes.shape({
129
+ width: PropTypes.number.isRequired,
130
+ src: PropTypes.string,
131
+ size: PropTypes.number,
132
+ format: PropTypes.oneOf(['jpeg', 'jpg', 'webp', 'png', 'gif']),
133
+ }),
134
+ ).isRequired,
135
+ /!** function which decides if image should be downloaded *!/
136
+ shouldAutoDownload: PropTypes.func,
137
+ /!** function which decides what message to show *!/
138
+ getMessage: PropTypes.func,
139
+ /!** function which decides what icon to show *!/
140
+ getIcon: PropTypes.func,
141
+ /!** type of loader *!/
142
+ loader: PropTypes.oneOf(['image', 'xhr']),
143
+ /!** Width of the image in px *!/
144
+ width: PropTypes.number.isRequired,
145
+ /!** Height of the image in px *!/
146
+ height: PropTypes.number.isRequired,
147
+ placeholder: PropTypes.oneOfType([
148
+ PropTypes.shape({
149
+ /!** Solid color placeholder *!/
150
+ color: PropTypes.string.isRequired,
151
+ }),
152
+ PropTypes.shape({
153
+ /!**
154
+ * [Low Quality Image Placeholder](https://github.com/zouhir/lqip)
155
+ * [SVG-Based Image Placeholder](https://github.com/technopagan/sqip)
156
+ * base64 encoded image of low quality
157
+ *!/
158
+ lqip: PropTypes.string.isRequired,
159
+ }),
160
+ ]).isRequired,
161
+ /!** Map of icons *!/
162
+ icons: PropTypes.object.isRequired,
163
+ /!** theme object - CSS Modules or React styles *!/
164
+ theme: PropTypes.object.isRequired,
165
+ }*/
166
+
167
+ static defaultProps = {
168
+ shouldAutoDownload: defaultShouldAutoDownload,
169
+ getMessage: defaultGetMessage,
170
+ getIcon: defaultGetIcon,
171
+ loader: 'xhr',
172
+ };
173
+
174
+ componentDidMount() {
175
+ if (nativeConnection) {
176
+ this.updateConnection = () => {
177
+ if (!navigator.onLine) return;
178
+ if (this.state.loadState === initial) {
179
+ this.setState({
180
+ connection: {
181
+ effectiveType: navigator.connection.effectiveType,
182
+ downlink: navigator.connection.downlink,
183
+ rtt: navigator.connection.rtt,
184
+ },
185
+ });
186
+ }
187
+ };
188
+ navigator.connection.addEventListener('onchange', this.updateConnection);
189
+ } else if (this.props.threshold) {
190
+ this.possiblySlowNetworkListener = (e) => {
191
+ if (this.state.loadState !== initial) return;
192
+ const {possiblySlowNetwork} = e.detail;
193
+ if (!this.state.possiblySlowNetwork && possiblySlowNetwork) {
194
+ this.setState({possiblySlowNetwork});
195
+ }
196
+ };
197
+ window.document.addEventListener(
198
+ 'possiblySlowNetwork',
199
+ this.possiblySlowNetworkListener,
200
+ );
201
+ }
202
+ this.updateOnlineStatus = () => this.setState({onLine: navigator.onLine});
203
+ this.updateOnlineStatus();
204
+ window.addEventListener('online', this.updateOnlineStatus);
205
+ window.addEventListener('offline', this.updateOnlineStatus);
206
+ }
207
+
208
+ componentWillUnmount() {
209
+ this.clear();
210
+ if (nativeConnection) {
211
+ navigator.connection.removeEventListener(
212
+ 'onchange',
213
+ this.updateConnection,
214
+ );
215
+ } else if (this.props.threshold) {
216
+ window.document.removeEventListener(
217
+ 'possiblySlowNetwork',
218
+ this.possiblySlowNetworkListener,
219
+ );
220
+ }
221
+ window.removeEventListener('online', this.updateOnlineStatus);
222
+ window.removeEventListener('offline', this.updateOnlineStatus);
223
+ }
224
+
225
+ onClick = () => {
226
+ const {loadState, onLine, overThreshold} = this.state;
227
+ if (!onLine) return;
228
+ switch (loadState) {
229
+ case loading:
230
+ if (overThreshold) this.cancel(true);
231
+ return;
232
+ case loaded:
233
+ // nothing
234
+ return;
235
+ case initial:
236
+ case error:
237
+ this.load(true);
238
+ return;
239
+ default:
240
+ throw new Error(`Wrong state: ${loadState}`);
241
+ }
242
+ };
243
+
244
+ clear() {
245
+ if (this.loader) {
246
+ this.loader.cancel();
247
+ this.loader = undefined;
248
+ }
249
+ }
250
+
251
+ cancel(userTriggered) {
252
+ if (loading !== this.state.loadState) return;
253
+ this.clear();
254
+ this.loadStateChange(initial, userTriggered);
255
+ }
256
+
257
+ loadStateChange(loadState, userTriggered, loadInfo = null) {
258
+ this.setState({
259
+ loadState,
260
+ overThreshold: false,
261
+ userTriggered: !!userTriggered,
262
+ loadInfo,
263
+ });
264
+ }
265
+
266
+ load = (userTriggered) => {
267
+ const {loadState, url} = this.state;
268
+ if (ssr || loaded === loadState || loading === loadState) return;
269
+ this.loadStateChange(loading, userTriggered);
270
+
271
+ const {threshold} = this.props;
272
+ const loader =
273
+ this.props.loader === 'xhr' ? xhrLoader(url) : imageLoader(url);
274
+ loader
275
+ .then(() => {
276
+ this.clear();
277
+ this.loadStateChange(loaded, false);
278
+ })
279
+ .catch((e) => {
280
+ this.clear();
281
+ if (e.status === 404) {
282
+ this.loadStateChange(error, false, 404);
283
+ } else {
284
+ this.loadStateChange(error, false);
285
+ }
286
+ });
287
+
288
+ if (threshold) {
289
+ const timeoutLoader = timeout(threshold);
290
+ timeoutLoader.then(() => {
291
+ if (!this.loader) return;
292
+ window.document.dispatchEvent(
293
+ new CustomEvent('possiblySlowNetwork', {
294
+ detail: {possiblySlowNetwork: true},
295
+ }),
296
+ );
297
+ this.setState({overThreshold: true});
298
+ if (!this.state.userTriggered) this.cancel(true);
299
+ });
300
+ this.loader = combineCancel(loader, timeoutLoader);
301
+ } else {
302
+ this.loader = loader;
303
+ }
304
+ };
305
+
306
+ onEnter = () => {
307
+ if (this.state.inViewport) return;
308
+ this.setState({inViewport: true});
309
+ const pickedSrc = selectSrc({
310
+ srcSet: this.props.srcSet,
311
+ maxImageWidth:
312
+ this.props.srcSet.length > 1
313
+ ? guessMaxImageWidth(this.state.dimensions) // eslint-disable-line react/no-access-state-in-setstate
314
+ : 0,
315
+ supportsWebp,
316
+ });
317
+ const {getUrl} = this.props;
318
+ const url = getUrl ? getUrl(pickedSrc) : pickedSrc.src;
319
+ const shouldAutoDownload = this.props.shouldAutoDownload({
320
+ ...this.state, // eslint-disable-line react/no-access-state-in-setstate
321
+ size: pickedSrc.size,
322
+ });
323
+ this.setState({pickedSrc, shouldAutoDownload, url}, () => {
324
+ if (shouldAutoDownload) this.load(false);
325
+ });
326
+ };
327
+
328
+ onLeave = () => {
329
+ if (this.state.loadState === loading && !this.state.userTriggered) {
330
+ this.setState({inViewport: false});
331
+ this.cancel(false);
332
+ }
333
+ };
334
+
335
+ render() {
336
+ const icon = this.props.getIcon(this.state);
337
+ const message = this.props.getMessage(icon, this.state);
338
+ return (
339
+ <Waypoint onEnter={this.onEnter} onLeave={this.onLeave}>
340
+ <Media
341
+ {...this.props}
342
+ {...fallbackParams(this.props)}
343
+ onClick={this.onClick}
344
+ icon={icon}
345
+ src={this.state.url || ''}
346
+ onDimensions={(dimensions) => this.setState({dimensions})}
347
+ message={message}
348
+ />
349
+ </Waypoint>
350
+ );
351
+ }
352
+ }
@@ -0,0 +1,10 @@
1
+ import React, { ReactNode } from 'react';
2
+ type Props = {
3
+ topOffset: number;
4
+ bottomOffset: number;
5
+ onEnter: () => void;
6
+ onLeave: () => void;
7
+ children: ReactNode;
8
+ };
9
+ export declare function Waypoint(props: Props): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
10
+ export {};