@spothero/ui 15.5.7 → 15.6.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": "@spothero/ui",
3
- "version": "15.5.7",
3
+ "version": "15.6.0",
4
4
  "description": "SpotHero's React component UI library.",
5
5
  "main": "v2/index.js",
6
6
  "repository": "https://github.com/spothero/fe-monorepo",
@@ -101,6 +101,7 @@
101
101
  "chalk": "4.1.0",
102
102
  "classnames": "2.2.6",
103
103
  "cypress": "6.6.0",
104
+ "eslint-loader": "4.0.2",
104
105
  "get-contrast-ratio": "0.2.1",
105
106
  "http-server": "0.12.3",
106
107
  "jest": "26.6.3",
@@ -122,8 +123,7 @@
122
123
  "regenerator-runtime": "0.13.7",
123
124
  "start-server-and-test": "1.12.6",
124
125
  "style-loader": "1.2.1",
125
- "webpack-merge": "5.1.4",
126
- "eslint-loader": "4.0.2"
126
+ "webpack-merge": "5.1.4"
127
127
  },
128
128
  "dependencies": {
129
129
  "@chakra-ui/react": "1.8.8",
@@ -146,6 +146,7 @@
146
146
  "react-input-mask": "2.0.4",
147
147
  "react-lazy-load": "3.0.13",
148
148
  "react-motion": "0.5.2",
149
+ "react-select": "5.4.0",
149
150
  "react-tether": "2.0.4",
150
151
  "regenerator-runtime": "0.13.7",
151
152
  "scrollingelement": "1.5.2",
@@ -0,0 +1,190 @@
1
+ import React, {forwardRef, useState} from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import FormControl from '../FormControl/FormControl';
4
+ import AsyncSelect from 'react-select/async';
5
+ import {useTheme} from '@chakra-ui/react';
6
+ import IconTimesCircle from '@spothero/icons/times-circle';
7
+
8
+ const AutoSuggestSelect = forwardRef(
9
+ (
10
+ {
11
+ id,
12
+ label,
13
+ helperText,
14
+ errorMessage,
15
+ isInvalid,
16
+ isDisabled,
17
+ isRequired,
18
+ getOptions,
19
+ onChange,
20
+ iconSrc,
21
+ placeholder,
22
+ },
23
+ ref
24
+ ) => {
25
+ const [query, setQuery] = useState('');
26
+ const {colors, fontSizes, sizes} = useTheme();
27
+
28
+ const handleInputChange = value => setQuery(value);
29
+
30
+ const loadOptions = () => {
31
+ return getOptions(query);
32
+ };
33
+
34
+ const icon = (color = 'transparent') => ({
35
+ alignItems: 'center',
36
+ display: 'flex',
37
+
38
+ ':before': {
39
+ backgroundColor: color,
40
+ content: '" "',
41
+ display: 'block',
42
+ marginRight: sizes['3'],
43
+ height: sizes['4'],
44
+ width: sizes['5'],
45
+ mask: `url(${iconSrc}) no-repeat 50% 50%`,
46
+ maskSize: 'contain',
47
+ },
48
+ });
49
+
50
+ const baseText = {
51
+ fontSize: fontSizes.base,
52
+ color: colors.black,
53
+ };
54
+
55
+ /** React Select doesn't use Chakra but it does use Emotion so it's not too difficult to use values from our Chakra theme. Here is the documentation for React Select styling: https://react-select.com/styles */
56
+ const customStyles = {
57
+ menu: provided => ({
58
+ ...provided,
59
+ ...baseText,
60
+ }),
61
+ control: (provided, state) => ({
62
+ ...provided,
63
+ borderColor: isInvalid
64
+ ? colors.error
65
+ : state.isFocused
66
+ ? colors.primary.default
67
+ : colors.gray['200'],
68
+ borderWidth: '1px',
69
+ boxShadow: 'none',
70
+ '&:hover': {
71
+ borderColor: isInvalid
72
+ ? colors.error
73
+ : state.isFocused
74
+ ? colors.primary.default
75
+ : colors.gray['200'],
76
+ },
77
+ }),
78
+ input: (provided, state) => ({
79
+ ...provided,
80
+ ...baseText,
81
+ padding: sizes['2'],
82
+ backgroundColor: state.isDisabled
83
+ ? colors.gray['200']
84
+ : 'transparent',
85
+ ...(iconSrc && icon(colors.gray['600'])),
86
+ }),
87
+ placeholder: provided => ({
88
+ ...provided,
89
+ padding: sizes['2'],
90
+ fontSize: fontSizes.base,
91
+ color: colors.gray['600'],
92
+ ...(iconSrc && icon()),
93
+ }),
94
+ singleValue: provided => ({
95
+ ...provided,
96
+ ...baseText,
97
+ padding: sizes['2'],
98
+ ...(iconSrc && icon()),
99
+ }),
100
+ option: (provided, state) => ({
101
+ ...provided,
102
+ backgroundColor: state.isSelected
103
+ ? colors.gray['200']
104
+ : state.isFocused
105
+ ? colors.gray['50']
106
+ : 'transparent',
107
+ color: colors.black,
108
+ }),
109
+ clearIndicator: provided => ({
110
+ ...provided,
111
+ color: colors.gray['600'],
112
+ }),
113
+ dropdownIndicator: provided => ({
114
+ ...provided,
115
+ color: colors.gray['600'],
116
+ }),
117
+ };
118
+
119
+ const clearIndicatorStyles = {
120
+ width: sizes['5'],
121
+ display: 'flex',
122
+ marginRight: sizes['3'],
123
+ color: colors.gray['600'],
124
+ cursor: 'pointer',
125
+ };
126
+
127
+ /** React Select allows you to override the clear indicator with your own custom component: https://react-select.com/components */
128
+ const ClearIndicator = ({innerRef, innerProps}) => (
129
+ <div style={clearIndicatorStyles} ref={innerRef} {...innerProps}>
130
+ <IconTimesCircle />
131
+ </div>
132
+ );
133
+
134
+ return (
135
+ <FormControl
136
+ errorMessage={errorMessage}
137
+ isRequired={isRequired}
138
+ helperText={helperText}
139
+ label={label}
140
+ inputId={id}
141
+ >
142
+ <AsyncSelect
143
+ closeMenuOnSelect
144
+ isClearable
145
+ components={{
146
+ DropdownIndicator: () => null,
147
+ IndicatorSeparator: () => null,
148
+ ClearIndicator,
149
+ }}
150
+ openMenuOnClick={false}
151
+ loadOptions={loadOptions}
152
+ onInputChange={handleInputChange}
153
+ onChange={onChange}
154
+ isDisabled={isDisabled}
155
+ id={id}
156
+ placeholder={placeholder}
157
+ styles={customStyles}
158
+ ref={ref}
159
+ />
160
+ </FormControl>
161
+ );
162
+ }
163
+ );
164
+
165
+ AutoSuggestSelect.propTypes = {
166
+ /** ID applied to the select and label */
167
+ id: PropTypes.string.isRequired,
168
+ /** Label that describes the select */
169
+ label: PropTypes.string,
170
+ /** Text to use as placeholder in the input */
171
+ placeholder: PropTypes.string,
172
+ /** Optional helper text displayed below the select */
173
+ helperText: PropTypes.string,
174
+ /** Error message that would dispplay under the select */
175
+ errorMessage: PropTypes.string,
176
+ /** Boolean that sets whether the select is valid */
177
+ isInvalid: PropTypes.bool,
178
+ /** Boolean that sets whether the select is disabled */
179
+ isDisabled: PropTypes.bool,
180
+ /** Boolean that sets whether the select is required */
181
+ isRequired: PropTypes.bool,
182
+ /** Function that is called with the value typed into the input that returns a list of options for the select */
183
+ getOptions: PropTypes.func.isRequired,
184
+ /** Function that is called when an option is selected, it returns the label and value of the selection */
185
+ onChange: PropTypes.func.isRequired,
186
+ /** Optional src to SVG to use as search icon */
187
+ iconSrc: PropTypes.string,
188
+ };
189
+
190
+ export default AutoSuggestSelect;
@@ -0,0 +1 @@
1
+ export {default as AutoSuggestSelect} from './AutoSuggestSelect';
@@ -31,6 +31,7 @@ export {
31
31
  } from './Popover';
32
32
  export {Modal} from './Modal';
33
33
  export {Radio, RadioGroup} from './Radio';
34
+ export {AutoSuggestSelect} from './AutoSuggestSelect';
34
35
 
35
36
  // generic chakra reexports
36
37
  export {