@spaced-out/ui-design-system 0.1.4 → 0.1.6
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/CHANGELOG.md +19 -0
- package/lib/components/Dropdown/Dropdown.js +2 -6
- package/lib/components/Dropdown/Dropdown.js.flow +2 -7
- package/lib/components/InContextAlert/InContextAlert.js +5 -4
- package/lib/components/InContextAlert/InContextAlert.js.flow +6 -8
- package/lib/components/InContextAlert/InContextAlert.module.css +0 -7
- package/lib/components/Link/Link.js.flow +1 -1
- package/lib/components/SearchInput/SearchInput.js +20 -5
- package/lib/components/SearchInput/SearchInput.js.flow +39 -17
- package/lib/components/SearchInput/SearchInput.module.css +33 -0
- package/lib/components/Typeahead/Typeahead.js +21 -22
- package/lib/components/Typeahead/Typeahead.js.flow +28 -25
- package/lib/components/Typeahead/Typeahead.module.css +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [0.1.6](https://github.com/spaced-out/ui-design-system/compare/v0.1.5...v0.1.6) (2023-04-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* typeahead focus and loading states search input icon changes ([47363ef](https://github.com/spaced-out/ui-design-system/commit/47363efa8b7706f6cc166ffc2b617c796bd342e7))
|
|
11
|
+
|
|
12
|
+
### [0.1.5](https://github.com/spaced-out/ui-design-system/compare/v0.1.4...v0.1.5) (2023-04-04)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* in context aleart and banner focus states ([9d3144d](https://github.com/spaced-out/ui-design-system/commit/9d3144dad0cc32f21cfd1ed4284b6eb5da99e742))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* typeahead and dropdown fixes ([fa9d5ed](https://github.com/spaced-out/ui-design-system/commit/fa9d5ed1276fb3381fa71ac2f57c203ca9900dd8))
|
|
23
|
+
|
|
5
24
|
### [0.1.4](https://github.com/spaced-out/ui-design-system/compare/v0.1.3...v0.1.4) (2023-04-03)
|
|
6
25
|
|
|
7
26
|
|
|
@@ -27,10 +27,9 @@ const Dropdown = _ref => {
|
|
|
27
27
|
menu,
|
|
28
28
|
onMenuOpen,
|
|
29
29
|
onMenuClose,
|
|
30
|
-
dropdownInputText,
|
|
30
|
+
dropdownInputText = '',
|
|
31
31
|
...inputProps
|
|
32
32
|
} = _ref;
|
|
33
|
-
const [inputValue, setInputValue] = React.useState(dropdownInputText || '');
|
|
34
33
|
const dropdownRef = React.useRef();
|
|
35
34
|
const {
|
|
36
35
|
x,
|
|
@@ -44,9 +43,6 @@ const Dropdown = _ref => {
|
|
|
44
43
|
whileElementsMounted: _reactDom.autoUpdate,
|
|
45
44
|
middleware: [(0, _reactDom.flip)(), (0, _reactDom.offset)(parseInt(_space.spaceXXSmall))]
|
|
46
45
|
});
|
|
47
|
-
React.useEffect(() => {
|
|
48
|
-
setInputValue(dropdownInputText || '');
|
|
49
|
-
}, [dropdownInputText]);
|
|
50
46
|
const onMenuToggle = isOpen => {
|
|
51
47
|
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
52
48
|
};
|
|
@@ -67,7 +63,7 @@ const Dropdown = _ref => {
|
|
|
67
63
|
boxRef: reference,
|
|
68
64
|
size: size,
|
|
69
65
|
placeholder: placeholder,
|
|
70
|
-
value:
|
|
66
|
+
value: dropdownInputText,
|
|
71
67
|
classNames: {
|
|
72
68
|
box: _DropdownModule.default.inputBox
|
|
73
69
|
}
|
|
@@ -45,10 +45,9 @@ export const Dropdown = ({
|
|
|
45
45
|
menu,
|
|
46
46
|
onMenuOpen,
|
|
47
47
|
onMenuClose,
|
|
48
|
-
dropdownInputText,
|
|
48
|
+
dropdownInputText = '',
|
|
49
49
|
...inputProps
|
|
50
50
|
}: DropdownProps): React.Node => {
|
|
51
|
-
const [inputValue, setInputValue] = React.useState(dropdownInputText || '');
|
|
52
51
|
const dropdownRef = React.useRef();
|
|
53
52
|
const {x, y, reference, floating, strategy} = useFloating({
|
|
54
53
|
strategy: 'absolute',
|
|
@@ -57,10 +56,6 @@ export const Dropdown = ({
|
|
|
57
56
|
middleware: [flip(), offset(parseInt(spaceXXSmall))],
|
|
58
57
|
});
|
|
59
58
|
|
|
60
|
-
React.useEffect(() => {
|
|
61
|
-
setInputValue(dropdownInputText || '');
|
|
62
|
-
}, [dropdownInputText]);
|
|
63
|
-
|
|
64
59
|
const onMenuToggle = (isOpen: boolean) => {
|
|
65
60
|
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
66
61
|
};
|
|
@@ -77,7 +72,7 @@ export const Dropdown = ({
|
|
|
77
72
|
boxRef={reference}
|
|
78
73
|
size={size}
|
|
79
74
|
placeholder={placeholder}
|
|
80
|
-
value={
|
|
75
|
+
value={dropdownInputText}
|
|
81
76
|
classNames={{box: css.inputBox}}
|
|
82
77
|
{...inputProps}
|
|
83
78
|
iconRightName={isOpen ? 'angle-up' : 'angle-down'}
|
|
@@ -8,6 +8,7 @@ var React = _interopRequireWildcard(require("react"));
|
|
|
8
8
|
var _typography = require("../../types/typography");
|
|
9
9
|
var _classify = require("../../utils/classify");
|
|
10
10
|
var _Icon = require("../Icon");
|
|
11
|
+
var _Link = require("../Link");
|
|
11
12
|
var _Text = require("../Text");
|
|
12
13
|
var _Truncate = require("../Truncate");
|
|
13
14
|
var _InContextAlertModule = _interopRequireDefault(require("./InContextAlert.module.css"));
|
|
@@ -110,10 +111,10 @@ const InContextAlert = props => {
|
|
|
110
111
|
line: 2
|
|
111
112
|
}, children)), !!(actionText || dismissable) && /*#__PURE__*/React.createElement("div", {
|
|
112
113
|
className: (0, _classify.classify)(_InContextAlertModule.default.actionContainer, classNames?.actionContainer)
|
|
113
|
-
}, !!actionText && /*#__PURE__*/React.createElement(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}, actionText), !!dismissable && /*#__PURE__*/React.createElement(_Icon.
|
|
114
|
+
}, !!actionText && /*#__PURE__*/React.createElement(_Link.Link, {
|
|
115
|
+
onClick: onAction,
|
|
116
|
+
color: "primary"
|
|
117
|
+
}, actionText), !!dismissable && /*#__PURE__*/React.createElement(_Icon.ClickableIcon, {
|
|
117
118
|
color: _typography.TEXT_COLORS.primary,
|
|
118
119
|
name: "close",
|
|
119
120
|
size: "small",
|
|
@@ -5,8 +5,9 @@ import * as React from 'react';
|
|
|
5
5
|
import {TEXT_COLORS} from '../../types/typography';
|
|
6
6
|
import {classify} from '../../utils/classify';
|
|
7
7
|
import type {IconType} from '../Icon';
|
|
8
|
-
import {Icon} from '../Icon';
|
|
9
|
-
import {
|
|
8
|
+
import {ClickableIcon, Icon} from '../Icon';
|
|
9
|
+
import {Link} from '../Link';
|
|
10
|
+
import {SubTitleExtraSmall} from '../Text';
|
|
10
11
|
import {Truncate} from '../Truncate';
|
|
11
12
|
|
|
12
13
|
import css from './InContextAlert.module.css';
|
|
@@ -172,15 +173,12 @@ export const InContextAlert = (props: InContextAlertProps): React.Node => {
|
|
|
172
173
|
)}
|
|
173
174
|
>
|
|
174
175
|
{!!actionText && (
|
|
175
|
-
<
|
|
176
|
-
className={css.actionText}
|
|
177
|
-
onClick={onAction}
|
|
178
|
-
>
|
|
176
|
+
<Link onClick={onAction} color="primary">
|
|
179
177
|
{actionText}
|
|
180
|
-
</
|
|
178
|
+
</Link>
|
|
181
179
|
)}
|
|
182
180
|
{!!dismissable && (
|
|
183
|
-
<
|
|
181
|
+
<ClickableIcon
|
|
184
182
|
color={TEXT_COLORS.primary}
|
|
185
183
|
name="close"
|
|
186
184
|
size="small"
|
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.SearchInput = void 0;
|
|
7
7
|
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _classify = _interopRequireDefault(require("../../utils/classify"));
|
|
9
|
+
var _CircularLoader = require("../CircularLoader");
|
|
8
10
|
var _Input = require("../Input");
|
|
9
11
|
var _SearchInputModule = _interopRequireDefault(require("./SearchInput.module.css"));
|
|
10
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -19,26 +21,39 @@ const SearchInput = _ref => {
|
|
|
19
21
|
placeholder = 'Search...',
|
|
20
22
|
classNames,
|
|
21
23
|
onClear,
|
|
24
|
+
isLoading,
|
|
25
|
+
size,
|
|
26
|
+
iconLeftName = 'magnifying-glass',
|
|
22
27
|
...searchInputProps
|
|
23
28
|
} = _ref;
|
|
24
29
|
const handleClearClick = () => {
|
|
25
30
|
onClear?.();
|
|
26
31
|
};
|
|
27
|
-
return /*#__PURE__*/React.createElement(
|
|
32
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
33
|
+
className: (0, _classify.default)(_SearchInputModule.default.searchInputWrapper, classNames?.wrapper)
|
|
34
|
+
}, /*#__PURE__*/React.createElement(_Input.Input, _extends({
|
|
28
35
|
type: "text"
|
|
29
36
|
}, searchInputProps, {
|
|
30
37
|
classNames: {
|
|
31
|
-
...classNames,
|
|
32
38
|
iconRight: value && !(disabled || locked) ? _SearchInputModule.default.clickable : '',
|
|
33
|
-
iconLeft: value && !disabled ? _SearchInputModule.default.primaryText : ''
|
|
39
|
+
iconLeft: value && !disabled ? _SearchInputModule.default.primaryText : '',
|
|
40
|
+
box: classNames?.box
|
|
34
41
|
},
|
|
35
42
|
placeholder: placeholder,
|
|
36
43
|
value: value,
|
|
37
44
|
disabled: disabled,
|
|
38
45
|
locked: locked,
|
|
39
|
-
iconLeftName:
|
|
46
|
+
iconLeftName: iconLeftName,
|
|
47
|
+
size: size,
|
|
40
48
|
iconRightName: value && !(disabled || locked) ? 'xmark' : 'fw',
|
|
41
49
|
onIconRightClick: handleClearClick
|
|
42
|
-
}))
|
|
50
|
+
})), isLoading && /*#__PURE__*/React.createElement("div", {
|
|
51
|
+
className: (0, _classify.default)(_SearchInputModule.default.loaderContainer, {
|
|
52
|
+
[_SearchInputModule.default.small]: size === 'small'
|
|
53
|
+
})
|
|
54
|
+
}, /*#__PURE__*/React.createElement(_CircularLoader.CircularLoader, {
|
|
55
|
+
colorToken: "colorFillPrimary",
|
|
56
|
+
size: size
|
|
57
|
+
})));
|
|
43
58
|
};
|
|
44
59
|
exports.SearchInput = SearchInput;
|
|
@@ -2,18 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
|
+
import classify from '../../utils/classify';
|
|
6
|
+
import {CircularLoader} from '../CircularLoader';
|
|
5
7
|
import type {InputProps} from '../Input';
|
|
6
8
|
import {Input} from '../Input';
|
|
7
9
|
|
|
8
10
|
import css from './SearchInput.module.css';
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
type ClassNames = $ReadOnly<{
|
|
13
|
+
type ClassNames = $ReadOnly<{
|
|
14
|
+
wrapper?: string,
|
|
15
|
+
box?: string,
|
|
16
|
+
iconLeft?: string,
|
|
17
|
+
}>;
|
|
12
18
|
|
|
13
19
|
export type SearchInputProps = {
|
|
14
20
|
...InputProps,
|
|
15
21
|
classNames?: ClassNames,
|
|
16
22
|
onClear?: () => void,
|
|
23
|
+
isLoading?: boolean,
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
export const SearchInput = ({
|
|
@@ -23,6 +30,9 @@ export const SearchInput = ({
|
|
|
23
30
|
placeholder = 'Search...',
|
|
24
31
|
classNames,
|
|
25
32
|
onClear,
|
|
33
|
+
isLoading,
|
|
34
|
+
size,
|
|
35
|
+
iconLeftName = 'magnifying-glass',
|
|
26
36
|
...searchInputProps
|
|
27
37
|
}: SearchInputProps): React.Node => {
|
|
28
38
|
const handleClearClick = () => {
|
|
@@ -30,21 +40,33 @@ export const SearchInput = ({
|
|
|
30
40
|
};
|
|
31
41
|
|
|
32
42
|
return (
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
<div className={classify(css.searchInputWrapper, classNames?.wrapper)}>
|
|
44
|
+
<Input
|
|
45
|
+
type="text"
|
|
46
|
+
{...searchInputProps}
|
|
47
|
+
classNames={{
|
|
48
|
+
iconRight: value && !(disabled || locked) ? css.clickable : '',
|
|
49
|
+
iconLeft: value && !disabled ? css.primaryText : '',
|
|
50
|
+
box: classNames?.box,
|
|
51
|
+
}}
|
|
52
|
+
placeholder={placeholder}
|
|
53
|
+
value={value}
|
|
54
|
+
disabled={disabled}
|
|
55
|
+
locked={locked}
|
|
56
|
+
iconLeftName={iconLeftName}
|
|
57
|
+
size={size}
|
|
58
|
+
iconRightName={value && !(disabled || locked) ? 'xmark' : 'fw'}
|
|
59
|
+
onIconRightClick={handleClearClick}
|
|
60
|
+
/>
|
|
61
|
+
{isLoading && (
|
|
62
|
+
<div
|
|
63
|
+
className={classify(css.loaderContainer, {
|
|
64
|
+
[css.small]: size === 'small',
|
|
65
|
+
})}
|
|
66
|
+
>
|
|
67
|
+
<CircularLoader colorToken="colorFillPrimary" size={size} />
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
49
71
|
);
|
|
50
72
|
};
|
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
colorTextPrimary
|
|
3
3
|
) from '../../styles/variables/_color.css';
|
|
4
4
|
|
|
5
|
+
@value (
|
|
6
|
+
size42,
|
|
7
|
+
size34
|
|
8
|
+
) from '../../styles/variables/_size.css';
|
|
9
|
+
|
|
10
|
+
@value (
|
|
11
|
+
spaceXXSmall
|
|
12
|
+
) from '../../styles/variables/_space.css';
|
|
13
|
+
|
|
14
|
+
.searchInputWrapper {
|
|
15
|
+
display: flex;
|
|
16
|
+
position: relative;
|
|
17
|
+
align-items: end;
|
|
18
|
+
gap: spaceXXSmall;
|
|
19
|
+
height: fit-content;
|
|
20
|
+
}
|
|
21
|
+
|
|
5
22
|
.clickable {
|
|
6
23
|
cursor: pointer;
|
|
7
24
|
}
|
|
@@ -9,3 +26,19 @@
|
|
|
9
26
|
.primaryText {
|
|
10
27
|
color: colorTextPrimary;
|
|
11
28
|
}
|
|
29
|
+
|
|
30
|
+
.loaderContainer {
|
|
31
|
+
display: flex;
|
|
32
|
+
height: size42;
|
|
33
|
+
width: size42;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
align-items: center;
|
|
37
|
+
margin-right: calc((size42 * -1) - spaceXXSmall);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.loaderContainer.small {
|
|
41
|
+
height: size34;
|
|
42
|
+
width: size34;
|
|
43
|
+
margin-right: calc((size34 * -1) - spaceXXSmall);
|
|
44
|
+
}
|
|
@@ -29,11 +29,12 @@ const Typeahead = _ref => {
|
|
|
29
29
|
menu,
|
|
30
30
|
onMenuOpen,
|
|
31
31
|
onMenuClose,
|
|
32
|
-
typeaheadInputText,
|
|
32
|
+
typeaheadInputText = '',
|
|
33
|
+
isLoading,
|
|
34
|
+
menuOpenOffset = 1,
|
|
33
35
|
...inputProps
|
|
34
36
|
} = _ref;
|
|
35
37
|
const typeaheadRef = React.useRef();
|
|
36
|
-
const [inputValue, setInputValue] = React.useState(typeaheadInputText || '');
|
|
37
38
|
const [filteredOptions, setFilteredOptions] = React.useState(menu?.options);
|
|
38
39
|
const {
|
|
39
40
|
x,
|
|
@@ -47,28 +48,19 @@ const Typeahead = _ref => {
|
|
|
47
48
|
whileElementsMounted: _reactDom.autoUpdate,
|
|
48
49
|
middleware: [(0, _reactDom.flip)(), (0, _reactDom.offset)(parseInt(_space.spaceXXSmall))]
|
|
49
50
|
});
|
|
50
|
-
const handleSelect = option => {
|
|
51
|
-
if (option?.key) {
|
|
52
|
-
onSelect && onSelect(option);
|
|
53
|
-
setInputValue(option.label);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
React.useEffect(() => {
|
|
57
|
-
setInputValue(typeaheadInputText || '');
|
|
58
|
-
}, [typeaheadInputText]);
|
|
59
51
|
const onMenuToggle = isOpen => {
|
|
60
52
|
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
61
53
|
};
|
|
62
54
|
React.useEffect(() => {
|
|
63
55
|
const optionsFiltered = menu?.options && menu.options.filter(option => {
|
|
64
|
-
if (!option.label || !
|
|
56
|
+
if (!option.label || !typeaheadInputText) {
|
|
65
57
|
return true;
|
|
66
58
|
} else {
|
|
67
|
-
return option.label.toLowerCase().indexOf(
|
|
59
|
+
return option.label.toLowerCase().indexOf(typeaheadInputText.toLowerCase()) !== -1;
|
|
68
60
|
}
|
|
69
61
|
});
|
|
70
62
|
setFilteredOptions(optionsFiltered || []);
|
|
71
|
-
}, [
|
|
63
|
+
}, [typeaheadInputText, menu?.options]);
|
|
72
64
|
return /*#__PURE__*/React.createElement(_clickAway.ClickAway, {
|
|
73
65
|
onChange: onMenuToggle
|
|
74
66
|
}, _ref2 => {
|
|
@@ -81,31 +73,38 @@ const Typeahead = _ref => {
|
|
|
81
73
|
return /*#__PURE__*/React.createElement("div", {
|
|
82
74
|
"data-testid": "Typeahead",
|
|
83
75
|
className: (0, _classify.classify)(_TypeaheadModule.default.typeaheadContainer, classNames?.wrapper),
|
|
84
|
-
ref: typeaheadRef
|
|
76
|
+
ref: typeaheadRef,
|
|
77
|
+
onClickCapture: cancelNext
|
|
85
78
|
}, /*#__PURE__*/React.createElement(_SearchInput.SearchInput, _extends({
|
|
86
79
|
boxRef: reference,
|
|
87
80
|
size: size,
|
|
88
81
|
placeholder: placeholder,
|
|
89
|
-
value:
|
|
82
|
+
value: typeaheadInputText,
|
|
90
83
|
classNames: {
|
|
91
84
|
box: classNames?.box
|
|
92
|
-
}
|
|
85
|
+
},
|
|
86
|
+
isLoading: isLoading
|
|
93
87
|
}, inputProps, {
|
|
94
88
|
onChange: e => {
|
|
95
89
|
e.stopPropagation();
|
|
96
|
-
setInputValue(e.target.value);
|
|
97
90
|
onSearch && onSearch(e);
|
|
98
|
-
if (e.target.value.length
|
|
91
|
+
if (e.target.value.length >= menuOpenOffset) {
|
|
92
|
+
onOpen();
|
|
93
|
+
} else {
|
|
94
|
+
clickAway();
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
onFocus: _e => {
|
|
98
|
+
if (typeaheadInputText.length >= menuOpenOffset) {
|
|
99
99
|
onOpen();
|
|
100
100
|
} else {
|
|
101
101
|
clickAway();
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
onClear: _e => {
|
|
105
|
-
setInputValue('');
|
|
106
105
|
onClear?.();
|
|
107
106
|
}
|
|
108
|
-
})), isOpen && menu && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
|
|
107
|
+
})), isOpen && !isLoading && menu && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
|
|
109
108
|
onClickCapture: cancelNext,
|
|
110
109
|
ref: floating,
|
|
111
110
|
style: {
|
|
@@ -118,7 +117,7 @@ const Typeahead = _ref => {
|
|
|
118
117
|
}, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
|
|
119
118
|
options: filteredOptions,
|
|
120
119
|
onSelect: option => {
|
|
121
|
-
|
|
120
|
+
onSelect && onSelect(option);
|
|
122
121
|
if (!menu.optionsVariant || menu.optionsVariant === 'normal') {
|
|
123
122
|
clickAway();
|
|
124
123
|
}
|
|
@@ -37,6 +37,8 @@ export type TypeaheadProps = {
|
|
|
37
37
|
typeaheadInputText?: string,
|
|
38
38
|
menu?: MenuProps,
|
|
39
39
|
onClear?: () => void,
|
|
40
|
+
isLoading?: boolean,
|
|
41
|
+
menuOpenOffset?: number,
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
export const Typeahead = ({
|
|
@@ -49,12 +51,12 @@ export const Typeahead = ({
|
|
|
49
51
|
menu,
|
|
50
52
|
onMenuOpen,
|
|
51
53
|
onMenuClose,
|
|
52
|
-
typeaheadInputText,
|
|
54
|
+
typeaheadInputText = '',
|
|
55
|
+
isLoading,
|
|
56
|
+
menuOpenOffset = 1,
|
|
53
57
|
...inputProps
|
|
54
58
|
}: TypeaheadProps): React.Node => {
|
|
55
59
|
const typeaheadRef = React.useRef();
|
|
56
|
-
|
|
57
|
-
const [inputValue, setInputValue] = React.useState(typeaheadInputText || '');
|
|
58
60
|
const [filteredOptions, setFilteredOptions] = React.useState(menu?.options);
|
|
59
61
|
|
|
60
62
|
const {x, y, reference, floating, strategy} = useFloating({
|
|
@@ -64,17 +66,6 @@ export const Typeahead = ({
|
|
|
64
66
|
middleware: [flip(), offset(parseInt(spaceXXSmall))],
|
|
65
67
|
});
|
|
66
68
|
|
|
67
|
-
const handleSelect = (option?: MenuOption) => {
|
|
68
|
-
if (option?.key) {
|
|
69
|
-
onSelect && onSelect(option);
|
|
70
|
-
setInputValue(option.label);
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
React.useEffect(() => {
|
|
75
|
-
setInputValue(typeaheadInputText || '');
|
|
76
|
-
}, [typeaheadInputText]);
|
|
77
|
-
|
|
78
69
|
const onMenuToggle = (isOpen: boolean) => {
|
|
79
70
|
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
80
71
|
};
|
|
@@ -83,16 +74,18 @@ export const Typeahead = ({
|
|
|
83
74
|
const optionsFiltered =
|
|
84
75
|
menu?.options &&
|
|
85
76
|
menu.options.filter((option) => {
|
|
86
|
-
if (!option.label || !
|
|
77
|
+
if (!option.label || !typeaheadInputText) {
|
|
87
78
|
return true;
|
|
88
79
|
} else {
|
|
89
80
|
return (
|
|
90
|
-
option.label
|
|
81
|
+
option.label
|
|
82
|
+
.toLowerCase()
|
|
83
|
+
.indexOf(typeaheadInputText.toLowerCase()) !== -1
|
|
91
84
|
);
|
|
92
85
|
}
|
|
93
86
|
});
|
|
94
87
|
setFilteredOptions(optionsFiltered || []);
|
|
95
|
-
}, [
|
|
88
|
+
}, [typeaheadInputText, menu?.options]);
|
|
96
89
|
|
|
97
90
|
return (
|
|
98
91
|
<ClickAway onChange={onMenuToggle}>
|
|
@@ -101,31 +94,41 @@ export const Typeahead = ({
|
|
|
101
94
|
data-testid="Typeahead"
|
|
102
95
|
className={classify(css.typeaheadContainer, classNames?.wrapper)}
|
|
103
96
|
ref={typeaheadRef}
|
|
97
|
+
onClickCapture={cancelNext}
|
|
104
98
|
>
|
|
105
99
|
<SearchInput
|
|
106
100
|
boxRef={reference}
|
|
107
101
|
size={size}
|
|
108
102
|
placeholder={placeholder}
|
|
109
|
-
value={
|
|
103
|
+
value={typeaheadInputText}
|
|
110
104
|
classNames={{box: classNames?.box}}
|
|
105
|
+
isLoading={isLoading}
|
|
111
106
|
{...inputProps}
|
|
112
107
|
onChange={(e) => {
|
|
113
108
|
e.stopPropagation();
|
|
114
|
-
setInputValue(e.target.value);
|
|
115
109
|
onSearch && onSearch(e);
|
|
116
|
-
if (e.target.value.length
|
|
110
|
+
if (e.target.value.length >= menuOpenOffset) {
|
|
111
|
+
onOpen();
|
|
112
|
+
} else {
|
|
113
|
+
clickAway();
|
|
114
|
+
}
|
|
115
|
+
}}
|
|
116
|
+
onFocus={(_e) => {
|
|
117
|
+
if (typeaheadInputText.length >= menuOpenOffset) {
|
|
117
118
|
onOpen();
|
|
118
119
|
} else {
|
|
119
120
|
clickAway();
|
|
120
121
|
}
|
|
121
122
|
}}
|
|
122
123
|
onClear={(_e) => {
|
|
123
|
-
setInputValue('');
|
|
124
124
|
onClear?.();
|
|
125
125
|
}}
|
|
126
126
|
/>
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
{isOpen &&
|
|
128
|
+
!isLoading &&
|
|
129
|
+
menu &&
|
|
130
|
+
filteredOptions &&
|
|
131
|
+
!!filteredOptions.length && (
|
|
129
132
|
<div
|
|
130
133
|
onClickCapture={cancelNext}
|
|
131
134
|
ref={floating}
|
|
@@ -141,10 +144,10 @@ export const Typeahead = ({
|
|
|
141
144
|
{...menu}
|
|
142
145
|
options={filteredOptions}
|
|
143
146
|
onSelect={(option) => {
|
|
144
|
-
|
|
147
|
+
onSelect && onSelect(option);
|
|
145
148
|
if (
|
|
146
149
|
!menu.optionsVariant ||
|
|
147
|
-
|
|
150
|
+
menu.optionsVariant === 'normal'
|
|
148
151
|
) {
|
|
149
152
|
clickAway();
|
|
150
153
|
}
|