@spaced-out/ui-design-system 0.0.67 → 0.1.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/CHANGELOG.md +20 -0
- package/lib/components/ButtonDropdown/ButtonDropdown.js +4 -2
- package/lib/components/ButtonDropdown/ButtonDropdown.js.flow +8 -3
- package/lib/components/Checkbox/Checkbox.js +3 -2
- package/lib/components/Checkbox/Checkbox.js.flow +3 -1
- package/lib/components/Chip/Chip.module.css +1 -0
- package/lib/components/Dropdown/Dropdown.js +22 -28
- package/lib/components/Dropdown/Dropdown.js.flow +30 -47
- package/lib/components/Icon/ClickableIcon.js +1 -1
- package/lib/components/Icon/ClickableIcon.js.flow +1 -1
- package/lib/components/InlineDropdown/InlineDropdown.js +5 -2
- package/lib/components/InlineDropdown/InlineDropdown.js.flow +8 -2
- package/lib/components/Input/Input.js +2 -1
- package/lib/components/Input/Input.js.flow +1 -0
- package/lib/components/Input/Input.module.css +15 -2
- package/lib/components/Menu/Menu.js +8 -4
- package/lib/components/Menu/Menu.js.flow +43 -13
- package/lib/components/Menu/Menu.module.css +19 -2
- package/lib/components/Menu/MenuOptionButton.js +22 -3
- package/lib/components/Menu/MenuOptionButton.js.flow +37 -13
- package/lib/components/RadioButton/RadioButton.js +2 -1
- package/lib/components/RadioButton/RadioButton.js.flow +3 -1
- package/lib/components/SearchInput/SearchInput.js.flow +2 -22
- package/lib/components/Tabs/Tab/Tab.js +1 -1
- package/lib/components/Tabs/Tab/Tab.js.flow +1 -1
- package/lib/components/Tabs/TabList/TabList.js +2 -5
- package/lib/components/Tabs/TabList/TabList.js.flow +4 -7
- package/lib/components/Typeahead/Typeahead.js +23 -18
- package/lib/components/Typeahead/Typeahead.js.flow +32 -33
- package/lib/utils/menu.js +52 -0
- package/lib/utils/menu.js.flow +81 -0
- package/package.json +1 -1
|
@@ -155,6 +155,18 @@
|
|
|
155
155
|
color: colorTextPrimary;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
.option:focus-within {
|
|
159
|
+
background: colorFillSecondary;
|
|
160
|
+
outline: none;
|
|
161
|
+
color: colorTextPrimary;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.option.selected {
|
|
165
|
+
background: colorFillSecondary;
|
|
166
|
+
outline: none;
|
|
167
|
+
color: colorTextPrimary;
|
|
168
|
+
}
|
|
169
|
+
|
|
158
170
|
.option:focus .optionTextSecondaryLabel {
|
|
159
171
|
color: colorTextSecondary;
|
|
160
172
|
}
|
|
@@ -187,12 +199,17 @@
|
|
|
187
199
|
padding-bottom: spaceNone;
|
|
188
200
|
}
|
|
189
201
|
|
|
202
|
+
.optionsWrapper {
|
|
203
|
+
display: flex;
|
|
204
|
+
flex-flow: column;
|
|
205
|
+
}
|
|
206
|
+
|
|
190
207
|
.groupTitleWrapper {
|
|
191
208
|
composes: formLabelSmall from '../../styles/typography.module.css';
|
|
192
209
|
display: flex;
|
|
193
|
-
|
|
210
|
+
padding-bottom: spaceXSmall;
|
|
194
211
|
padding-left: spaceSmall;
|
|
195
212
|
padding-right: calc(spaceXSmall / 2);
|
|
196
213
|
color: colorTextTertiary;
|
|
197
|
-
|
|
214
|
+
padding-top: spaceSmall;
|
|
198
215
|
}
|
|
@@ -7,7 +7,9 @@ exports.MenuOptionButton = void 0;
|
|
|
7
7
|
var React = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _classify = require("../../utils/classify");
|
|
9
9
|
var _Button = require("../Button");
|
|
10
|
+
var _Checkbox = require("../Checkbox");
|
|
10
11
|
var _Icon = require("../Icon");
|
|
12
|
+
var _RadioButton = require("../RadioButton");
|
|
11
13
|
var _Truncate = require("../Truncate");
|
|
12
14
|
var _MenuModule = _interopRequireDefault(require("./Menu.module.css"));
|
|
13
15
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -21,7 +23,9 @@ const MenuOptionButton = props => {
|
|
|
21
23
|
onSelect,
|
|
22
24
|
selectedOption,
|
|
23
25
|
menuDisabled,
|
|
24
|
-
classNames
|
|
26
|
+
classNames,
|
|
27
|
+
optionsVariant = 'normal',
|
|
28
|
+
selectedKeys
|
|
25
29
|
} = props;
|
|
26
30
|
const {
|
|
27
31
|
key,
|
|
@@ -36,12 +40,18 @@ const MenuOptionButton = props => {
|
|
|
36
40
|
optionSize
|
|
37
41
|
} = option;
|
|
38
42
|
const [buttonSize, setButtonSize] = React.useState(optionSize || size);
|
|
43
|
+
const isSelected = () => {
|
|
44
|
+
if (!selectedKeys || !Array.isArray(selectedKeys) || !selectedKeys.length) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return selectedKeys.includes(option.key);
|
|
48
|
+
};
|
|
39
49
|
React.useEffect(() => {
|
|
40
50
|
setButtonSize(optionSize || size);
|
|
41
51
|
}, [optionSize, size]);
|
|
42
52
|
return /*#__PURE__*/React.createElement(_Button.UnstyledButton, {
|
|
43
53
|
className: (0, _classify.classify)(_MenuModule.default.option, {
|
|
44
|
-
[_MenuModule.default.selected]: key === selectedOption?.key,
|
|
54
|
+
[_MenuModule.default.selected]: isSelected() || key === selectedOption?.key,
|
|
45
55
|
[_MenuModule.default.optionSmall]: buttonSize === 'small',
|
|
46
56
|
[_MenuModule.default.optionMedium]: buttonSize === 'medium',
|
|
47
57
|
[_MenuModule.default.disabled]: menuDisabled || disabled,
|
|
@@ -51,7 +61,16 @@ const MenuOptionButton = props => {
|
|
|
51
61
|
disabled: menuDisabled || disabled,
|
|
52
62
|
onClick: () => onSelect && onSelect(option),
|
|
53
63
|
autoFocus: selectedOption?.key === key
|
|
54
|
-
},
|
|
64
|
+
}, optionsVariant === 'checkbox' && /*#__PURE__*/React.createElement(_Checkbox.Checkbox, {
|
|
65
|
+
tabIndex: -1,
|
|
66
|
+
disabled: menuDisabled || disabled,
|
|
67
|
+
checked: isSelected()
|
|
68
|
+
}), optionsVariant === 'radio' && /*#__PURE__*/React.createElement(_RadioButton.RadioButton, {
|
|
69
|
+
disabled: menuDisabled || disabled,
|
|
70
|
+
value: option.key,
|
|
71
|
+
selectedValue: selectedKeys?.[0],
|
|
72
|
+
tabIndex: -1
|
|
73
|
+
}), !!iconLeft && /*#__PURE__*/React.createElement(_Icon.Icon, {
|
|
55
74
|
name: iconLeft,
|
|
56
75
|
type: iconLeftType,
|
|
57
76
|
size: "small",
|
|
@@ -3,30 +3,32 @@ import * as React from 'react';
|
|
|
3
3
|
|
|
4
4
|
import {classify} from '../../utils/classify';
|
|
5
5
|
import {UnstyledButton} from '../Button';
|
|
6
|
+
import {Checkbox} from '../Checkbox';
|
|
6
7
|
import {Icon} from '../Icon';
|
|
8
|
+
import {RadioButton} from '../RadioButton';
|
|
7
9
|
import {Truncate} from '../Truncate';
|
|
8
10
|
|
|
9
|
-
import type {MenuOption} from './Menu';
|
|
11
|
+
import type {BaseMenuProps, MenuOption} from './Menu';
|
|
10
12
|
|
|
11
13
|
import css from './Menu.module.css';
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
type ClassNames = $ReadOnly<{wrapper?: string, option?: string}>;
|
|
15
|
-
|
|
16
16
|
export type MenuOptionProps = {
|
|
17
|
+
...BaseMenuProps,
|
|
17
18
|
option: MenuOption,
|
|
18
|
-
onSelect?: (option: MenuOption) => mixed,
|
|
19
|
-
selectedOption?: MenuOption,
|
|
20
|
-
classNames?: ClassNames,
|
|
21
|
-
size?: 'medium' | 'small',
|
|
22
|
-
width?: string,
|
|
23
|
-
menuDisabled?: boolean,
|
|
24
|
-
isFluid?: boolean,
|
|
25
19
|
};
|
|
26
20
|
|
|
27
21
|
export const MenuOptionButton = (props: MenuOptionProps): React.Node => {
|
|
28
|
-
const {
|
|
29
|
-
|
|
22
|
+
const {
|
|
23
|
+
option,
|
|
24
|
+
size,
|
|
25
|
+
onSelect,
|
|
26
|
+
selectedOption,
|
|
27
|
+
menuDisabled,
|
|
28
|
+
classNames,
|
|
29
|
+
optionsVariant = 'normal',
|
|
30
|
+
selectedKeys,
|
|
31
|
+
} = props;
|
|
30
32
|
const {
|
|
31
33
|
key,
|
|
32
34
|
label,
|
|
@@ -40,6 +42,13 @@ export const MenuOptionButton = (props: MenuOptionProps): React.Node => {
|
|
|
40
42
|
optionSize,
|
|
41
43
|
} = option;
|
|
42
44
|
const [buttonSize, setButtonSize] = React.useState(optionSize || size);
|
|
45
|
+
const isSelected = () => {
|
|
46
|
+
if (!selectedKeys || !Array.isArray(selectedKeys) || !selectedKeys.length) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return selectedKeys.includes(option.key);
|
|
51
|
+
};
|
|
43
52
|
|
|
44
53
|
React.useEffect(() => {
|
|
45
54
|
setButtonSize(optionSize || size);
|
|
@@ -50,7 +59,7 @@ export const MenuOptionButton = (props: MenuOptionProps): React.Node => {
|
|
|
50
59
|
className={classify(
|
|
51
60
|
css.option,
|
|
52
61
|
{
|
|
53
|
-
[css.selected]: key === selectedOption?.key,
|
|
62
|
+
[css.selected]: isSelected() || key === selectedOption?.key,
|
|
54
63
|
[css.optionSmall]: buttonSize === 'small',
|
|
55
64
|
[css.optionMedium]: buttonSize === 'medium',
|
|
56
65
|
[css.disabled]: menuDisabled || disabled,
|
|
@@ -63,6 +72,21 @@ export const MenuOptionButton = (props: MenuOptionProps): React.Node => {
|
|
|
63
72
|
onClick={() => onSelect && onSelect(option)}
|
|
64
73
|
autoFocus={selectedOption?.key === key}
|
|
65
74
|
>
|
|
75
|
+
{optionsVariant === 'checkbox' && (
|
|
76
|
+
<Checkbox
|
|
77
|
+
tabIndex={-1}
|
|
78
|
+
disabled={menuDisabled || disabled}
|
|
79
|
+
checked={isSelected()}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
{optionsVariant === 'radio' && (
|
|
83
|
+
<RadioButton
|
|
84
|
+
disabled={menuDisabled || disabled}
|
|
85
|
+
value={option.key}
|
|
86
|
+
selectedValue={selectedKeys?.[0]}
|
|
87
|
+
tabIndex={-1}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
66
90
|
{!!iconLeft && (
|
|
67
91
|
<Icon
|
|
68
92
|
name={iconLeft}
|
|
@@ -24,6 +24,7 @@ const RadioButton = _ref => {
|
|
|
24
24
|
align = 'vertical',
|
|
25
25
|
className,
|
|
26
26
|
error = false,
|
|
27
|
+
tabIndex = 0,
|
|
27
28
|
...props
|
|
28
29
|
} = _ref;
|
|
29
30
|
const radioInput = /*#__PURE__*/React.createRef();
|
|
@@ -61,7 +62,7 @@ const RadioButton = _ref => {
|
|
|
61
62
|
ref: radioInput,
|
|
62
63
|
onChange: onChangeHandler,
|
|
63
64
|
onKeyDown: onKeyDownHandler,
|
|
64
|
-
tabIndex: disabled ?
|
|
65
|
+
tabIndex: disabled ? -1 : tabIndex,
|
|
65
66
|
name: name,
|
|
66
67
|
value: value || ''
|
|
67
68
|
}, props)), React.Children.count(children) > 0 && /*#__PURE__*/React.createElement(_Text.FormLabelMedium, {
|
|
@@ -26,6 +26,7 @@ export type RadioButtonProps = {
|
|
|
26
26
|
className?: string,
|
|
27
27
|
error?: boolean,
|
|
28
28
|
onChange?: (newValue: string) => mixed,
|
|
29
|
+
tabIndex?: number,
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
export const RadioButton = ({
|
|
@@ -39,6 +40,7 @@ export const RadioButton = ({
|
|
|
39
40
|
align = 'vertical',
|
|
40
41
|
className,
|
|
41
42
|
error = false,
|
|
43
|
+
tabIndex = 0,
|
|
42
44
|
...props
|
|
43
45
|
}: RadioButtonProps): React.Node => {
|
|
44
46
|
const radioInput = React.createRef<HTMLInputElement>();
|
|
@@ -87,7 +89,7 @@ export const RadioButton = ({
|
|
|
87
89
|
ref={radioInput}
|
|
88
90
|
onChange={onChangeHandler}
|
|
89
91
|
onKeyDown={onKeyDownHandler}
|
|
90
|
-
tabIndex={disabled ?
|
|
92
|
+
tabIndex={disabled ? -1 : tabIndex}
|
|
91
93
|
name={name}
|
|
92
94
|
value={value || ''}
|
|
93
95
|
{...props}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
|
+
import type {InputProps} from '../Input';
|
|
5
6
|
import {Input} from '../Input';
|
|
6
7
|
|
|
7
8
|
import css from './SearchInput.module.css';
|
|
@@ -10,29 +11,8 @@ import css from './SearchInput.module.css';
|
|
|
10
11
|
type ClassNames = $ReadOnly<{box?: string, iconLeft?: string}>;
|
|
11
12
|
|
|
12
13
|
export type SearchInputProps = {
|
|
14
|
+
...InputProps,
|
|
13
15
|
classNames?: ClassNames,
|
|
14
|
-
name?: string,
|
|
15
|
-
placeholder?: string,
|
|
16
|
-
disabled?: boolean,
|
|
17
|
-
locked?: boolean,
|
|
18
|
-
value?: string,
|
|
19
|
-
error?: boolean,
|
|
20
|
-
errorText?: string,
|
|
21
|
-
label?: string | React.Node,
|
|
22
|
-
helperText?: string | React.Node,
|
|
23
|
-
size?: 'medium' | 'small',
|
|
24
|
-
required?: boolean,
|
|
25
|
-
boxRef?: (?HTMLElement) => mixed,
|
|
26
|
-
onChange?: (
|
|
27
|
-
evt: SyntheticInputEvent<HTMLInputElement>,
|
|
28
|
-
isEnter?: boolean,
|
|
29
|
-
) => mixed,
|
|
30
|
-
onFocus?: (e: SyntheticInputEvent<HTMLInputElement>) => mixed,
|
|
31
|
-
onBlur?: (e: SyntheticInputEvent<HTMLInputElement>) => mixed,
|
|
32
|
-
onKeyDown?: (e: SyntheticKeyboardEvent<HTMLInputElement>) => mixed,
|
|
33
|
-
onPaste?: (e: ClipboardEvent) => mixed,
|
|
34
|
-
onPaste?: (e: ClipboardEvent) => mixed,
|
|
35
|
-
onContainerClick?: ?(SyntheticEvent<HTMLElement>) => mixed,
|
|
36
16
|
onClear?: () => void,
|
|
37
17
|
};
|
|
38
18
|
|
|
@@ -63,7 +63,7 @@ const Tab = /*#__PURE__*/React.forwardRef((_ref, forwardRef) => {
|
|
|
63
63
|
style: {
|
|
64
64
|
width
|
|
65
65
|
},
|
|
66
|
-
tabIndex: disabled ?
|
|
66
|
+
tabIndex: disabled ? -1 : 0,
|
|
67
67
|
ref: tabRef
|
|
68
68
|
}), /*#__PURE__*/React.createElement("span", {
|
|
69
69
|
className: (0, _classify.classify)(_TabModule.default.iconTextWrap, {
|
|
@@ -74,10 +74,7 @@ const TabList = _ref => {
|
|
|
74
74
|
label
|
|
75
75
|
});
|
|
76
76
|
};
|
|
77
|
-
const
|
|
78
|
-
key: selectedTab?.tabId,
|
|
79
|
-
label: selectedTab?.label || ''
|
|
80
|
-
};
|
|
77
|
+
const selectedKeys = [selectedTab?.tabId || ''];
|
|
81
78
|
const isMenuOptionSelected = (() => {
|
|
82
79
|
for (let i = 0; i < menuOptions.length; i++) {
|
|
83
80
|
if (menuOptions[i].key === selectedTab?.tabId) {
|
|
@@ -102,7 +99,7 @@ const TabList = _ref => {
|
|
|
102
99
|
isFluid: false,
|
|
103
100
|
menuDisabled: false,
|
|
104
101
|
options: menuOptions,
|
|
105
|
-
|
|
102
|
+
selectedKeys,
|
|
106
103
|
width: menuWidth
|
|
107
104
|
}
|
|
108
105
|
}
|
|
@@ -15,10 +15,10 @@ type ClassNames = $ReadOnly<{wrapper?: string}>;
|
|
|
15
15
|
|
|
16
16
|
export type TabListProps = {
|
|
17
17
|
classNames?: ClassNames,
|
|
18
|
-
onSelect?: ({tabId
|
|
18
|
+
onSelect?: ({tabId: string, label?: string}) => mixed,
|
|
19
19
|
children?: React.Node,
|
|
20
20
|
size?: 'medium',
|
|
21
|
-
selectedTab?: {tabId
|
|
21
|
+
selectedTab?: {tabId: string, label?: string},
|
|
22
22
|
menuWidth?: string,
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -80,10 +80,7 @@ export const TabList = ({
|
|
|
80
80
|
const menuOnSelect = ({key, label}) => {
|
|
81
81
|
onSelect && onSelect({tabId: key, label});
|
|
82
82
|
};
|
|
83
|
-
const
|
|
84
|
-
key: selectedTab?.tabId,
|
|
85
|
-
label: selectedTab?.label || '',
|
|
86
|
-
};
|
|
83
|
+
const selectedKeys = [selectedTab?.tabId || ''];
|
|
87
84
|
|
|
88
85
|
const isMenuOptionSelected = (() => {
|
|
89
86
|
for (let i = 0; i < menuOptions.length; i++) {
|
|
@@ -109,7 +106,7 @@ export const TabList = ({
|
|
|
109
106
|
isFluid: false,
|
|
110
107
|
menuDisabled: false,
|
|
111
108
|
options: menuOptions,
|
|
112
|
-
|
|
109
|
+
selectedKeys,
|
|
113
110
|
width: menuWidth,
|
|
114
111
|
},
|
|
115
112
|
}}
|
|
@@ -20,20 +20,21 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
20
20
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
21
21
|
const Typeahead = _ref => {
|
|
22
22
|
let {
|
|
23
|
-
|
|
24
|
-
size,
|
|
23
|
+
size = 'medium',
|
|
25
24
|
classNames,
|
|
26
25
|
placeholder = 'Select...',
|
|
27
26
|
onSelect,
|
|
28
27
|
onSearch,
|
|
29
|
-
selectedOption,
|
|
30
|
-
menuSize,
|
|
31
28
|
onClear,
|
|
29
|
+
menu,
|
|
30
|
+
onMenuOpen,
|
|
31
|
+
onMenuClose,
|
|
32
|
+
typeaheadInputText,
|
|
32
33
|
...inputProps
|
|
33
34
|
} = _ref;
|
|
34
35
|
const typeaheadRef = React.useRef();
|
|
35
|
-
const [inputValue, setInputValue] = React.useState(
|
|
36
|
-
const [filteredOptions, setFilteredOptions] = React.useState(options);
|
|
36
|
+
const [inputValue, setInputValue] = React.useState(typeaheadInputText || '');
|
|
37
|
+
const [filteredOptions, setFilteredOptions] = React.useState(menu?.options);
|
|
37
38
|
const {
|
|
38
39
|
x,
|
|
39
40
|
y,
|
|
@@ -53,12 +54,13 @@ const Typeahead = _ref => {
|
|
|
53
54
|
}
|
|
54
55
|
};
|
|
55
56
|
React.useEffect(() => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
setInputValue(typeaheadInputText || '');
|
|
58
|
+
}, [typeaheadInputText]);
|
|
59
|
+
const onMenuToggle = isOpen => {
|
|
60
|
+
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
61
|
+
};
|
|
60
62
|
React.useEffect(() => {
|
|
61
|
-
const optionsFiltered = options && options.filter(option => {
|
|
63
|
+
const optionsFiltered = menu?.options && menu.options.filter(option => {
|
|
62
64
|
if (!option.label || !inputValue) {
|
|
63
65
|
return true;
|
|
64
66
|
} else {
|
|
@@ -67,7 +69,9 @@ const Typeahead = _ref => {
|
|
|
67
69
|
});
|
|
68
70
|
setFilteredOptions(optionsFiltered || []);
|
|
69
71
|
}, [inputValue]);
|
|
70
|
-
return /*#__PURE__*/React.createElement(_clickAway.ClickAway,
|
|
72
|
+
return /*#__PURE__*/React.createElement(_clickAway.ClickAway, {
|
|
73
|
+
onChange: onMenuToggle
|
|
74
|
+
}, _ref2 => {
|
|
71
75
|
let {
|
|
72
76
|
isOpen,
|
|
73
77
|
onOpen,
|
|
@@ -101,7 +105,7 @@ const Typeahead = _ref => {
|
|
|
101
105
|
setInputValue('');
|
|
102
106
|
onClear?.();
|
|
103
107
|
}
|
|
104
|
-
})), isOpen && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
|
|
108
|
+
})), isOpen && menu && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
|
|
105
109
|
onClickCapture: cancelNext,
|
|
106
110
|
ref: floating,
|
|
107
111
|
style: {
|
|
@@ -111,15 +115,16 @@ const Typeahead = _ref => {
|
|
|
111
115
|
width: _size.sizeFluid,
|
|
112
116
|
backgroundColor: _color.colorBackgroundTertiary
|
|
113
117
|
}
|
|
114
|
-
}, /*#__PURE__*/React.createElement(_Menu.Menu, {
|
|
115
|
-
isFluid: true,
|
|
118
|
+
}, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
|
|
116
119
|
options: filteredOptions,
|
|
117
120
|
onSelect: option => {
|
|
118
121
|
handleSelect(option);
|
|
119
|
-
|
|
122
|
+
if (!menu.optionsVariant || menu.optionsVariant === 'normal') {
|
|
123
|
+
clickAway();
|
|
124
|
+
}
|
|
120
125
|
},
|
|
121
|
-
size:
|
|
122
|
-
})));
|
|
126
|
+
size: menu.size || size
|
|
127
|
+
}))));
|
|
123
128
|
});
|
|
124
129
|
};
|
|
125
130
|
exports.Typeahead = Typeahead;
|
|
@@ -17,7 +17,8 @@ import {sizeFluid} from '../../styles/variables/_size';
|
|
|
17
17
|
import {spaceNone, spaceXXSmall} from '../../styles/variables/_space';
|
|
18
18
|
import {classify} from '../../utils/classify';
|
|
19
19
|
import {ClickAway} from '../../utils/click-away';
|
|
20
|
-
import type {
|
|
20
|
+
import type {InputProps} from '../Input';
|
|
21
|
+
import type {MenuOption, MenuProps} from '../Menu';
|
|
21
22
|
import {Menu} from '../Menu';
|
|
22
23
|
import {SearchInput} from '../SearchInput';
|
|
23
24
|
|
|
@@ -27,43 +28,34 @@ import css from './Typeahead.module.css';
|
|
|
27
28
|
type ClassNames = $ReadOnly<{wrapper?: string, box?: string}>;
|
|
28
29
|
|
|
29
30
|
export type TypeaheadProps = {
|
|
31
|
+
...InputProps,
|
|
30
32
|
classNames?: ClassNames,
|
|
31
33
|
onSelect?: (option: MenuOption) => mixed,
|
|
32
34
|
onSearch?: (evt: SyntheticInputEvent<HTMLInputElement>) => mixed,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
placeholder?: string,
|
|
38
|
-
locked?: boolean,
|
|
39
|
-
error?: boolean,
|
|
40
|
-
errorText?: string,
|
|
41
|
-
label?: string | React.Node,
|
|
42
|
-
helperText?: string | React.Node,
|
|
43
|
-
size?: 'medium' | 'small',
|
|
44
|
-
required?: boolean,
|
|
45
|
-
options?: Array<MenuOption>,
|
|
46
|
-
selectedOption?: MenuOption,
|
|
47
|
-
menuSize?: 'medium' | 'small',
|
|
35
|
+
onMenuOpen?: () => mixed,
|
|
36
|
+
onMenuClose?: () => mixed,
|
|
37
|
+
typeaheadInputText?: string,
|
|
38
|
+
menu?: MenuProps,
|
|
48
39
|
onClear?: () => void,
|
|
49
40
|
};
|
|
50
41
|
|
|
51
42
|
export const Typeahead = ({
|
|
52
|
-
|
|
53
|
-
size,
|
|
43
|
+
size = 'medium',
|
|
54
44
|
classNames,
|
|
55
45
|
placeholder = 'Select...',
|
|
56
46
|
onSelect,
|
|
57
47
|
onSearch,
|
|
58
|
-
selectedOption,
|
|
59
|
-
menuSize,
|
|
60
48
|
onClear,
|
|
49
|
+
menu,
|
|
50
|
+
onMenuOpen,
|
|
51
|
+
onMenuClose,
|
|
52
|
+
typeaheadInputText,
|
|
61
53
|
...inputProps
|
|
62
54
|
}: TypeaheadProps): React.Node => {
|
|
63
55
|
const typeaheadRef = React.useRef();
|
|
64
56
|
|
|
65
|
-
const [inputValue, setInputValue] = React.useState(
|
|
66
|
-
const [filteredOptions, setFilteredOptions] = React.useState(options);
|
|
57
|
+
const [inputValue, setInputValue] = React.useState(typeaheadInputText || '');
|
|
58
|
+
const [filteredOptions, setFilteredOptions] = React.useState(menu?.options);
|
|
67
59
|
|
|
68
60
|
const {x, y, reference, floating, strategy} = useFloating({
|
|
69
61
|
strategy: 'absolute',
|
|
@@ -80,15 +72,17 @@ export const Typeahead = ({
|
|
|
80
72
|
};
|
|
81
73
|
|
|
82
74
|
React.useEffect(() => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
setInputValue(typeaheadInputText || '');
|
|
76
|
+
}, [typeaheadInputText]);
|
|
77
|
+
|
|
78
|
+
const onMenuToggle = (isOpen: boolean) => {
|
|
79
|
+
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
80
|
+
};
|
|
87
81
|
|
|
88
82
|
React.useEffect(() => {
|
|
89
83
|
const optionsFiltered =
|
|
90
|
-
options &&
|
|
91
|
-
options.filter((option) => {
|
|
84
|
+
menu?.options &&
|
|
85
|
+
menu.options.filter((option) => {
|
|
92
86
|
if (!option.label || !inputValue) {
|
|
93
87
|
return true;
|
|
94
88
|
} else {
|
|
@@ -101,7 +95,7 @@ export const Typeahead = ({
|
|
|
101
95
|
}, [inputValue]);
|
|
102
96
|
|
|
103
97
|
return (
|
|
104
|
-
<ClickAway>
|
|
98
|
+
<ClickAway onChange={onMenuToggle}>
|
|
105
99
|
{({isOpen, onOpen, cancelNext, clickAway}) => (
|
|
106
100
|
<div
|
|
107
101
|
data-testid="Typeahead"
|
|
@@ -131,7 +125,7 @@ export const Typeahead = ({
|
|
|
131
125
|
}}
|
|
132
126
|
/>
|
|
133
127
|
|
|
134
|
-
{isOpen && filteredOptions && !!filteredOptions.length && (
|
|
128
|
+
{isOpen && menu && filteredOptions && !!filteredOptions.length && (
|
|
135
129
|
<div
|
|
136
130
|
onClickCapture={cancelNext}
|
|
137
131
|
ref={floating}
|
|
@@ -144,13 +138,18 @@ export const Typeahead = ({
|
|
|
144
138
|
}}
|
|
145
139
|
>
|
|
146
140
|
<Menu
|
|
147
|
-
|
|
141
|
+
{...menu}
|
|
148
142
|
options={filteredOptions}
|
|
149
143
|
onSelect={(option) => {
|
|
150
144
|
handleSelect(option);
|
|
151
|
-
|
|
145
|
+
if (
|
|
146
|
+
!menu.optionsVariant ||
|
|
147
|
+
menu.optionsVariant === 'normal'
|
|
148
|
+
) {
|
|
149
|
+
clickAway();
|
|
150
|
+
}
|
|
152
151
|
}}
|
|
153
|
-
size={
|
|
152
|
+
size={menu.size || size}
|
|
154
153
|
/>
|
|
155
154
|
</div>
|
|
156
155
|
)}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getTextLabelFromSelectedKeys = exports.getSelectedKeysFromSelectedOption = exports.getOptionsFromKeys = exports.getOptionFromKey = exports.getButtonLabelFromSelectedKeys = void 0;
|
|
7
|
+
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
9
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
10
|
+
|
|
11
|
+
const getSelectedKeysFromSelectedOption = (currentOption, currentSelectedKeys) => {
|
|
12
|
+
if (!Array.isArray(currentSelectedKeys) || !currentOption?.key) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
let newSelectedKeys = [];
|
|
16
|
+
if (currentSelectedKeys.includes(currentOption.key)) {
|
|
17
|
+
newSelectedKeys = currentSelectedKeys.filter(item => item !== currentOption.key);
|
|
18
|
+
} else {
|
|
19
|
+
newSelectedKeys = [...currentSelectedKeys, currentOption.key];
|
|
20
|
+
}
|
|
21
|
+
return newSelectedKeys;
|
|
22
|
+
};
|
|
23
|
+
exports.getSelectedKeysFromSelectedOption = getSelectedKeysFromSelectedOption;
|
|
24
|
+
const getTextLabelFromSelectedKeys = (currentSelectedKeys, options) => {
|
|
25
|
+
if (!Array.isArray(currentSelectedKeys) || !Array.isArray(options)) {
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
const selectedOptions = getOptionsFromKeys(options, currentSelectedKeys);
|
|
29
|
+
return selectedOptions.map(option => option.label).join(', ');
|
|
30
|
+
};
|
|
31
|
+
exports.getTextLabelFromSelectedKeys = getTextLabelFromSelectedKeys;
|
|
32
|
+
const getButtonLabelFromSelectedKeys = (currentSelectedKeys, label) => {
|
|
33
|
+
if (!Array.isArray(currentSelectedKeys) || typeof label !== 'string' || !currentSelectedKeys.length) {
|
|
34
|
+
return label;
|
|
35
|
+
}
|
|
36
|
+
return `(${currentSelectedKeys.length}) ${label}`;
|
|
37
|
+
};
|
|
38
|
+
exports.getButtonLabelFromSelectedKeys = getButtonLabelFromSelectedKeys;
|
|
39
|
+
const getOptionFromKey = (options, key) => {
|
|
40
|
+
if (!Array.isArray(options) || !key || !options.length) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return options.find(option => option.key === key);
|
|
44
|
+
};
|
|
45
|
+
exports.getOptionFromKey = getOptionFromKey;
|
|
46
|
+
const getOptionsFromKeys = (options, keys) => {
|
|
47
|
+
if (!Array.isArray(options) || !Array.isArray(keys) || !options.length || !keys.length) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
return options.filter(option => keys.includes(option.key));
|
|
51
|
+
};
|
|
52
|
+
exports.getOptionsFromKeys = getOptionsFromKeys;
|