@axinom/mosaic-ui 0.41.0-rc.9 → 0.41.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-ui",
3
- "version": "0.41.0-rc.9",
3
+ "version": "0.41.0",
4
4
  "description": "UI components for building Axinom Mosaic applications",
5
5
  "author": "Axinom",
6
6
  "license": "PROPRIETARY",
@@ -32,7 +32,7 @@
32
32
  "build-storybook": "storybook build"
33
33
  },
34
34
  "dependencies": {
35
- "@axinom/mosaic-core": "^0.4.14-rc.9",
35
+ "@axinom/mosaic-core": "^0.4.14",
36
36
  "@faker-js/faker": "^7.4.0",
37
37
  "@popperjs/core": "^2.11.8",
38
38
  "clsx": "^1.1.0",
@@ -104,5 +104,5 @@
104
104
  "publishConfig": {
105
105
  "access": "public"
106
106
  },
107
- "gitHead": "731200c07c26ffdc0c0b0b96589e24db74317987"
107
+ "gitHead": "e583a1076964626d1d0b1f9fb507d1defc307102"
108
108
  }
@@ -57,7 +57,7 @@ describe('ImageLoader', () => {
57
57
  const imgDisplay = wrapper.find('img').prop('style')?.display;
58
58
 
59
59
  expect(loader.exists()).toBe(false);
60
- expect(imgDisplay).toBe('block');
60
+ expect(imgDisplay).toBe('unset');
61
61
  });
62
62
 
63
63
  it('emits onLoad callback with img src after successful load', () => {
@@ -98,11 +98,10 @@ describe('ImageLoader', () => {
98
98
  wrapper.find('img').prop('onError')!({} as SyntheticEvent);
99
99
 
100
100
  const loader = wrapper.find(ContentLoader);
101
- const imgDisplay = wrapper.find('img').prop('style')?.display;
102
101
  const fallbackContainer = wrapper.find('.container').at(1);
103
102
 
103
+ expect(wrapper.find('img').exists()).toBe(false);
104
104
  expect(loader.exists()).toBe(false);
105
- expect(imgDisplay).toBe('none');
106
105
  expect(fallbackContainer.hasClass('fallback')).toBe(true);
107
106
  });
108
107
 
@@ -119,11 +118,10 @@ describe('ImageLoader', () => {
119
118
  const fallbackContainer = wrapper.find('.container').at(1);
120
119
 
121
120
  expect(loader.exists()).toBe(false);
122
- expect(images.at(0).prop('style')?.display).toBe('none'); // hidden failed image
123
121
  expect(fallbackContainer.exists()).toBe(false); // no background color
124
- expect(images.at(1).exists()).toBe(true); // fallback image
125
- expect(images.at(1).prop('src')).toBe(mockFallbackUrl);
126
- expect(images.at(1).hasClass('fallBackImage')).toBe(true);
122
+ expect(images.at(0).exists()).toBe(true); // fallback image
123
+ expect(images.at(0).prop('src')).toBe(mockFallbackUrl);
124
+ expect(images.at(0).hasClass('fallBackImage')).toBe(true);
127
125
  });
128
126
 
129
127
  it('emits onError callback with img src after load failure', () => {
@@ -7,7 +7,7 @@ import classes from './ImageLoader.scss';
7
7
 
8
8
  export interface ImageLoaderProps {
9
9
  /** Image's url */
10
- imgSrc: string;
10
+ imgSrc?: string;
11
11
  /** Image's alt attribute */
12
12
  alt?: string;
13
13
  /** Image loader height (default: 50) */
@@ -33,9 +33,9 @@ export interface ImageLoaderProps {
33
33
  /** Specify the amount of time the component should wait for the image source to arrive before rendering the fallback, in milliseconds (default: 2000). If the image manages to load at a later time, the image will be rendered */
34
34
  imageTimeout?: number;
35
35
  /** Callback emitted after the image has successfully loaded. Img src is sent back */
36
- onLoad?: (src: string) => void;
36
+ onLoad?: (src?: string) => void;
37
37
  /** Callback emitted after the image has failed to load. Img src is sent back */
38
- onError?: (src: string) => void;
38
+ onError?: (src?: string) => void;
39
39
  /** Callback emitted when the image element is clicked */
40
40
  onImageClick?: (
41
41
  event: React.MouseEvent<HTMLImageElement, MouseEvent>,
@@ -45,6 +45,12 @@ export interface ImageLoaderProps {
45
45
  imageClassName?: string;
46
46
  }
47
47
 
48
+ enum ImageLoaderState {
49
+ Loading = 'loading',
50
+ Loaded = 'loaded',
51
+ Failed = 'failed',
52
+ }
53
+
48
54
  /**
49
55
  * Renders a loading animation while an image is being fetched
50
56
  * @example
@@ -72,25 +78,32 @@ export const ImageLoader: React.FC<ImageLoaderProps> = ({
72
78
  }) => {
73
79
  const actualViewBox = viewBox || `0 0 ${width} ${height}`;
74
80
 
75
- const [srcTimedOut, setSrcTimedOut] = useState<boolean>(false);
76
- const [isLoading, setIsLoading] = useState<boolean>(true);
77
- const [fallBack, setFallBack] = useState<boolean>(false);
81
+ const [state, setState] = useState<ImageLoaderState>(
82
+ ImageLoaderState.Loading,
83
+ );
84
+
85
+ // Fallback if the image source is undefined
86
+ // We won't even try to load the image in that case
87
+ useEffect(() => {
88
+ if (imgSrc === undefined) {
89
+ setState(ImageLoaderState.Failed);
90
+ }
91
+ }, [imgSrc]);
78
92
 
79
- // check if url has loaded after set time (milliseconds)
80
- useEffect(
81
- () => {
93
+ // Fallback if the image source fails to load in time
94
+ useEffect(() => {
95
+ if (state === ImageLoaderState.Loading) {
82
96
  const timer = setTimeout(() => {
83
- if (imgSrc === undefined) {
84
- setSrcTimedOut(true);
97
+ if (state === ImageLoaderState.Loading) {
98
+ setState(ImageLoaderState.Failed);
99
+ onError(imgSrc);
85
100
  }
86
101
  }, imageTimeout);
87
102
  return () => {
88
103
  clearTimeout(timer);
89
104
  };
90
- },
91
- // eslint-disable-next-line react-hooks/exhaustive-deps
92
- [],
93
- );
105
+ }
106
+ }, [imageTimeout, imgSrc, onError, state]);
94
107
 
95
108
  const customStyles = {
96
109
  height: `${height}px`,
@@ -98,20 +111,18 @@ export const ImageLoader: React.FC<ImageLoaderProps> = ({
98
111
  } as React.CSSProperties;
99
112
 
100
113
  const onLoadHandler = useCallback(() => {
101
- setIsLoading(false);
114
+ setState(ImageLoaderState.Loaded);
102
115
  onLoad(imgSrc);
103
- setFallBack(false);
104
116
  }, [imgSrc, onLoad]);
105
117
 
106
118
  const onErrorHandler = useCallback(() => {
107
- setIsLoading(false);
108
- setFallBack(true);
119
+ setState(ImageLoaderState.Failed);
109
120
  onError(imgSrc);
110
121
  }, [imgSrc, onError]);
111
122
 
112
123
  return (
113
124
  <div className={classes.container}>
114
- {isLoading && (
125
+ {state === ImageLoaderState.Loading && (
115
126
  <div className={classes.loader} style={customStyles}>
116
127
  <ContentLoader
117
128
  speed={speed}
@@ -123,14 +134,14 @@ export const ImageLoader: React.FC<ImageLoaderProps> = ({
123
134
  </ContentLoader>
124
135
  </div>
125
136
  )}
126
- {(imgSrc !== undefined || srcTimedOut) && (
127
- <div className={classes.imageContainer}>
137
+ <div className={classes.imageContainer}>
138
+ {state !== ImageLoaderState.Failed && imgSrc !== undefined && (
128
139
  <img
129
- src={String(imgSrc)}
140
+ src={imgSrc}
130
141
  height={imgHeight}
131
142
  width={imgWidth}
132
143
  style={{
133
- display: isLoading ? 'none' : fallBack ? 'none' : 'block',
144
+ display: state === ImageLoaderState.Loading ? 'none' : 'unset',
134
145
  objectFit: 'contain',
135
146
  maxWidth: '100%',
136
147
  }}
@@ -141,23 +152,23 @@ export const ImageLoader: React.FC<ImageLoaderProps> = ({
141
152
  data-test-id="image-loader-img"
142
153
  className={imageClassName}
143
154
  />
144
- {fallBack &&
145
- (!fallbackSrc ? (
146
- <div
147
- className={clsx(classes.container, classes.fallback)}
148
- style={customStyles}
149
- ></div>
150
- ) : (
151
- <img
152
- className={classes.fallBackImage}
153
- src={String(fallbackSrc)}
154
- height={imgHeight}
155
- width={imgWidth}
156
- />
157
- ))}
158
- {!isLoading && !fallBack && children}
159
- </div>
160
- )}
155
+ )}
156
+ {state === ImageLoaderState.Failed &&
157
+ (fallbackSrc ? (
158
+ <img
159
+ className={classes.fallBackImage}
160
+ src={String(fallbackSrc)}
161
+ height={imgHeight}
162
+ width={imgWidth}
163
+ />
164
+ ) : (
165
+ <div
166
+ className={clsx(classes.container, classes.fallback)}
167
+ style={customStyles}
168
+ ></div>
169
+ ))}
170
+ {state === ImageLoaderState.Loaded && children}
171
+ </div>
161
172
  </div>
162
173
  );
163
174
  };