@performant-software/semantic-components 1.0.15 → 1.0.16

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,37 +601,6 @@ 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
-
635
604
  .item-list {
636
605
  margin: 1em 0em 1em 0em;
637
606
  }
@@ -716,9 +685,6 @@ div.react-calendar {
716
685
  width: 100% !important;
717
686
  height: 100% !important;
718
687
  }
719
- .lazy-document > .image.hidden {
720
- display: none;
721
- }
722
688
 
723
689
  .photo-viewer {
724
690
  padding: 30px;
@@ -747,9 +713,6 @@ div.react-calendar {
747
713
  padding-bottom: 20%;
748
714
  text-align: center;
749
715
  }
750
- .lazy-image > .image.hidden {
751
- display: none;
752
- }
753
716
 
754
717
  .video-player video {
755
718
  width: 100%;
@@ -782,9 +745,6 @@ div.react-calendar {
782
745
  display: table;
783
746
  width: 100%;
784
747
  }
785
- .lazy-video > .image.hidden {
786
- display: none;
787
- }
788
748
 
789
749
  .listLoader.ui.segment {
790
750
  position: absolute;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@performant-software/semantic-components",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
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.15",
15
+ "@performant-software/shared-components": "^1.0.16",
16
16
  "@react-google-maps/api": "^2.8.1",
17
17
  "axios": "^0.26.1",
18
18
  "i18next": "^19.4.4",
@@ -1,9 +1,16 @@
1
1
  // @flow
2
2
 
3
- import React, { useEffect } from 'react';
3
+ import { Timer } from '@performant-software/shared-components';
4
+ import React, {
5
+ useCallback,
6
+ useEffect,
7
+ useRef,
8
+ useState
9
+ } from 'react';
4
10
  import {
5
11
  Checkbox,
6
12
  Icon,
13
+ Input,
7
14
  Label,
8
15
  List
9
16
  } from 'semantic-ui-react';
@@ -14,7 +21,8 @@ import LinkButton from './LinkButton';
14
21
  import { type RefinementListProps } from '../types/InstantSearch';
15
22
 
16
23
  type Props = FacetProps & RefinementListProps & {
17
- defaultValue?: string
24
+ defaultValue?: string,
25
+ searchable?: boolean
18
26
  };
19
27
 
20
28
  const FacetList = ({ useRefinementList, ...props }: Props) => {
@@ -23,9 +31,39 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
23
31
  refine,
24
32
  canToggleShowMore,
25
33
  isShowingMore,
34
+ searchForItems,
26
35
  toggleShowMore,
27
36
  } = useRefinementList(props);
28
37
 
38
+ const ref = useRef();
39
+ const [query, setQuery] = useState('');
40
+
41
+ /**
42
+ * Clears the current search state.
43
+ *
44
+ * @type {(function(): void)|*}
45
+ */
46
+ const onClear = useCallback(() => {
47
+ // Reset the query view
48
+ setQuery('');
49
+
50
+ // Reset the list of refinements
51
+ searchForItems();
52
+
53
+ // Refocus the input element
54
+ const { current: instance } = ref;
55
+ if (instance) {
56
+ instance.focus();
57
+ }
58
+ }, []);
59
+
60
+ /**
61
+ * Executes the search within the list of facet values.
62
+ *
63
+ * @type {function(): *}
64
+ */
65
+ const onSearch = useCallback(() => searchForItems(query), [query, searchForItems]);
66
+
29
67
  /**
30
68
  * Sets the default value if provided.
31
69
  */
@@ -36,9 +74,18 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
36
74
  }, [props.defaultValue]);
37
75
 
38
76
  /**
39
- * Do not render the component if no items are present.
77
+ * Persist the facet search when a user selects or deselects items.
78
+ */
79
+ useEffect(() => {
80
+ if (query) {
81
+ searchForItems(query);
82
+ }
83
+ }, [items]);
84
+
85
+ /**
86
+ * Do not render the component if no items are present and no query has been entered.
40
87
  */
41
- if (_.isEmpty(items)) {
88
+ if (_.isEmpty(items) && _.isEmpty(query)) {
42
89
  return null;
43
90
  }
44
91
 
@@ -48,6 +95,24 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
48
95
  divided={props.divided}
49
96
  title={props.title}
50
97
  >
98
+ { props.searchable && (
99
+ <Input
100
+ icon={query && (
101
+ <Icon
102
+ link
103
+ name='times'
104
+ onClick={onClear}
105
+ />
106
+ )}
107
+ fluid
108
+ onChange={(e, { value }) => setQuery(value)}
109
+ onKeyDown={() => Timer.clearSearchTimer()}
110
+ onKeyUp={() => Timer.setSearchTimer(onSearch)}
111
+ placeholder={i18n.t('FacetList.labels.search')}
112
+ ref={ref}
113
+ value={query}
114
+ />
115
+ )}
51
116
  <List
52
117
  className='facet-list'
53
118
  >
@@ -26,7 +26,3 @@
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, { useCallback, useState, type Node } from 'react';
3
+ import React, { useState, type Node } from 'react';
4
4
  import { pdfjs, Document, Page } from 'react-pdf';
5
5
  import {
6
6
  Dimmer,
@@ -38,25 +38,6 @@ 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
-
60
41
  if (!visible) {
61
42
  return (
62
43
  <Visibility
@@ -96,7 +77,6 @@ const LazyDocument = (props: Props) => {
96
77
  { !error && props.preview && (
97
78
  <Image
98
79
  {...props.image}
99
- className={getClassNames()}
100
80
  onError={() => {
101
81
  setError(true);
102
82
  setLoaded(true);
@@ -112,7 +92,6 @@ const LazyDocument = (props: Props) => {
112
92
  { !error && loaded && !props.preview && props.src && props.pdf && (
113
93
  <Image
114
94
  {...props.image}
115
- className={getClassNames()}
116
95
  size={props.size}
117
96
  >
118
97
  <Document
@@ -128,7 +107,7 @@ const LazyDocument = (props: Props) => {
128
107
  { (error || (!props.preview && !(props.src && props.pdf))) && (
129
108
  <Image
130
109
  {...props.image}
131
- className={getClassNames('placeholder-image')}
110
+ className='placeholder-image'
132
111
  size={props.size}
133
112
  >
134
113
  <Icon
@@ -21,7 +21,3 @@
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, { useCallback, useState, type Node } from 'react';
3
+ import React, { useState, type Node } from 'react';
4
4
  import {
5
5
  Button,
6
6
  Dimmer,
@@ -36,25 +36,6 @@ 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
-
58
39
  if (!visible) {
59
40
  return (
60
41
  <Visibility
@@ -94,7 +75,6 @@ const LazyImage = (props: Props) => {
94
75
  { !error && (props.preview || props.src) && (
95
76
  <Image
96
77
  {...props.image}
97
- className={getClassNames()}
98
78
  onError={() => {
99
79
  setError(true);
100
80
  setLoaded(true);
@@ -110,7 +90,7 @@ const LazyImage = (props: Props) => {
110
90
  { (error || !(props.preview || props.src)) && (
111
91
  <Image
112
92
  {...props.image}
113
- className={getClassNames('placeholder-image')}
93
+ className='placeholder-image'
114
94
  size={props.size}
115
95
  >
116
96
  <Icon
@@ -26,7 +26,3 @@
26
26
  display: table;
27
27
  width: 100%;
28
28
  }
29
-
30
- .lazy-video > .image.hidden {
31
- display: none;
32
- }
@@ -1,11 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, {
4
- useCallback,
5
- useState,
6
- type Element,
7
- type Node
8
- } from 'react';
3
+ import React, { useState, type Element, type Node } from 'react';
9
4
  import {
10
5
  Button,
11
6
  Dimmer,
@@ -44,25 +39,6 @@ const LazyVideo = (props: Props) => {
44
39
  const [modal, setModal] = useState(false);
45
40
  const [visible, setVisible] = useState(false);
46
41
 
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
-
66
42
  if (!visible) {
67
43
  return (
68
44
  <Visibility
@@ -102,7 +78,6 @@ const LazyVideo = (props: Props) => {
102
78
  { !error && props.preview && (
103
79
  <Image
104
80
  {...props.image}
105
- className={getClassNames()}
106
81
  onError={() => {
107
82
  setError(true);
108
83
  setLoaded(true);
@@ -118,7 +93,6 @@ const LazyVideo = (props: Props) => {
118
93
  { !error && !props.preview && props.src && (
119
94
  <Image
120
95
  {...props.image}
121
- className={getClassNames()}
122
96
  size={props.size}
123
97
  >
124
98
  <video
@@ -137,7 +111,7 @@ const LazyVideo = (props: Props) => {
137
111
  { (error || (!props.preview && !props.src)) && (
138
112
  <Image
139
113
  {...props.image}
140
- className={getClassNames('placeholder-image')}
114
+ className='placeholder-image'
141
115
  size={props.size}
142
116
  >
143
117
  <Icon
package/src/i18n/en.json CHANGED
@@ -129,6 +129,9 @@
129
129
  "buttons": {
130
130
  "showLess": "Show Less",
131
131
  "showMore": "Show More"
132
+ },
133
+ "labels": {
134
+ "search": "Search"
132
135
  }
133
136
  },
134
137
  "FileUpload": {
package/src/index.js CHANGED
@@ -45,7 +45,6 @@ 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';
49
48
  export { default as ItemCollection } from './components/ItemCollection';
50
49
  export { default as ItemList } from './components/ItemList';
51
50
  export { default as Items } from './components/Items';
@@ -1,9 +1,16 @@
1
1
  // @flow
2
2
 
3
- import React, { useEffect } from 'react';
3
+ import { Timer } from '@performant-software/shared-components';
4
+ import React, {
5
+ useCallback,
6
+ useEffect,
7
+ useRef,
8
+ useState
9
+ } from 'react';
4
10
  import {
5
11
  Checkbox,
6
12
  Icon,
13
+ Input,
7
14
  Label,
8
15
  List
9
16
  } from 'semantic-ui-react';
@@ -14,7 +21,8 @@ import LinkButton from './LinkButton';
14
21
  import { type RefinementListProps } from '../types/InstantSearch';
15
22
 
16
23
  type Props = FacetProps & RefinementListProps & {
17
- defaultValue?: string
24
+ defaultValue?: string,
25
+ searchable?: boolean
18
26
  };
19
27
 
20
28
  const FacetList = ({ useRefinementList, ...props }: Props) => {
@@ -23,9 +31,39 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
23
31
  refine,
24
32
  canToggleShowMore,
25
33
  isShowingMore,
34
+ searchForItems,
26
35
  toggleShowMore,
27
36
  } = useRefinementList(props);
28
37
 
38
+ const ref = useRef();
39
+ const [query, setQuery] = useState('');
40
+
41
+ /**
42
+ * Clears the current search state.
43
+ *
44
+ * @type {(function(): void)|*}
45
+ */
46
+ const onClear = useCallback(() => {
47
+ // Reset the query view
48
+ setQuery('');
49
+
50
+ // Reset the list of refinements
51
+ searchForItems();
52
+
53
+ // Refocus the input element
54
+ const { current: instance } = ref;
55
+ if (instance) {
56
+ instance.focus();
57
+ }
58
+ }, []);
59
+
60
+ /**
61
+ * Executes the search within the list of facet values.
62
+ *
63
+ * @type {function(): *}
64
+ */
65
+ const onSearch = useCallback(() => searchForItems(query), [query, searchForItems]);
66
+
29
67
  /**
30
68
  * Sets the default value if provided.
31
69
  */
@@ -36,9 +74,18 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
36
74
  }, [props.defaultValue]);
37
75
 
38
76
  /**
39
- * Do not render the component if no items are present.
77
+ * Persist the facet search when a user selects or deselects items.
78
+ */
79
+ useEffect(() => {
80
+ if (query) {
81
+ searchForItems(query);
82
+ }
83
+ }, [items]);
84
+
85
+ /**
86
+ * Do not render the component if no items are present and no query has been entered.
40
87
  */
41
- if (_.isEmpty(items)) {
88
+ if (_.isEmpty(items) && _.isEmpty(query)) {
42
89
  return null;
43
90
  }
44
91
 
@@ -48,6 +95,24 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
48
95
  divided={props.divided}
49
96
  title={props.title}
50
97
  >
98
+ { props.searchable && (
99
+ <Input
100
+ icon={query && (
101
+ <Icon
102
+ link
103
+ name='times'
104
+ onClick={onClear}
105
+ />
106
+ )}
107
+ fluid
108
+ onChange={(e, { value }) => setQuery(value)}
109
+ onKeyDown={() => Timer.clearSearchTimer()}
110
+ onKeyUp={() => Timer.setSearchTimer(onSearch)}
111
+ placeholder={i18n.t('FacetList.labels.search')}
112
+ ref={ref}
113
+ value={query}
114
+ />
115
+ )}
51
116
  <List
52
117
  className='facet-list'
53
118
  >
@@ -1,6 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, { useCallback, useState, type Node } from 'react';
3
+ import React, { useState, type Node } from 'react';
4
4
  import { pdfjs, Document, Page } from 'react-pdf';
5
5
  import {
6
6
  Dimmer,
@@ -38,25 +38,6 @@ 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
-
60
41
  if (!visible) {
61
42
  return (
62
43
  <Visibility
@@ -96,7 +77,6 @@ const LazyDocument = (props: Props) => {
96
77
  { !error && props.preview && (
97
78
  <Image
98
79
  {...props.image}
99
- className={getClassNames()}
100
80
  onError={() => {
101
81
  setError(true);
102
82
  setLoaded(true);
@@ -112,7 +92,6 @@ const LazyDocument = (props: Props) => {
112
92
  { !error && loaded && !props.preview && props.src && props.pdf && (
113
93
  <Image
114
94
  {...props.image}
115
- className={getClassNames()}
116
95
  size={props.size}
117
96
  >
118
97
  <Document
@@ -128,7 +107,7 @@ const LazyDocument = (props: Props) => {
128
107
  { (error || (!props.preview && !(props.src && props.pdf))) && (
129
108
  <Image
130
109
  {...props.image}
131
- className={getClassNames('placeholder-image')}
110
+ className='placeholder-image'
132
111
  size={props.size}
133
112
  >
134
113
  <Icon
@@ -1,6 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, { useCallback, useState, type Node } from 'react';
3
+ import React, { useState, type Node } from 'react';
4
4
  import {
5
5
  Button,
6
6
  Dimmer,
@@ -36,25 +36,6 @@ 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
-
58
39
  if (!visible) {
59
40
  return (
60
41
  <Visibility
@@ -94,7 +75,6 @@ const LazyImage = (props: Props) => {
94
75
  { !error && (props.preview || props.src) && (
95
76
  <Image
96
77
  {...props.image}
97
- className={getClassNames()}
98
78
  onError={() => {
99
79
  setError(true);
100
80
  setLoaded(true);
@@ -110,7 +90,7 @@ const LazyImage = (props: Props) => {
110
90
  { (error || !(props.preview || props.src)) && (
111
91
  <Image
112
92
  {...props.image}
113
- className={getClassNames('placeholder-image')}
93
+ className='placeholder-image'
114
94
  size={props.size}
115
95
  >
116
96
  <Icon
@@ -1,11 +1,6 @@
1
1
  // @flow
2
2
 
3
- import React, {
4
- useCallback,
5
- useState,
6
- type Element,
7
- type Node
8
- } from 'react';
3
+ import React, { useState, type Element, type Node } from 'react';
9
4
  import {
10
5
  Button,
11
6
  Dimmer,
@@ -44,25 +39,6 @@ const LazyVideo = (props: Props) => {
44
39
  const [modal, setModal] = useState(false);
45
40
  const [visible, setVisible] = useState(false);
46
41
 
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
-
66
42
  if (!visible) {
67
43
  return (
68
44
  <Visibility
@@ -102,7 +78,6 @@ const LazyVideo = (props: Props) => {
102
78
  { !error && props.preview && (
103
79
  <Image
104
80
  {...props.image}
105
- className={getClassNames()}
106
81
  onError={() => {
107
82
  setError(true);
108
83
  setLoaded(true);
@@ -118,7 +93,6 @@ const LazyVideo = (props: Props) => {
118
93
  { !error && !props.preview && props.src && (
119
94
  <Image
120
95
  {...props.image}
121
- className={getClassNames()}
122
96
  size={props.size}
123
97
  >
124
98
  <video
@@ -137,7 +111,7 @@ const LazyVideo = (props: Props) => {
137
111
  { (error || (!props.preview && !props.src)) && (
138
112
  <Image
139
113
  {...props.image}
140
- className={getClassNames('placeholder-image')}
114
+ className='placeholder-image'
141
115
  size={props.size}
142
116
  >
143
117
  <Icon