@performant-software/semantic-components 0.5.14 → 0.5.16-beta.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/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/main.css +43 -0
- package/package.json +3 -3
- package/src/components/AudioPlayer.css +3 -0
- package/src/components/AudioPlayer.js +54 -0
- package/src/components/LazyAudio.css +23 -0
- package/src/components/LazyAudio.js +140 -0
- package/src/components/LazyDocument.css +2 -0
- package/src/components/LazyDocument.js +25 -15
- package/src/components/LazyImage.css +3 -1
- package/src/components/LazyImage.js +30 -11
- package/src/components/LazyLoader.css +7 -0
- package/src/components/LazyLoader.js +28 -0
- package/src/components/LazyVideo.css +8 -1
- package/src/components/LazyVideo.js +30 -5
- package/src/components/PhotoViewer.js +38 -25
- package/src/components/VideoPlayer.js +23 -2
- package/src/i18n/en.json +29 -0
- package/src/index.js +2 -0
- package/types/components/AudioPlayer.js.flow +54 -0
- package/types/components/LazyAudio.js.flow +140 -0
- package/types/components/LazyDocument.js.flow +25 -15
- package/types/components/LazyImage.js.flow +30 -11
- package/types/components/LazyLoader.js.flow +28 -0
- package/types/components/LazyVideo.js.flow +30 -5
- package/types/components/PhotoViewer.js.flow +38 -25
- package/types/components/VideoPlayer.js.flow +23 -2
- package/types/index.js.flow +2 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { Image, Modal } from 'semantic-ui-react';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { Image, Message, Modal } from 'semantic-ui-react';
|
|
5
5
|
import ModalContext from '../context/ModalContext';
|
|
6
6
|
import './PhotoViewer.css';
|
|
7
|
+
import i18n from '../i18n/i18n';
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
9
10
|
alt?: string,
|
|
@@ -13,29 +14,41 @@ type Props = {
|
|
|
13
14
|
size?: string
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
const PhotoViewer = (props: Props) =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
)
|
|
17
|
+
const PhotoViewer = (props: Props) => {
|
|
18
|
+
const [error, setError] = useState(false);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<ModalContext.Consumer>
|
|
22
|
+
{(mountNode) => (
|
|
23
|
+
<Modal
|
|
24
|
+
centered={false}
|
|
25
|
+
className='photo-viewer'
|
|
26
|
+
closeIcon
|
|
27
|
+
mountNode={mountNode}
|
|
28
|
+
onClose={props.onClose.bind(this)}
|
|
29
|
+
open={props.open}
|
|
30
|
+
size={props.size}
|
|
31
|
+
>
|
|
32
|
+
<Modal.Content>
|
|
33
|
+
{ error && (
|
|
34
|
+
<Message
|
|
35
|
+
content={i18n.t('PhotoViewer.errors.path.content', { path: props.image })}
|
|
36
|
+
header={i18n.t('PhotoViewer.errors.path.header')}
|
|
37
|
+
icon='exclamation circle'
|
|
38
|
+
/>
|
|
39
|
+
)}
|
|
40
|
+
<Image
|
|
41
|
+
alt={props.alt}
|
|
42
|
+
fluid
|
|
43
|
+
onError={() => setError(true)}
|
|
44
|
+
src={props.image}
|
|
45
|
+
/>
|
|
46
|
+
</Modal.Content>
|
|
47
|
+
</Modal>
|
|
48
|
+
)}
|
|
49
|
+
</ModalContext.Consumer>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
39
52
|
|
|
40
53
|
PhotoViewer.defaultProps = {
|
|
41
54
|
size: 'small'
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import React, {
|
|
4
|
-
|
|
3
|
+
import React, {
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
type Element
|
|
8
|
+
} from 'react';
|
|
9
|
+
import {
|
|
10
|
+
Embed,
|
|
11
|
+
Message,
|
|
12
|
+
Modal,
|
|
13
|
+
Ref
|
|
14
|
+
} from 'semantic-ui-react';
|
|
5
15
|
import ModalContext from '../context/ModalContext';
|
|
6
16
|
import './VideoPlayer.css';
|
|
17
|
+
import i18n from '../i18n/i18n';
|
|
7
18
|
|
|
8
19
|
type Props = {
|
|
9
20
|
autoPlay?: boolean,
|
|
@@ -18,6 +29,8 @@ type Props = {
|
|
|
18
29
|
};
|
|
19
30
|
|
|
20
31
|
const VideoPlayer = (props: Props) => {
|
|
32
|
+
const [error, setError] = useState(false);
|
|
33
|
+
|
|
21
34
|
const embedRef = useRef();
|
|
22
35
|
|
|
23
36
|
/**
|
|
@@ -46,6 +59,13 @@ const VideoPlayer = (props: Props) => {
|
|
|
46
59
|
size={props.size}
|
|
47
60
|
>
|
|
48
61
|
<Modal.Content>
|
|
62
|
+
{ error && (
|
|
63
|
+
<Message
|
|
64
|
+
content={i18n.t('VideoPlayer.errors.path.content', { path: props.video })}
|
|
65
|
+
header={i18n.t('VideoPlayer.errors.path.header')}
|
|
66
|
+
icon='exclamation circle'
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
49
69
|
{ props.embedded && (
|
|
50
70
|
<Ref
|
|
51
71
|
innerRef={embedRef}
|
|
@@ -63,6 +83,7 @@ const VideoPlayer = (props: Props) => {
|
|
|
63
83
|
<video
|
|
64
84
|
autoPlay={props.autoPlay}
|
|
65
85
|
controls
|
|
86
|
+
onError={() => setError(true)}
|
|
66
87
|
src={props.video}
|
|
67
88
|
/>
|
|
68
89
|
)}
|
package/src/i18n/en.json
CHANGED
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
"AccordionSelector": {
|
|
9
9
|
"title": "Select Items"
|
|
10
10
|
},
|
|
11
|
+
"AudioPlayer": {
|
|
12
|
+
"errors": {
|
|
13
|
+
"path": {
|
|
14
|
+
"content": "Please check the audio path: {{path}}",
|
|
15
|
+
"header": "There was a problem loading the audio"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
11
19
|
"Common": {
|
|
12
20
|
"buttons": {
|
|
13
21
|
"add": "Add",
|
|
@@ -135,6 +143,11 @@
|
|
|
135
143
|
"value": "Value"
|
|
136
144
|
}
|
|
137
145
|
},
|
|
146
|
+
"LazyAudio": {
|
|
147
|
+
"buttons": {
|
|
148
|
+
"play": "Play"
|
|
149
|
+
}
|
|
150
|
+
},
|
|
138
151
|
"LazyDocument": {
|
|
139
152
|
"buttons": {
|
|
140
153
|
"download": "Download"
|
|
@@ -193,6 +206,14 @@
|
|
|
193
206
|
"loginErrorHeader": "Invalid Credentials",
|
|
194
207
|
"password": "Password"
|
|
195
208
|
},
|
|
209
|
+
"PhotoViewer": {
|
|
210
|
+
"errors": {
|
|
211
|
+
"path": {
|
|
212
|
+
"content": "Please check the image path: {{path}}",
|
|
213
|
+
"header": "There was a problem loading the image"
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
196
217
|
"ReferenceCodeFormLabel": {
|
|
197
218
|
"content": "The values in this list can be edited via the {{name}} reference table."
|
|
198
219
|
},
|
|
@@ -240,6 +261,14 @@
|
|
|
240
261
|
},
|
|
241
262
|
"title": "Select Frame"
|
|
242
263
|
},
|
|
264
|
+
"VideoPlayer": {
|
|
265
|
+
"errors": {
|
|
266
|
+
"path": {
|
|
267
|
+
"content": "Please check the video path: {{path}}",
|
|
268
|
+
"header": "There was a problem loading the video"
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
243
272
|
"ViewXML": {
|
|
244
273
|
"buttons": {
|
|
245
274
|
"view": "View XML"
|
package/src/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { default as AccordionList } from './components/AccordionList';
|
|
|
9
9
|
export { default as AccordionSelector } from './components/AccordionSelector';
|
|
10
10
|
export { default as ArrowButtons } from './components/ArrowButtons';
|
|
11
11
|
export { default as AssociatedDropdown } from './components/AssociatedDropdown';
|
|
12
|
+
export { default as AudioPlayer } from './components/AudioPlayer';
|
|
12
13
|
export { default as BooleanIcon } from './components/BooleanIcon';
|
|
13
14
|
export { default as CancelButton } from './components/CancelButton';
|
|
14
15
|
export { default as ColorButton } from './components/ColorButton';
|
|
@@ -39,6 +40,7 @@ export { default as ItemList } from './components/ItemList';
|
|
|
39
40
|
export { default as Items } from './components/Items';
|
|
40
41
|
export { default as KeyboardField } from './components/KeyboardField';
|
|
41
42
|
export { default as KeyValuePairs } from './components/KeyValuePairs';
|
|
43
|
+
export { default as LazyAudio } from './components/LazyAudio';
|
|
42
44
|
export { default as LazyDocument } from './components/LazyDocument';
|
|
43
45
|
export { default as LazyImage } from './components/LazyImage';
|
|
44
46
|
export { default as LazyVideo } from './components/LazyVideo';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { Button, Message, Modal } from 'semantic-ui-react';
|
|
5
|
+
import i18n from '../i18n/i18n';
|
|
6
|
+
import ModalContext from '../context/ModalContext';
|
|
7
|
+
import './AudioPlayer.css';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
centered?: boolean,
|
|
11
|
+
onClose: () => void,
|
|
12
|
+
open: boolean,
|
|
13
|
+
src: string
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const AudioPlayer = (props: Props) => {
|
|
17
|
+
const [error, setError] = useState(false);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<ModalContext.Consumer>
|
|
21
|
+
{(mountNode) => (
|
|
22
|
+
<Modal
|
|
23
|
+
centered={props.centered}
|
|
24
|
+
className='audio-player'
|
|
25
|
+
mountNode={mountNode}
|
|
26
|
+
open={props.open}
|
|
27
|
+
>
|
|
28
|
+
<Modal.Content>
|
|
29
|
+
{ error && (
|
|
30
|
+
<Message
|
|
31
|
+
content={i18n.t('AudioPlayer.errors.path.content', { path: props.src })}
|
|
32
|
+
header={i18n.t('AudioPlayer.errors.path.header')}
|
|
33
|
+
icon='exclamation circle'
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
<audio
|
|
37
|
+
controls
|
|
38
|
+
onError={() => setError(true)}
|
|
39
|
+
src={props.src}
|
|
40
|
+
/>
|
|
41
|
+
</Modal.Content>
|
|
42
|
+
<Modal.Actions>
|
|
43
|
+
<Button
|
|
44
|
+
content={i18n.t('Common.buttons.close')}
|
|
45
|
+
onClick={props.onClose}
|
|
46
|
+
/>
|
|
47
|
+
</Modal.Actions>
|
|
48
|
+
</Modal>
|
|
49
|
+
)}
|
|
50
|
+
</ModalContext.Consumer>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default AudioPlayer;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useState, type Node } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Dimmer,
|
|
7
|
+
Icon,
|
|
8
|
+
Image,
|
|
9
|
+
Loader,
|
|
10
|
+
Segment,
|
|
11
|
+
Transition,
|
|
12
|
+
Visibility
|
|
13
|
+
} from 'semantic-ui-react';
|
|
14
|
+
import i18n from '../i18n/i18n';
|
|
15
|
+
import AudioPlayer from './AudioPlayer';
|
|
16
|
+
import LazyLoader from './LazyLoader';
|
|
17
|
+
import './LazyAudio.css';
|
|
18
|
+
|
|
19
|
+
type Props = {
|
|
20
|
+
children?: Node,
|
|
21
|
+
dimmable: boolean,
|
|
22
|
+
duration?: number,
|
|
23
|
+
image?: any,
|
|
24
|
+
preview?: string,
|
|
25
|
+
size?: string,
|
|
26
|
+
src?: string
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const LazyAudio = (props: Props) => {
|
|
30
|
+
const [dimmer, setDimmer] = useState(false);
|
|
31
|
+
const [error, setError] = useState(false);
|
|
32
|
+
const [loaded, setLoaded] = useState(!props.preview);
|
|
33
|
+
const [modal, setModal] = useState(false);
|
|
34
|
+
const [visible, setVisible] = useState(false);
|
|
35
|
+
|
|
36
|
+
if (!visible) {
|
|
37
|
+
return (
|
|
38
|
+
<Visibility
|
|
39
|
+
as='span'
|
|
40
|
+
fireOnMount
|
|
41
|
+
onTopVisible={() => setVisible(true)}
|
|
42
|
+
>
|
|
43
|
+
<Loader
|
|
44
|
+
active
|
|
45
|
+
inline='centered'
|
|
46
|
+
size={props.size}
|
|
47
|
+
/>
|
|
48
|
+
</Visibility>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<>
|
|
54
|
+
<Transition
|
|
55
|
+
duration={props.duration}
|
|
56
|
+
visible
|
|
57
|
+
>
|
|
58
|
+
<Dimmer.Dimmable
|
|
59
|
+
as={Segment}
|
|
60
|
+
className='lazy-audio'
|
|
61
|
+
compact
|
|
62
|
+
onBlur={() => setDimmer(false)}
|
|
63
|
+
onMouseEnter={() => setDimmer(true)}
|
|
64
|
+
onMouseLeave={() => setDimmer(false)}
|
|
65
|
+
>
|
|
66
|
+
{ !loaded && (
|
|
67
|
+
<LazyLoader
|
|
68
|
+
active
|
|
69
|
+
size={props.size}
|
|
70
|
+
/>
|
|
71
|
+
)}
|
|
72
|
+
{ !error && props.preview && (
|
|
73
|
+
<Image
|
|
74
|
+
{...props.image}
|
|
75
|
+
onError={() => {
|
|
76
|
+
setError(true);
|
|
77
|
+
setLoaded(true);
|
|
78
|
+
}}
|
|
79
|
+
onLoad={() => {
|
|
80
|
+
setError(false);
|
|
81
|
+
setLoaded(true);
|
|
82
|
+
}}
|
|
83
|
+
size={props.size}
|
|
84
|
+
src={props.preview}
|
|
85
|
+
/>
|
|
86
|
+
)}
|
|
87
|
+
{ (error || !props.preview) && (
|
|
88
|
+
<Image
|
|
89
|
+
{...props.image}
|
|
90
|
+
className='placeholder-image'
|
|
91
|
+
size={props.size}
|
|
92
|
+
>
|
|
93
|
+
<Icon
|
|
94
|
+
name='file audio outline'
|
|
95
|
+
size='big'
|
|
96
|
+
/>
|
|
97
|
+
</Image>
|
|
98
|
+
)}
|
|
99
|
+
{ (props.src || props.children) && props.dimmable && (
|
|
100
|
+
<Dimmer
|
|
101
|
+
active={dimmer}
|
|
102
|
+
>
|
|
103
|
+
<div
|
|
104
|
+
className='buttons'
|
|
105
|
+
>
|
|
106
|
+
{ props.src && (
|
|
107
|
+
<Button
|
|
108
|
+
content={i18n.t('LazyAudio.buttons.play')}
|
|
109
|
+
icon='play circle outline'
|
|
110
|
+
onClick={() => setModal(true)}
|
|
111
|
+
primary
|
|
112
|
+
/>
|
|
113
|
+
)}
|
|
114
|
+
{ props.children }
|
|
115
|
+
</div>
|
|
116
|
+
</Dimmer>
|
|
117
|
+
)}
|
|
118
|
+
</Dimmer.Dimmable>
|
|
119
|
+
</Transition>
|
|
120
|
+
{ props.src && (
|
|
121
|
+
<AudioPlayer
|
|
122
|
+
onClose={() => setModal(false)}
|
|
123
|
+
open={modal}
|
|
124
|
+
size='large'
|
|
125
|
+
src={props.src}
|
|
126
|
+
/>
|
|
127
|
+
)}
|
|
128
|
+
</>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
LazyAudio.defaultProps = {
|
|
133
|
+
dimmable: true,
|
|
134
|
+
duration: 1000,
|
|
135
|
+
preview: undefined,
|
|
136
|
+
size: 'medium',
|
|
137
|
+
src: undefined
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export default LazyAudio;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import React, { useState,
|
|
3
|
+
import React, { useState, type Node } from 'react';
|
|
4
4
|
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack';
|
|
5
5
|
import {
|
|
6
6
|
Dimmer,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from 'semantic-ui-react';
|
|
14
14
|
import i18n from '../i18n/i18n';
|
|
15
15
|
import DownloadButton from './DownloadButton';
|
|
16
|
+
import LazyLoader from './LazyLoader';
|
|
16
17
|
import './LazyDocument.css';
|
|
17
18
|
|
|
18
19
|
type Props = {
|
|
@@ -20,23 +21,17 @@ type Props = {
|
|
|
20
21
|
dimmable?: boolean,
|
|
21
22
|
duration?: number,
|
|
22
23
|
image?: any,
|
|
24
|
+
pdf?: boolean,
|
|
23
25
|
preview?: ?string,
|
|
24
26
|
size?: string,
|
|
25
27
|
src?: string
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
const LazyDocument = (props: Props) => {
|
|
29
|
-
const [visible, setVisible] = useState(false);
|
|
30
31
|
const [dimmer, setDimmer] = useState(false);
|
|
31
|
-
const [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (props.src && !props.preview) {
|
|
35
|
-
fetch(props.src)
|
|
36
|
-
.then((response) => response.blob())
|
|
37
|
-
.then((blob) => setContentType(blob.type));
|
|
38
|
-
}
|
|
39
|
-
}, [props.preview, props.src]);
|
|
32
|
+
const [error, setError] = useState(false);
|
|
33
|
+
const [loaded, setLoaded] = useState(!props.preview);
|
|
34
|
+
const [visible, setVisible] = useState(false);
|
|
40
35
|
|
|
41
36
|
if (!visible) {
|
|
42
37
|
return (
|
|
@@ -68,14 +63,28 @@ const LazyDocument = (props: Props) => {
|
|
|
68
63
|
onMouseEnter={() => setDimmer(true)}
|
|
69
64
|
onMouseLeave={() => setDimmer(false)}
|
|
70
65
|
>
|
|
71
|
-
{
|
|
66
|
+
{ !loaded && (
|
|
67
|
+
<LazyLoader
|
|
68
|
+
active
|
|
69
|
+
size={props.size}
|
|
70
|
+
/>
|
|
71
|
+
)}
|
|
72
|
+
{ !error && props.preview && (
|
|
72
73
|
<Image
|
|
73
74
|
{...props.image}
|
|
75
|
+
onError={() => {
|
|
76
|
+
setError(true);
|
|
77
|
+
setLoaded(true);
|
|
78
|
+
}}
|
|
79
|
+
onLoad={() => {
|
|
80
|
+
setError(false);
|
|
81
|
+
setLoaded(true);
|
|
82
|
+
}}
|
|
74
83
|
src={props.preview}
|
|
75
84
|
size={props.size}
|
|
76
85
|
/>
|
|
77
86
|
)}
|
|
78
|
-
{ !props.preview && props.src &&
|
|
87
|
+
{ !props.preview && props.src && props.pdf && (
|
|
79
88
|
<Image
|
|
80
89
|
{...props.image}
|
|
81
90
|
size={props.size}
|
|
@@ -89,7 +98,7 @@ const LazyDocument = (props: Props) => {
|
|
|
89
98
|
</Document>
|
|
90
99
|
</Image>
|
|
91
100
|
)}
|
|
92
|
-
{ !props.preview && (
|
|
101
|
+
{ (error || (!props.preview && !(props.src && props.pdf))) && (
|
|
93
102
|
<Image
|
|
94
103
|
{...props.image}
|
|
95
104
|
className='placeholder-image'
|
|
@@ -113,7 +122,7 @@ const LazyDocument = (props: Props) => {
|
|
|
113
122
|
content={i18n.t('LazyDocument.buttons.download')}
|
|
114
123
|
icon='cloud download'
|
|
115
124
|
primary
|
|
116
|
-
url={props.src
|
|
125
|
+
url={props.src}
|
|
117
126
|
/>
|
|
118
127
|
)}
|
|
119
128
|
{ props.children }
|
|
@@ -129,6 +138,7 @@ const LazyDocument = (props: Props) => {
|
|
|
129
138
|
LazyDocument.defaultProps = {
|
|
130
139
|
dimmable: true,
|
|
131
140
|
duration: 1000,
|
|
141
|
+
pdf: false,
|
|
132
142
|
preview: undefined,
|
|
133
143
|
size: 'medium',
|
|
134
144
|
src: undefined
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
Visibility
|
|
13
13
|
} from 'semantic-ui-react';
|
|
14
14
|
import i18n from '../i18n/i18n';
|
|
15
|
+
import LazyLoader from './LazyLoader';
|
|
15
16
|
import PhotoViewer from './PhotoViewer';
|
|
16
17
|
import './LazyImage.css';
|
|
17
18
|
|
|
@@ -26,9 +27,11 @@ type Props = {
|
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
const LazyImage = (props: Props) => {
|
|
29
|
-
const [visible, setVisible] = useState(false);
|
|
30
|
-
const [modal, setModal] = useState(false);
|
|
31
30
|
const [dimmer, setDimmer] = useState(false);
|
|
31
|
+
const [error, setError] = useState(false);
|
|
32
|
+
const [loaded, setLoaded] = useState(!(props.src || props.preview));
|
|
33
|
+
const [modal, setModal] = useState(false);
|
|
34
|
+
const [visible, setVisible] = useState(false);
|
|
32
35
|
|
|
33
36
|
if (!visible) {
|
|
34
37
|
return (
|
|
@@ -60,14 +63,28 @@ const LazyImage = (props: Props) => {
|
|
|
60
63
|
onMouseEnter={() => setDimmer(true)}
|
|
61
64
|
onMouseLeave={() => setDimmer(false)}
|
|
62
65
|
>
|
|
63
|
-
{
|
|
66
|
+
{ !loaded && (
|
|
67
|
+
<LazyLoader
|
|
68
|
+
active
|
|
69
|
+
size={props.size}
|
|
70
|
+
/>
|
|
71
|
+
)}
|
|
72
|
+
{ !error && (props.preview || props.src) && (
|
|
64
73
|
<Image
|
|
65
74
|
{...props.image}
|
|
75
|
+
onError={() => {
|
|
76
|
+
setError(true);
|
|
77
|
+
setLoaded(true);
|
|
78
|
+
}}
|
|
79
|
+
onLoad={() => {
|
|
80
|
+
setError(false);
|
|
81
|
+
setLoaded(true);
|
|
82
|
+
}}
|
|
66
83
|
size={props.size}
|
|
67
84
|
src={props.preview || props.src}
|
|
68
85
|
/>
|
|
69
86
|
)}
|
|
70
|
-
{ !props.src && (
|
|
87
|
+
{ (error || !(props.preview || props.src)) && (
|
|
71
88
|
<Image
|
|
72
89
|
{...props.image}
|
|
73
90
|
className='placeholder-image'
|
|
@@ -79,7 +96,7 @@ const LazyImage = (props: Props) => {
|
|
|
79
96
|
/>
|
|
80
97
|
</Image>
|
|
81
98
|
)}
|
|
82
|
-
{ (props.src || props.children) && props.dimmable && (
|
|
99
|
+
{ !error && (props.src || props.children) && props.dimmable && (
|
|
83
100
|
<Dimmer
|
|
84
101
|
active={dimmer}
|
|
85
102
|
>
|
|
@@ -100,12 +117,14 @@ const LazyImage = (props: Props) => {
|
|
|
100
117
|
)}
|
|
101
118
|
</Dimmer.Dimmable>
|
|
102
119
|
</Transition>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
120
|
+
{ props.src && (
|
|
121
|
+
<PhotoViewer
|
|
122
|
+
image={props.src}
|
|
123
|
+
onClose={() => setModal(false)}
|
|
124
|
+
open={modal}
|
|
125
|
+
size='large'
|
|
126
|
+
/>
|
|
127
|
+
)}
|
|
109
128
|
</>
|
|
110
129
|
);
|
|
111
130
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Image, Loader } from 'semantic-ui-react';
|
|
5
|
+
import './LazyLoader.css';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
active: boolean,
|
|
9
|
+
size: string
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const LazyLoader = (props: Props) => (
|
|
13
|
+
<Image
|
|
14
|
+
className='lazy-loader'
|
|
15
|
+
size={props.size}
|
|
16
|
+
>
|
|
17
|
+
<Loader
|
|
18
|
+
active={props.active}
|
|
19
|
+
/>
|
|
20
|
+
</Image>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
LazyLoader.defaultProps = {
|
|
24
|
+
active: false,
|
|
25
|
+
size: 'small'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default LazyLoader;
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
Visibility
|
|
13
13
|
} from 'semantic-ui-react';
|
|
14
14
|
import i18n from '../i18n/i18n';
|
|
15
|
+
import LazyLoader from './LazyLoader';
|
|
15
16
|
import VideoPlayer from './VideoPlayer';
|
|
16
17
|
import './LazyVideo.css';
|
|
17
18
|
|
|
@@ -29,9 +30,11 @@ type Props = {
|
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
const LazyVideo = (props: Props) => {
|
|
32
|
-
const [visible, setVisible] = useState(false);
|
|
33
|
-
const [modal, setModal] = useState(false);
|
|
34
33
|
const [dimmer, setDimmer] = useState(false);
|
|
34
|
+
const [error, setError] = useState(false);
|
|
35
|
+
const [loaded, setLoaded] = useState(!(props.preview || props.src));
|
|
36
|
+
const [modal, setModal] = useState(false);
|
|
37
|
+
const [visible, setVisible] = useState(false);
|
|
35
38
|
|
|
36
39
|
if (!visible) {
|
|
37
40
|
return (
|
|
@@ -63,24 +66,46 @@ const LazyVideo = (props: Props) => {
|
|
|
63
66
|
onMouseEnter={() => setDimmer(true)}
|
|
64
67
|
onMouseLeave={() => setDimmer(false)}
|
|
65
68
|
>
|
|
66
|
-
{
|
|
69
|
+
{ !loaded && (
|
|
70
|
+
<LazyLoader
|
|
71
|
+
active
|
|
72
|
+
size={props.size}
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
{ !error && props.preview && (
|
|
67
76
|
<Image
|
|
68
77
|
{...props.image}
|
|
78
|
+
onError={() => {
|
|
79
|
+
setError(true);
|
|
80
|
+
setLoaded(true);
|
|
81
|
+
}}
|
|
82
|
+
onLoad={() => {
|
|
83
|
+
setError(false);
|
|
84
|
+
setLoaded(true);
|
|
85
|
+
}}
|
|
69
86
|
src={props.preview}
|
|
70
87
|
size={props.size}
|
|
71
88
|
/>
|
|
72
89
|
)}
|
|
73
|
-
{ !props.preview && props.src && (
|
|
90
|
+
{ !error && !props.preview && props.src && (
|
|
74
91
|
<Image
|
|
75
92
|
{...props.image}
|
|
76
93
|
size={props.size}
|
|
77
94
|
>
|
|
78
95
|
<video
|
|
96
|
+
onError={() => {
|
|
97
|
+
setError(true);
|
|
98
|
+
setLoaded(true);
|
|
99
|
+
}}
|
|
100
|
+
onLoadedData={() => {
|
|
101
|
+
setError(false);
|
|
102
|
+
setLoaded(true);
|
|
103
|
+
}}
|
|
79
104
|
src={props.src}
|
|
80
105
|
/>
|
|
81
106
|
</Image>
|
|
82
107
|
)}
|
|
83
|
-
{ !props.preview && !props.src && (
|
|
108
|
+
{ (error || (!props.preview && !props.src)) && (
|
|
84
109
|
<Image
|
|
85
110
|
{...props.image}
|
|
86
111
|
className='placeholder-image'
|