-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathAdvancedImage.tsx
More file actions
136 lines (126 loc) · 4.08 KB
/
AdvancedImage.tsx
File metadata and controls
136 lines (126 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import React from 'react';
import { CloudinaryImage } from '@cloudinary/url-gen/assets/CloudinaryImage';
import {
HtmlImageLayer,
Plugins,
isBrowser,
serverSideSrc,
cancelCurrentlyRunningPlugins
} from '@cloudinary/html'
import { SDKAnalyticsConstants } from './internal/SDKAnalyticsConstants';
import { warnOnOversizedImage, warnOnLazyLCP } from './internal/PerformanceWarnings';
interface ImgProps {
cldImg: CloudinaryImage;
plugins?: Plugins;
[x: string]: any;
}
/**
* @mixin ReactSDK
* @description The Cloudinary React SDK contains components like \<AdvancedImage\> to easily render your media assets from Cloudinary.
* The SDK also comes with support for optional JS plugins that make the components smart, with features like lazy loading, placeholder, accessibility & responsiveness.
*
* @example
* <caption>
* Please note that the order of the plugins is important. See {@link https://cloudinary.com/documentation/sdks/js/frontend-frameworks/index.html#plugin-order|Plugin Order} for more details.
* </caption>
* // Example
* import {CloudinaryImage} from "@cloudinary/url-gen/assets/CloudinaryImage";
* import {
* AdvancedImage,
* accessibility,
* responsive,
* lazyload,
* placeholder
* } from '@cloudinary/react';
*
* const App = () => {
*
* const myCld = new Cloudinary({ cloudName: 'demo'});
* let img = myCld().image('sample');
*
* return (
* <div>
* <div style={{height: "1000px"}}/>
* <AdvancedImage
* cldImg={img}
* plugins={[lazyload(), responsive(100), placeholder()]}
* />
* </div>
* )
* };
*
*
*
*
*
*/
/**
* @memberOf ReactSDK
* @type {Component}
* @description The Cloudinary image component.
* @prop {CloudinaryImage} cldImg Generated by @cloudinary/url-gen
* @prop {Plugins} plugins Advanced image component plugins accessibility(), responsive(), lazyload(), placeholder()
*/
class AdvancedImage extends React.Component <ImgProps> {
imageRef: React.RefObject<HTMLImageElement>;
htmlLayerInstance: HtmlImageLayer;
constructor(props: ImgProps) {
super(props);
this.imageRef = React.createRef();
}
/**
* On mount, creates a new HTMLLayer instance and initializes with ref to img element,
* user generated cloudinaryImage and the plugins to be used.
*/
componentDidMount() {
this.htmlLayerInstance = new HtmlImageLayer(
this.imageRef.current,
this.props.cldImg,
this.props.plugins,
SDKAnalyticsConstants
)
if(NODE_ENV === 'development' && this.imageRef.current && !this.props["silence-warnings"]) {
warnOnLazyLCP(this.imageRef.current);
if(this.imageRef.current?.complete) {
warnOnOversizedImage(this.imageRef.current);
} else {
this.imageRef.current?.addEventListener('load', (e) => warnOnOversizedImage(e.currentTarget as HTMLImageElement));
}
}
}
/**
* On update, we cancel running plugins and update image instance with the state of user
* cloudinaryImage and the state of plugins.
*/
componentDidUpdate() {
cancelCurrentlyRunningPlugins(this.htmlLayerInstance.htmlPluginState);
// call html layer to update the dom again with plugins and reset toBeCanceled
this.htmlLayerInstance.update(this.props.cldImg, this.props.plugins, SDKAnalyticsConstants)
}
/**
* On unmount, we cancel the currently running plugins, and destroy the html layer instance
*/
componentWillUnmount() {
// Safely cancel running events on unmount.
cancelCurrentlyRunningPlugins(this.htmlLayerInstance.htmlPluginState);
this.htmlLayerInstance.unmount();
}
render() {
const {
cldImg,
plugins,
...otherProps // Assume any other props are for the base element
} = this.props;
if (isBrowser()) { // On client side render
return <img suppressHydrationWarning {...otherProps} ref={this.imageRef} />
} else { // on server side render
const src = serverSideSrc(
this.props.plugins,
this.props.cldImg,
SDKAnalyticsConstants
);
return <img {...otherProps} src={src} />
}
}
}
export { AdvancedImage };