@performant-software/semantic-components 1.0.16 → 1.0.17

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/main.css CHANGED
@@ -601,6 +601,37 @@ div.react-calendar {
601
601
  aspect-ratio: 1;
602
602
  }
603
603
 
604
+ .image-carousel > .content {
605
+ height: 100%;
606
+ width: 100%;
607
+ }
608
+ .image-carousel > .content > .ui.grid {
609
+ height: 100%;
610
+ }
611
+ .image-carousel > .content > .ui.grid > .row.image-content {
612
+ flex-grow: 1;
613
+ }
614
+ .image-carousel > .content > .ui.grid > .row.image-content > .column {
615
+ display: flex;
616
+ justify-content: center;
617
+ align-items: center;
618
+ }
619
+ .image-carousel > .content > .ui.grid > .row.image-content > .column.image-container {
620
+ flex-grow: 1;
621
+ }
622
+ .image-carousel > .content > .ui.grid > .row.image-content > .column.image-container img {
623
+ width: 100%;
624
+ height: auto;
625
+ max-height: 70vh;
626
+ object-fit: contain;
627
+ }
628
+ .image-carousel .ui.button,
629
+ .image-carousel .ui.button:hover {
630
+ border: none;
631
+ background: none;
632
+ color: #FFFFFF;
633
+ }
634
+
604
635
  .item-list {
605
636
  margin: 1em 0em 1em 0em;
606
637
  }
@@ -685,6 +716,9 @@ div.react-calendar {
685
716
  width: 100% !important;
686
717
  height: 100% !important;
687
718
  }
719
+ .lazy-document > .image.hidden {
720
+ display: none;
721
+ }
688
722
 
689
723
  .photo-viewer {
690
724
  padding: 30px;
@@ -713,6 +747,9 @@ div.react-calendar {
713
747
  padding-bottom: 20%;
714
748
  text-align: center;
715
749
  }
750
+ .lazy-image > .image.hidden {
751
+ display: none;
752
+ }
716
753
 
717
754
  .video-player video {
718
755
  width: 100%;
@@ -745,6 +782,9 @@ div.react-calendar {
745
782
  display: table;
746
783
  width: 100%;
747
784
  }
785
+ .lazy-video > .image.hidden {
786
+ display: none;
787
+ }
748
788
 
749
789
  .listLoader.ui.segment {
750
790
  position: absolute;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@performant-software/semantic-components",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "A package of shared components based on the Semantic UI Framework.",
5
5
  "license": "MIT",
6
6
  "main": "./build/index.js",
@@ -12,7 +12,7 @@
12
12
  "build": "webpack --mode production && flow-copy-source -v src types"
13
13
  },
14
14
  "dependencies": {
15
- "@performant-software/shared-components": "^1.0.16",
15
+ "@performant-software/shared-components": "^1.0.17",
16
16
  "@react-google-maps/api": "^2.8.1",
17
17
  "axios": "^0.26.1",
18
18
  "i18next": "^19.4.4",
@@ -0,0 +1,36 @@
1
+ .image-carousel > .content {
2
+ height: 100%;
3
+ width: 100%;
4
+ }
5
+
6
+ .image-carousel > .content > .ui.grid {
7
+ height: 100%;
8
+ }
9
+
10
+ .image-carousel > .content > .ui.grid > .row.image-content {
11
+ flex-grow: 1;
12
+ }
13
+
14
+ .image-carousel > .content > .ui.grid > .row.image-content > .column {
15
+ display: flex;
16
+ justify-content: center;
17
+ align-items: center;
18
+ }
19
+
20
+ .image-carousel > .content > .ui.grid > .row.image-content > .column.image-container {
21
+ flex-grow: 1;
22
+ }
23
+
24
+ .image-carousel > .content > .ui.grid > .row.image-content > .column.image-container img {
25
+ width: 100%;
26
+ height: auto;
27
+ max-height: 70vh;
28
+ object-fit: contain;
29
+ }
30
+
31
+ .image-carousel .ui.button,
32
+ .image-carousel .ui.button:hover {
33
+ border: none;
34
+ background: none;
35
+ color: #FFFFFF;
36
+ }
@@ -0,0 +1,154 @@
1
+ // @flow
2
+
3
+ import React, {
4
+ useCallback,
5
+ useEffect,
6
+ useMemo,
7
+ useState
8
+ } from 'react';
9
+ import {
10
+ Button,
11
+ Dimmer,
12
+ Grid,
13
+ Image,
14
+ Loader,
15
+ Transition
16
+ } from 'semantic-ui-react';
17
+ import './ImageCarousel.css';
18
+
19
+ type ImageType = {
20
+ caption?: string,
21
+ src: string
22
+ };
23
+
24
+ type Props = {
25
+ images: Array<ImageType>,
26
+ onClose: () => void
27
+ };
28
+
29
+ const ImageCarousel = (props: Props) => {
30
+ const [currentIndex, setCurrentIndex] = useState(0);
31
+ const [visible, setVisible] = useState(true);
32
+
33
+ /**
34
+ * Sets the current image based on the current index.
35
+ *
36
+ * @type {*}
37
+ */
38
+ const image = useMemo(() => {
39
+ let value;
40
+
41
+ if (props.images && props.images.length > currentIndex) {
42
+ value = props.images[currentIndex];
43
+ }
44
+
45
+ return value;
46
+ }, [currentIndex, props.images]);
47
+
48
+ /**
49
+ * Sets the new index value.
50
+ *
51
+ * @type {(function(*): void)|*}
52
+ */
53
+ const onIndexChange = useCallback((increment) => {
54
+ const newIndex = currentIndex + increment;
55
+
56
+ if (newIndex >= 0 && newIndex < props.images.length) {
57
+ setCurrentIndex(newIndex);
58
+ setVisible(false);
59
+ }
60
+ }, [currentIndex, props.images]);
61
+
62
+ /**
63
+ * Sets up the component when initially mounted.
64
+ */
65
+ useEffect(() => {
66
+ // Disabled scrolling on the page when carousel is visible.
67
+ if (document.body) {
68
+ document.body.style.overflow = 'hidden';
69
+ }
70
+
71
+ return () => {
72
+ // Re-enable scrolling
73
+ if (document.body) {
74
+ document.body.style.overflow = 'auto';
75
+ }
76
+ };
77
+ }, []);
78
+
79
+ return (
80
+ <Dimmer
81
+ active
82
+ className='image-carousel'
83
+ page
84
+ >
85
+ <Grid
86
+ padded
87
+ >
88
+ <Grid.Row>
89
+ <Grid.Column
90
+ textAlign='right'
91
+ >
92
+ <Button
93
+ icon='times'
94
+ onClick={props.onClose}
95
+ size='huge'
96
+ />
97
+ </Grid.Column>
98
+ </Grid.Row>
99
+ <Grid.Row
100
+ className='image-content'
101
+ >
102
+ <Grid.Column>
103
+ { props.images && props.images.length > 1 && (
104
+ <Button
105
+ disabled={currentIndex === 0}
106
+ icon='chevron left'
107
+ onClick={() => onIndexChange(-1)}
108
+ size='massive'
109
+ />
110
+ )}
111
+ </Grid.Column>
112
+ <Grid.Column
113
+ className='image-container'
114
+ >
115
+ { !visible && (
116
+ <Loader
117
+ active
118
+ />
119
+ )}
120
+ <Transition
121
+ animation='fade'
122
+ duration={500}
123
+ visible={visible}
124
+ >
125
+ <Image
126
+ src={image?.src}
127
+ onLoad={() => setVisible(true)}
128
+ />
129
+ </Transition>
130
+ </Grid.Column>
131
+ <Grid.Column>
132
+ { props.images && props.images.length > 1 && (
133
+ <Button
134
+ disabled={currentIndex === props.images.length - 1}
135
+ icon='chevron right'
136
+ onClick={() => onIndexChange(1)}
137
+ size='massive'
138
+ />
139
+ )}
140
+ </Grid.Column>
141
+ </Grid.Row>
142
+ <Grid.Row>
143
+ <Grid.Column
144
+ textAlign='center'
145
+ >
146
+ { image?.caption }
147
+ </Grid.Column>
148
+ </Grid.Row>
149
+ </Grid>
150
+ </Dimmer>
151
+ );
152
+ };
153
+
154
+ export default ImageCarousel;
@@ -26,3 +26,7 @@
26
26
  width: 100% !important;
27
27
  height: 100% !important;
28
28
  }
29
+
30
+ .lazy-document > .image.hidden {
31
+ display: none;
32
+ }
@@ -1,6 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, { useState, type Node } from 'react';
3
+ import React, { useCallback, useState, type Node } from 'react';
4
4
  import { pdfjs, Document, Page } from 'react-pdf';
5
5
  import {
6
6
  Dimmer,
@@ -38,6 +38,25 @@ const LazyDocument = (props: Props) => {
38
38
  const [loaded, setLoaded] = useState(!props.preview);
39
39
  const [visible, setVisible] = useState(false);
40
40
 
41
+ /**
42
+ * Returns the list of class names for the image component.
43
+ *
44
+ * @type {function(*=): []}
45
+ */
46
+ const getClassNames = useCallback((defaultClass = null) => {
47
+ const classNames = [];
48
+
49
+ if (defaultClass) {
50
+ classNames.push(defaultClass);
51
+ }
52
+
53
+ if (!loaded) {
54
+ classNames.push('hidden');
55
+ }
56
+
57
+ return classNames.join(' ');
58
+ }, [loaded]);
59
+
41
60
  if (!visible) {
42
61
  return (
43
62
  <Visibility
@@ -77,6 +96,7 @@ const LazyDocument = (props: Props) => {
77
96
  { !error && props.preview && (
78
97
  <Image
79
98
  {...props.image}
99
+ className={getClassNames()}
80
100
  onError={() => {
81
101
  setError(true);
82
102
  setLoaded(true);
@@ -92,6 +112,7 @@ const LazyDocument = (props: Props) => {
92
112
  { !error && loaded && !props.preview && props.src && props.pdf && (
93
113
  <Image
94
114
  {...props.image}
115
+ className={getClassNames()}
95
116
  size={props.size}
96
117
  >
97
118
  <Document
@@ -107,7 +128,7 @@ const LazyDocument = (props: Props) => {
107
128
  { (error || (!props.preview && !(props.src && props.pdf))) && (
108
129
  <Image
109
130
  {...props.image}
110
- className='placeholder-image'
131
+ className={getClassNames('placeholder-image')}
111
132
  size={props.size}
112
133
  >
113
134
  <Icon
@@ -21,3 +21,7 @@
21
21
  padding-bottom: 20%;
22
22
  text-align: center;
23
23
  }
24
+
25
+ .lazy-image > .image.hidden {
26
+ display: none;
27
+ }
@@ -1,6 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, { useState, type Node } from 'react';
3
+ import React, { useCallback, useState, type Node } from 'react';
4
4
  import {
5
5
  Button,
6
6
  Dimmer,
@@ -36,6 +36,25 @@ const LazyImage = (props: Props) => {
36
36
  const [modal, setModal] = useState(false);
37
37
  const [visible, setVisible] = useState(false);
38
38
 
39
+ /**
40
+ * Returns the list of class names for the image component.
41
+ *
42
+ * @type {function(*=): []}
43
+ */
44
+ const getClassNames = useCallback((defaultClass = null) => {
45
+ const classNames = [];
46
+
47
+ if (defaultClass) {
48
+ classNames.push(defaultClass);
49
+ }
50
+
51
+ if (!loaded) {
52
+ classNames.push('hidden');
53
+ }
54
+
55
+ return classNames.join(' ');
56
+ }, [loaded]);
57
+
39
58
  if (!visible) {
40
59
  return (
41
60
  <Visibility
@@ -75,6 +94,7 @@ const LazyImage = (props: Props) => {
75
94
  { !error && (props.preview || props.src) && (
76
95
  <Image
77
96
  {...props.image}
97
+ className={getClassNames()}
78
98
  onError={() => {
79
99
  setError(true);
80
100
  setLoaded(true);
@@ -90,7 +110,7 @@ const LazyImage = (props: Props) => {
90
110
  { (error || !(props.preview || props.src)) && (
91
111
  <Image
92
112
  {...props.image}
93
- className='placeholder-image'
113
+ className={getClassNames('placeholder-image')}
94
114
  size={props.size}
95
115
  >
96
116
  <Icon
@@ -26,3 +26,7 @@
26
26
  display: table;
27
27
  width: 100%;
28
28
  }
29
+
30
+ .lazy-video > .image.hidden {
31
+ display: none;
32
+ }
@@ -1,6 +1,11 @@
1
1
  // @flow
2
2
 
3
- import React, { useState, type Element, type Node } from 'react';
3
+ import React, {
4
+ useCallback,
5
+ useState,
6
+ type Element,
7
+ type Node
8
+ } from 'react';
4
9
  import {
5
10
  Button,
6
11
  Dimmer,
@@ -39,6 +44,25 @@ const LazyVideo = (props: Props) => {
39
44
  const [modal, setModal] = useState(false);
40
45
  const [visible, setVisible] = useState(false);
41
46
 
47
+ /**
48
+ * Returns the list of class names for the image component.
49
+ *
50
+ * @type {function(*=): []}
51
+ */
52
+ const getClassNames = useCallback((defaultClass = null) => {
53
+ const classNames = [];
54
+
55
+ if (defaultClass) {
56
+ classNames.push(defaultClass);
57
+ }
58
+
59
+ if (!loaded) {
60
+ classNames.push('hidden');
61
+ }
62
+
63
+ return classNames.join(' ');
64
+ }, [loaded]);
65
+
42
66
  if (!visible) {
43
67
  return (
44
68
  <Visibility
@@ -78,6 +102,7 @@ const LazyVideo = (props: Props) => {
78
102
  { !error && props.preview && (
79
103
  <Image
80
104
  {...props.image}
105
+ className={getClassNames()}
81
106
  onError={() => {
82
107
  setError(true);
83
108
  setLoaded(true);
@@ -93,6 +118,7 @@ const LazyVideo = (props: Props) => {
93
118
  { !error && !props.preview && props.src && (
94
119
  <Image
95
120
  {...props.image}
121
+ className={getClassNames()}
96
122
  size={props.size}
97
123
  >
98
124
  <video
@@ -111,7 +137,7 @@ const LazyVideo = (props: Props) => {
111
137
  { (error || (!props.preview && !props.src)) && (
112
138
  <Image
113
139
  {...props.image}
114
- className='placeholder-image'
140
+ className={getClassNames('placeholder-image')}
115
141
  size={props.size}
116
142
  >
117
143
  <Icon
package/src/index.js CHANGED
@@ -45,6 +45,7 @@ export { default as GoogleMap } from './components/GoogleMap';
45
45
  export { default as GooglePlacesSearch } from './components/GooglePlacesSearch';
46
46
  export { default as HorizontalCards } from './components/HorizontalCards';
47
47
  export { default as IIIFModal } from './components/IIIFModal';
48
+ export { default as ImageCarousel } from './components/ImageCarousel';
48
49
  export { default as ItemCollection } from './components/ItemCollection';
49
50
  export { default as ItemList } from './components/ItemList';
50
51
  export { default as Items } from './components/Items';
@@ -1,6 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, { useState, type Node } from 'react';
3
+ import React, { useCallback, useState, type Node } from 'react';
4
4
  import { pdfjs, Document, Page } from 'react-pdf';
5
5
  import {
6
6
  Dimmer,
@@ -38,6 +38,25 @@ const LazyDocument = (props: Props) => {
38
38
  const [loaded, setLoaded] = useState(!props.preview);
39
39
  const [visible, setVisible] = useState(false);
40
40
 
41
+ /**
42
+ * Returns the list of class names for the image component.
43
+ *
44
+ * @type {function(*=): []}
45
+ */
46
+ const getClassNames = useCallback((defaultClass = null) => {
47
+ const classNames = [];
48
+
49
+ if (defaultClass) {
50
+ classNames.push(defaultClass);
51
+ }
52
+
53
+ if (!loaded) {
54
+ classNames.push('hidden');
55
+ }
56
+
57
+ return classNames.join(' ');
58
+ }, [loaded]);
59
+
41
60
  if (!visible) {
42
61
  return (
43
62
  <Visibility
@@ -77,6 +96,7 @@ const LazyDocument = (props: Props) => {
77
96
  { !error && props.preview && (
78
97
  <Image
79
98
  {...props.image}
99
+ className={getClassNames()}
80
100
  onError={() => {
81
101
  setError(true);
82
102
  setLoaded(true);
@@ -92,6 +112,7 @@ const LazyDocument = (props: Props) => {
92
112
  { !error && loaded && !props.preview && props.src && props.pdf && (
93
113
  <Image
94
114
  {...props.image}
115
+ className={getClassNames()}
95
116
  size={props.size}
96
117
  >
97
118
  <Document
@@ -107,7 +128,7 @@ const LazyDocument = (props: Props) => {
107
128
  { (error || (!props.preview && !(props.src && props.pdf))) && (
108
129
  <Image
109
130
  {...props.image}
110
- className='placeholder-image'
131
+ className={getClassNames('placeholder-image')}
111
132
  size={props.size}
112
133
  >
113
134
  <Icon
@@ -1,6 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, { useState, type Node } from 'react';
3
+ import React, { useCallback, useState, type Node } from 'react';
4
4
  import {
5
5
  Button,
6
6
  Dimmer,
@@ -36,6 +36,25 @@ const LazyImage = (props: Props) => {
36
36
  const [modal, setModal] = useState(false);
37
37
  const [visible, setVisible] = useState(false);
38
38
 
39
+ /**
40
+ * Returns the list of class names for the image component.
41
+ *
42
+ * @type {function(*=): []}
43
+ */
44
+ const getClassNames = useCallback((defaultClass = null) => {
45
+ const classNames = [];
46
+
47
+ if (defaultClass) {
48
+ classNames.push(defaultClass);
49
+ }
50
+
51
+ if (!loaded) {
52
+ classNames.push('hidden');
53
+ }
54
+
55
+ return classNames.join(' ');
56
+ }, [loaded]);
57
+
39
58
  if (!visible) {
40
59
  return (
41
60
  <Visibility
@@ -75,6 +94,7 @@ const LazyImage = (props: Props) => {
75
94
  { !error && (props.preview || props.src) && (
76
95
  <Image
77
96
  {...props.image}
97
+ className={getClassNames()}
78
98
  onError={() => {
79
99
  setError(true);
80
100
  setLoaded(true);
@@ -90,7 +110,7 @@ const LazyImage = (props: Props) => {
90
110
  { (error || !(props.preview || props.src)) && (
91
111
  <Image
92
112
  {...props.image}
93
- className='placeholder-image'
113
+ className={getClassNames('placeholder-image')}
94
114
  size={props.size}
95
115
  >
96
116
  <Icon
@@ -1,6 +1,11 @@
1
1
  // @flow
2
2
 
3
- import React, { useState, type Element, type Node } from 'react';
3
+ import React, {
4
+ useCallback,
5
+ useState,
6
+ type Element,
7
+ type Node
8
+ } from 'react';
4
9
  import {
5
10
  Button,
6
11
  Dimmer,
@@ -39,6 +44,25 @@ const LazyVideo = (props: Props) => {
39
44
  const [modal, setModal] = useState(false);
40
45
  const [visible, setVisible] = useState(false);
41
46
 
47
+ /**
48
+ * Returns the list of class names for the image component.
49
+ *
50
+ * @type {function(*=): []}
51
+ */
52
+ const getClassNames = useCallback((defaultClass = null) => {
53
+ const classNames = [];
54
+
55
+ if (defaultClass) {
56
+ classNames.push(defaultClass);
57
+ }
58
+
59
+ if (!loaded) {
60
+ classNames.push('hidden');
61
+ }
62
+
63
+ return classNames.join(' ');
64
+ }, [loaded]);
65
+
42
66
  if (!visible) {
43
67
  return (
44
68
  <Visibility
@@ -78,6 +102,7 @@ const LazyVideo = (props: Props) => {
78
102
  { !error && props.preview && (
79
103
  <Image
80
104
  {...props.image}
105
+ className={getClassNames()}
81
106
  onError={() => {
82
107
  setError(true);
83
108
  setLoaded(true);
@@ -93,6 +118,7 @@ const LazyVideo = (props: Props) => {
93
118
  { !error && !props.preview && props.src && (
94
119
  <Image
95
120
  {...props.image}
121
+ className={getClassNames()}
96
122
  size={props.size}
97
123
  >
98
124
  <video
@@ -111,7 +137,7 @@ const LazyVideo = (props: Props) => {
111
137
  { (error || (!props.preview && !props.src)) && (
112
138
  <Image
113
139
  {...props.image}
114
- className='placeholder-image'
140
+ className={getClassNames('placeholder-image')}
115
141
  size={props.size}
116
142
  >
117
143
  <Icon
@@ -45,6 +45,7 @@ export { default as GoogleMap } from './components/GoogleMap';
45
45
  export { default as GooglePlacesSearch } from './components/GooglePlacesSearch';
46
46
  export { default as HorizontalCards } from './components/HorizontalCards';
47
47
  export { default as IIIFModal } from './components/IIIFModal';
48
+ export { default as ImageCarousel } from './components/ImageCarousel';
48
49
  export { default as ItemCollection } from './components/ItemCollection';
49
50
  export { default as ItemList } from './components/ItemList';
50
51
  export { default as Items } from './components/Items';