@spaced-out/ui-design-system 0.1.26 → 0.1.28
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/.cspell/custom-words.txt +7 -0
- package/.storybook/main.js +70 -28
- package/.storybook/manager-head.html +4 -0
- package/.storybook/manager.js +0 -4
- package/.storybook/preview-head.html +32 -6
- package/.storybook/preview.js +0 -5
- package/CHANGELOG.md +41 -0
- package/babel.config.js +1 -0
- package/lib/components/Badge/Badge.module.css +1 -0
- package/lib/components/ButtonDropdown/ButtonDropdown.js +10 -9
- package/lib/components/ButtonDropdown/ButtonDropdown.js.flow +6 -4
- package/lib/components/Checkbox/Checkbox.js +3 -7
- package/lib/components/Checkbox/Checkbox.js.flow +3 -8
- package/lib/components/Chip/Chip.js +1 -1
- package/lib/components/Chip/Chip.js.flow +2 -2
- package/lib/components/CollapsibleCard/CollapsibleCard.js +3 -0
- package/lib/components/CollapsibleCard/CollapsibleCard.js.flow +4 -0
- package/lib/components/Dialog/Dialog.js +23 -2
- package/lib/components/Dialog/Dialog.js.flow +38 -0
- package/lib/components/Dropdown/Dropdown.js +10 -9
- package/lib/components/Dropdown/Dropdown.js.flow +6 -4
- package/lib/components/FocusManager/FocusManager.js +7 -5
- package/lib/components/FocusManager/FocusManager.js.flow +3 -3
- package/lib/components/InlineDropdown/InlineDropdown.js +10 -9
- package/lib/components/InlineDropdown/InlineDropdown.js.flow +6 -4
- package/lib/components/Menu/Menu.js +48 -12
- package/lib/components/Menu/Menu.js.flow +102 -9
- package/lib/components/Menu/Menu.module.css +10 -0
- package/lib/components/Menu/MenuOptionButton.js +21 -4
- package/lib/components/Menu/MenuOptionButton.js.flow +21 -0
- package/lib/components/Modal/Modal.js +35 -8
- package/lib/components/Modal/Modal.js.flow +52 -7
- package/lib/components/Modal/Modal.module.css +1 -3
- package/lib/components/Panel/Panel.js +21 -1
- package/lib/components/Panel/Panel.js.flow +30 -1
- package/lib/components/Panel/Panel.module.css +0 -1
- package/lib/components/Table/DefaultRow.js +5 -5
- package/lib/components/Table/DefaultRow.js.flow +14 -11
- package/lib/components/Table/StaticTable.js +5 -1
- package/lib/components/Table/StaticTable.js.flow +4 -0
- package/lib/components/Table/Table.js.flow +2 -0
- package/lib/components/Tabs/TabList/TabDropdown.js +10 -9
- package/lib/components/Tabs/TabList/TabDropdown.js.flow +6 -4
- package/lib/components/Toast/Toast.js +7 -5
- package/lib/components/Toast/Toast.js.flow +5 -3
- package/lib/components/Tooltip/Tooltip.js +22 -25
- package/lib/components/Tooltip/Tooltip.js.flow +25 -22
- package/lib/components/Typeahead/Typeahead.js +10 -9
- package/lib/components/Typeahead/Typeahead.js.flow +6 -4
- package/lib/hooks/index.js +55 -0
- package/lib/hooks/index.js.flow +5 -0
- package/lib/hooks/useCopyToClipboard.js +31 -0
- package/lib/hooks/useCopyToClipboard.js.flow +31 -0
- package/lib/hooks/useInputState.js +23 -0
- package/lib/hooks/useInputState.js.flow +28 -0
- package/lib/hooks/useLockedBody.js +54 -0
- package/lib/hooks/useLockedBody.js.flow +55 -0
- package/lib/hooks/useToggle.js +18 -0
- package/lib/hooks/useToggle.js.flow +17 -0
- package/lib/hooks/useWindowSize.js +32 -0
- package/lib/hooks/useWindowSize.js.flow +37 -0
- package/lib/styles/typography.module.css +1 -0
- package/lib/types/common.js +0 -1
- package/lib/utils/index.js +11 -0
- package/lib/utils/index.js.flow +1 -0
- package/lib/utils/menu.js +57 -2
- package/lib/utils/menu.js.flow +109 -1
- package/lib/utils/string.js +4 -2
- package/lib/utils/string.js.flow +3 -0
- package/lib/utils/tokens.js +154 -0
- package/lib/utils/tokens.js.flow +228 -0
- package/package.json +19 -16
- package/.storybook/public/favicon.svg +0 -6
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.Dropdown = void 0;
|
|
7
7
|
var React = _interopRequireWildcard(require("react"));
|
|
8
|
-
var
|
|
8
|
+
var _react2 = require("@floating-ui/react");
|
|
9
9
|
var _color = require("../../styles/variables/_color");
|
|
10
10
|
var _size = require("../../styles/variables/_size");
|
|
11
11
|
var _space = require("../../styles/variables/_space");
|
|
@@ -34,14 +34,14 @@ const Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
34
34
|
const {
|
|
35
35
|
x,
|
|
36
36
|
y,
|
|
37
|
-
|
|
38
|
-
floating,
|
|
37
|
+
refs,
|
|
39
38
|
strategy
|
|
40
|
-
} = (0,
|
|
39
|
+
} = (0, _react2.useFloating)({
|
|
40
|
+
open: true,
|
|
41
41
|
strategy: 'absolute',
|
|
42
42
|
placement: 'bottom-start',
|
|
43
|
-
whileElementsMounted:
|
|
44
|
-
middleware: [(0,
|
|
43
|
+
whileElementsMounted: _react2.autoUpdate,
|
|
44
|
+
middleware: [(0, _react2.flip)(), (0, _react2.offset)(parseInt(_space.spaceXXSmall))]
|
|
45
45
|
});
|
|
46
46
|
const onMenuToggle = isOpen => {
|
|
47
47
|
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
@@ -60,7 +60,7 @@ const Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
60
60
|
className: (0, _classify.classify)(_DropdownModule.default.dropdownContainer, classNames?.wrapper),
|
|
61
61
|
ref: dropdownRef
|
|
62
62
|
}, /*#__PURE__*/React.createElement(_Input.Input, _extends({}, inputProps, {
|
|
63
|
-
boxRef:
|
|
63
|
+
boxRef: refs.setReference,
|
|
64
64
|
size: size,
|
|
65
65
|
placeholder: placeholder,
|
|
66
66
|
value: dropdownInputText,
|
|
@@ -76,7 +76,7 @@ const Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
76
76
|
ref: ref
|
|
77
77
|
})), isOpen && menu && /*#__PURE__*/React.createElement("div", {
|
|
78
78
|
onClickCapture: cancelNext,
|
|
79
|
-
ref:
|
|
79
|
+
ref: refs.setFloating,
|
|
80
80
|
style: {
|
|
81
81
|
position: strategy,
|
|
82
82
|
top: y ?? _space.spaceNone,
|
|
@@ -91,7 +91,8 @@ const Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
91
91
|
clickAway();
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
|
-
size: menu.size || size
|
|
94
|
+
size: menu.size || size,
|
|
95
|
+
onTabOut: clickAway
|
|
95
96
|
}))));
|
|
96
97
|
});
|
|
97
98
|
});
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
offset,
|
|
11
11
|
// $FlowFixMe[untyped-import]
|
|
12
12
|
useFloating,
|
|
13
|
-
} from '@floating-ui/react
|
|
13
|
+
} from '@floating-ui/react';
|
|
14
14
|
|
|
15
15
|
import {colorBackgroundTertiary} from '../../styles/variables/_color';
|
|
16
16
|
import {sizeFluid} from '../../styles/variables/_size';
|
|
@@ -57,7 +57,8 @@ export const Dropdown: React$AbstractComponent<
|
|
|
57
57
|
ref,
|
|
58
58
|
): React.Node => {
|
|
59
59
|
const dropdownRef = React.useRef();
|
|
60
|
-
const {x, y,
|
|
60
|
+
const {x, y, refs, strategy} = useFloating({
|
|
61
|
+
open: true,
|
|
61
62
|
strategy: 'absolute',
|
|
62
63
|
placement: 'bottom-start',
|
|
63
64
|
whileElementsMounted: autoUpdate,
|
|
@@ -78,7 +79,7 @@ export const Dropdown: React$AbstractComponent<
|
|
|
78
79
|
>
|
|
79
80
|
<Input
|
|
80
81
|
{...inputProps}
|
|
81
|
-
boxRef={
|
|
82
|
+
boxRef={refs.setReference}
|
|
82
83
|
size={size}
|
|
83
84
|
placeholder={placeholder}
|
|
84
85
|
value={dropdownInputText}
|
|
@@ -95,7 +96,7 @@ export const Dropdown: React$AbstractComponent<
|
|
|
95
96
|
{isOpen && menu && (
|
|
96
97
|
<div
|
|
97
98
|
onClickCapture={cancelNext}
|
|
98
|
-
ref={
|
|
99
|
+
ref={refs.setFloating}
|
|
99
100
|
style={{
|
|
100
101
|
position: strategy,
|
|
101
102
|
top: y ?? spaceNone,
|
|
@@ -116,6 +117,7 @@ export const Dropdown: React$AbstractComponent<
|
|
|
116
117
|
}
|
|
117
118
|
}}
|
|
118
119
|
size={menu.size || size}
|
|
120
|
+
onTabOut={clickAway}
|
|
119
121
|
/>
|
|
120
122
|
</div>
|
|
121
123
|
)}
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.FocusManager = void 0;
|
|
7
7
|
var React = _interopRequireWildcard(require("react"));
|
|
8
|
-
var
|
|
8
|
+
var _react2 = require("@floating-ui/react");
|
|
9
9
|
var _classify = _interopRequireDefault(require("../../utils/classify"));
|
|
10
10
|
var _FocusManagerModule = _interopRequireDefault(require("./FocusManager.module.css"));
|
|
11
11
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -14,20 +14,22 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
14
14
|
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); }
|
|
15
15
|
const FocusManager = props => {
|
|
16
16
|
const {
|
|
17
|
-
|
|
17
|
+
refs,
|
|
18
18
|
context
|
|
19
|
-
} = (0,
|
|
19
|
+
} = (0, _react2.useFloating)({
|
|
20
|
+
open: true
|
|
21
|
+
});
|
|
20
22
|
const {
|
|
21
23
|
classNames,
|
|
22
24
|
children,
|
|
23
25
|
initialFocus = -1,
|
|
24
26
|
...restFloatingFocusManagerProps
|
|
25
27
|
} = props;
|
|
26
|
-
return /*#__PURE__*/React.createElement(
|
|
28
|
+
return /*#__PURE__*/React.createElement(_react2.FloatingFocusManager, _extends({
|
|
27
29
|
context: context,
|
|
28
30
|
initialFocus: initialFocus
|
|
29
31
|
}, restFloatingFocusManagerProps), /*#__PURE__*/React.createElement("div", {
|
|
30
|
-
ref:
|
|
32
|
+
ref: refs.setFloating,
|
|
31
33
|
"data-testid": "FocusManager",
|
|
32
34
|
className: (0, _classify.default)(_FocusManagerModule.default.wrapper, classNames?.wrapper)
|
|
33
35
|
}, children));
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
FloatingFocusManager,
|
|
7
7
|
// $FlowFixMe[untyped-import]
|
|
8
8
|
useFloating,
|
|
9
|
-
} from '@floating-ui/react
|
|
9
|
+
} from '@floating-ui/react';
|
|
10
10
|
|
|
11
11
|
import classify from '../../utils/classify';
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@ export type FocusManagerProps = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
export const FocusManager = (props: FocusManagerProps): React.Node => {
|
|
27
|
-
const {
|
|
27
|
+
const {refs, context} = useFloating({open: true});
|
|
28
28
|
const {
|
|
29
29
|
classNames,
|
|
30
30
|
children,
|
|
@@ -39,7 +39,7 @@ export const FocusManager = (props: FocusManagerProps): React.Node => {
|
|
|
39
39
|
{...restFloatingFocusManagerProps}
|
|
40
40
|
>
|
|
41
41
|
<div
|
|
42
|
-
ref={
|
|
42
|
+
ref={refs.setFloating}
|
|
43
43
|
data-testid="FocusManager"
|
|
44
44
|
className={classify(css.wrapper, classNames?.wrapper)}
|
|
45
45
|
>
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.InlineDropdown = void 0;
|
|
7
7
|
var React = _interopRequireWildcard(require("react"));
|
|
8
|
-
var
|
|
8
|
+
var _react2 = require("@floating-ui/react");
|
|
9
9
|
var _space = require("../../styles/variables/_space");
|
|
10
10
|
var _classify = require("../../utils/classify");
|
|
11
11
|
var _clickAway = require("../../utils/click-away");
|
|
@@ -36,14 +36,14 @@ const InlineDropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
36
36
|
const {
|
|
37
37
|
x,
|
|
38
38
|
y,
|
|
39
|
-
|
|
40
|
-
floating,
|
|
39
|
+
refs,
|
|
41
40
|
strategy
|
|
42
|
-
} = (0,
|
|
41
|
+
} = (0, _react2.useFloating)({
|
|
42
|
+
open: true,
|
|
43
43
|
strategy: 'absolute',
|
|
44
44
|
placement: anchorPosition,
|
|
45
|
-
whileElementsMounted:
|
|
46
|
-
middleware: [(0,
|
|
45
|
+
whileElementsMounted: _react2.autoUpdate,
|
|
46
|
+
middleware: [(0, _react2.shift)(), (0, _react2.flip)(), (0, _react2.offset)(parseInt(_space.spaceXXSmall))]
|
|
47
47
|
});
|
|
48
48
|
const onMenuToggle = isOpen => {
|
|
49
49
|
isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
|
|
@@ -63,7 +63,7 @@ const InlineDropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
63
63
|
ref: menuBtnRef
|
|
64
64
|
}, /*#__PURE__*/React.createElement(_Button.UnstyledButton, _extends({}, restButtonProps, {
|
|
65
65
|
disabled: disabled,
|
|
66
|
-
ref:
|
|
66
|
+
ref: refs.setReference,
|
|
67
67
|
onClick: e => {
|
|
68
68
|
e.stopPropagation();
|
|
69
69
|
onOpen();
|
|
@@ -80,7 +80,7 @@ const InlineDropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
80
80
|
})
|
|
81
81
|
})), isOpen && menu && /*#__PURE__*/React.createElement("div", {
|
|
82
82
|
onClickCapture: cancelNext,
|
|
83
|
-
ref:
|
|
83
|
+
ref: refs.setFloating,
|
|
84
84
|
style: {
|
|
85
85
|
display: 'flex',
|
|
86
86
|
position: strategy,
|
|
@@ -94,7 +94,8 @@ const InlineDropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
94
94
|
clickAway();
|
|
95
95
|
}
|
|
96
96
|
},
|
|
97
|
-
size: menu.size || 'medium'
|
|
97
|
+
size: menu.size || 'medium',
|
|
98
|
+
onTabOut: clickAway
|
|
98
99
|
}))));
|
|
99
100
|
});
|
|
100
101
|
});
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
shift,
|
|
13
13
|
// $FlowFixMe[untyped-import]
|
|
14
14
|
useFloating,
|
|
15
|
-
} from '@floating-ui/react
|
|
15
|
+
} from '@floating-ui/react';
|
|
16
16
|
|
|
17
17
|
import {spaceNone, spaceXXSmall} from '../../styles/variables/_space';
|
|
18
18
|
import {classify} from '../../utils/classify';
|
|
@@ -66,7 +66,8 @@ export const InlineDropdown: React$AbstractComponent<
|
|
|
66
66
|
): React.Node => {
|
|
67
67
|
const menuBtnRef = React.useRef(null);
|
|
68
68
|
React.useImperativeHandle(ref, () => menuBtnRef.current);
|
|
69
|
-
const {x, y,
|
|
69
|
+
const {x, y, refs, strategy} = useFloating({
|
|
70
|
+
open: true,
|
|
70
71
|
strategy: 'absolute',
|
|
71
72
|
placement: anchorPosition,
|
|
72
73
|
whileElementsMounted: autoUpdate,
|
|
@@ -91,7 +92,7 @@ export const InlineDropdown: React$AbstractComponent<
|
|
|
91
92
|
<UnstyledButton
|
|
92
93
|
{...restButtonProps}
|
|
93
94
|
disabled={disabled}
|
|
94
|
-
ref={
|
|
95
|
+
ref={refs.setReference}
|
|
95
96
|
onClick={(e) => {
|
|
96
97
|
e.stopPropagation();
|
|
97
98
|
onOpen();
|
|
@@ -118,7 +119,7 @@ export const InlineDropdown: React$AbstractComponent<
|
|
|
118
119
|
{isOpen && menu && (
|
|
119
120
|
<div
|
|
120
121
|
onClickCapture={cancelNext}
|
|
121
|
-
ref={
|
|
122
|
+
ref={refs.setFloating}
|
|
122
123
|
style={{
|
|
123
124
|
display: 'flex',
|
|
124
125
|
position: strategy,
|
|
@@ -138,6 +139,7 @@ export const InlineDropdown: React$AbstractComponent<
|
|
|
138
139
|
}
|
|
139
140
|
}}
|
|
140
141
|
size={menu.size || 'medium'}
|
|
142
|
+
onTabOut={clickAway}
|
|
141
143
|
/>
|
|
142
144
|
</div>
|
|
143
145
|
)}
|
|
@@ -6,6 +6,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Menu = void 0;
|
|
7
7
|
var React = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _classify = require("../../utils/classify");
|
|
9
|
+
var _menu = require("../../utils/menu");
|
|
10
|
+
var _SearchInput = require("../SearchInput");
|
|
11
|
+
var _Text = require("../Text");
|
|
9
12
|
var _MenuOptionButton = require("./MenuOptionButton");
|
|
10
13
|
var _MenuModule = _interopRequireDefault(require("./Menu.module.css"));
|
|
11
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -18,44 +21,69 @@ const RenderOption = _ref => {
|
|
|
18
21
|
composeOptions,
|
|
19
22
|
groupTitleOptions,
|
|
20
23
|
classNames,
|
|
24
|
+
searchText = '',
|
|
21
25
|
...restProps
|
|
22
26
|
} = _ref;
|
|
27
|
+
const {
|
|
28
|
+
allowSearch
|
|
29
|
+
} = restProps;
|
|
23
30
|
if (options && Array.isArray(options) && options.length) {
|
|
24
|
-
|
|
31
|
+
const optionsFiltered = !allowSearch ? options : (0, _menu.getFilteredOptionsFromSearchText)(options, searchText);
|
|
32
|
+
const resultText = !allowSearch ? '' : (0, _menu.getFilteredOptionsResultText)(optionsFiltered);
|
|
33
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, allowSearch && /*#__PURE__*/React.createElement(_Text.FormLabelSmall, {
|
|
34
|
+
className: _MenuModule.default.filterOptionsResultText,
|
|
35
|
+
color: "tertiary"
|
|
36
|
+
}, resultText), optionsFiltered.map((option, idx) => /*#__PURE__*/React.createElement(React.Fragment, {
|
|
25
37
|
key: option.key
|
|
26
38
|
}, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
|
|
27
39
|
option: option,
|
|
28
40
|
classNames: classNames
|
|
29
|
-
}, restProps
|
|
41
|
+
}, restProps, {
|
|
42
|
+
isLastItem: idx === optionsFiltered.length - 1
|
|
43
|
+
})))));
|
|
30
44
|
}
|
|
31
45
|
if (composeOptions && Array.isArray(composeOptions) && composeOptions.length) {
|
|
32
|
-
|
|
46
|
+
const optionsFiltered = !allowSearch ? composeOptions : (0, _menu.getFilteredComposeOptionsFromSearchText)(composeOptions, searchText);
|
|
47
|
+
const resultText = !allowSearch ? '' : (0, _menu.getFilteredComposeOptionsResultText)(optionsFiltered);
|
|
48
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, allowSearch && /*#__PURE__*/React.createElement(_Text.FormLabelSmall, {
|
|
49
|
+
className: _MenuModule.default.filterOptionsResultText,
|
|
50
|
+
color: "tertiary"
|
|
51
|
+
}, resultText), optionsFiltered.map((composeMenuOptions, index) =>
|
|
33
52
|
/*#__PURE__*/
|
|
34
53
|
// eslint-disable-next-line react/no-array-index-key
|
|
35
54
|
React.createElement("span", {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}, composeMenuOptions.map(option => /*#__PURE__*/React.createElement(React.Fragment, {
|
|
55
|
+
key: index,
|
|
56
|
+
className: _MenuModule.default.menuDivider
|
|
57
|
+
}, composeMenuOptions.map((option, idx) => /*#__PURE__*/React.createElement(React.Fragment, {
|
|
39
58
|
key: option.key
|
|
40
59
|
}, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
|
|
41
60
|
option: option,
|
|
42
61
|
classNames: classNames
|
|
43
|
-
}, restProps
|
|
62
|
+
}, restProps, {
|
|
63
|
+
isLastItem: index === optionsFiltered.length - 1 && idx === composeMenuOptions.length - 1
|
|
64
|
+
})))))));
|
|
44
65
|
}
|
|
45
66
|
if (groupTitleOptions && Array.isArray(groupTitleOptions) && groupTitleOptions.length) {
|
|
46
|
-
|
|
67
|
+
const optionsFiltered = !allowSearch ? groupTitleOptions : (0, _menu.getFilteredGroupTitleOptionsFromSearchText)(groupTitleOptions, searchText);
|
|
68
|
+
const resultText = !allowSearch ? '' : (0, _menu.getFilteredGroupTitleOptionsResultText)(optionsFiltered);
|
|
69
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, allowSearch && /*#__PURE__*/React.createElement(_Text.FormLabelSmall, {
|
|
70
|
+
className: _MenuModule.default.filterOptionsResultText,
|
|
71
|
+
color: "tertiary"
|
|
72
|
+
}, resultText), optionsFiltered.map((optionsGroup, index) =>
|
|
47
73
|
/*#__PURE__*/
|
|
48
74
|
// eslint-disable-next-line react/no-array-index-key
|
|
49
75
|
React.createElement(React.Fragment, {
|
|
50
76
|
key: index
|
|
51
77
|
}, !!optionsGroup.groupTitle && /*#__PURE__*/React.createElement("div", {
|
|
52
78
|
className: (0, _classify.classify)(_MenuModule.default.groupTitleWrapper, classNames?.groupTitle)
|
|
53
|
-
}, optionsGroup.groupTitle), optionsGroup.options?.map(option => /*#__PURE__*/React.createElement(React.Fragment, {
|
|
79
|
+
}, optionsGroup.groupTitle), optionsGroup.options?.map((option, idx) => /*#__PURE__*/React.createElement(React.Fragment, {
|
|
54
80
|
key: option.key
|
|
55
81
|
}, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
|
|
56
82
|
option: option,
|
|
57
83
|
classNames: classNames
|
|
58
|
-
}, restProps
|
|
84
|
+
}, restProps, {
|
|
85
|
+
isLastItem: index === optionsFiltered.length - 1 && idx === (optionsGroup.options && optionsGroup.options.length - 1)
|
|
86
|
+
})))))));
|
|
59
87
|
}
|
|
60
88
|
return /*#__PURE__*/React.createElement(React.Fragment, null);
|
|
61
89
|
};
|
|
@@ -64,8 +92,10 @@ const Menu = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
64
92
|
classNames,
|
|
65
93
|
size = 'medium',
|
|
66
94
|
width,
|
|
67
|
-
isFluid = true
|
|
95
|
+
isFluid = true,
|
|
96
|
+
allowSearch
|
|
68
97
|
} = props;
|
|
98
|
+
const [searchText, setSearchText] = React.useState('');
|
|
69
99
|
return /*#__PURE__*/React.createElement("div", {
|
|
70
100
|
className: (0, _classify.classify)(_MenuModule.default.menuCard, {
|
|
71
101
|
[_MenuModule.default.fluid]: isFluid,
|
|
@@ -76,6 +106,12 @@ const Menu = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
76
106
|
width
|
|
77
107
|
},
|
|
78
108
|
ref: ref
|
|
79
|
-
}, /*#__PURE__*/React.createElement(
|
|
109
|
+
}, allowSearch && /*#__PURE__*/React.createElement(_SearchInput.SearchInput, {
|
|
110
|
+
value: searchText,
|
|
111
|
+
onChange: e => setSearchText(e.target.value),
|
|
112
|
+
onClear: () => setSearchText('')
|
|
113
|
+
}), /*#__PURE__*/React.createElement(RenderOption, _extends({}, props, {
|
|
114
|
+
searchText: searchText
|
|
115
|
+
})));
|
|
80
116
|
});
|
|
81
117
|
exports.Menu = Menu;
|
|
@@ -2,7 +2,17 @@
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
import {classify} from '../../utils/classify';
|
|
5
|
+
import {
|
|
6
|
+
getFilteredComposeOptionsFromSearchText,
|
|
7
|
+
getFilteredComposeOptionsResultText,
|
|
8
|
+
getFilteredGroupTitleOptionsFromSearchText,
|
|
9
|
+
getFilteredGroupTitleOptionsResultText,
|
|
10
|
+
getFilteredOptionsFromSearchText,
|
|
11
|
+
getFilteredOptionsResultText,
|
|
12
|
+
} from '../../utils/menu';
|
|
5
13
|
import type {IconType} from '../Icon/Icon';
|
|
14
|
+
import {SearchInput} from '../SearchInput';
|
|
15
|
+
import {FormLabelSmall} from '../Text';
|
|
6
16
|
|
|
7
17
|
import {MenuOptionButton} from './MenuOptionButton';
|
|
8
18
|
|
|
@@ -43,6 +53,10 @@ export type BaseMenuProps = {
|
|
|
43
53
|
width?: string,
|
|
44
54
|
menuDisabled?: boolean,
|
|
45
55
|
isFluid?: boolean,
|
|
56
|
+
// onTabOut is a callback function that is called when
|
|
57
|
+
// the user navigates outside of the menu using the tab key.
|
|
58
|
+
onTabOut?: () => mixed,
|
|
59
|
+
allowSearch?: boolean,
|
|
46
60
|
};
|
|
47
61
|
|
|
48
62
|
export type MenuOptionTypes = {
|
|
@@ -65,22 +79,45 @@ export type MenuProps = {
|
|
|
65
79
|
...MenuOptionTypes,
|
|
66
80
|
};
|
|
67
81
|
|
|
82
|
+
export type RenderOptionProps = {
|
|
83
|
+
...MenuProps,
|
|
84
|
+
searchText?: string,
|
|
85
|
+
};
|
|
86
|
+
|
|
68
87
|
const RenderOption = ({
|
|
69
88
|
options,
|
|
70
89
|
composeOptions,
|
|
71
90
|
groupTitleOptions,
|
|
72
91
|
classNames,
|
|
92
|
+
searchText = '',
|
|
73
93
|
...restProps
|
|
74
|
-
}:
|
|
94
|
+
}: RenderOptionProps): React.Node => {
|
|
95
|
+
const {allowSearch} = restProps;
|
|
75
96
|
if (options && Array.isArray(options) && options.length) {
|
|
97
|
+
const optionsFiltered = !allowSearch
|
|
98
|
+
? options
|
|
99
|
+
: getFilteredOptionsFromSearchText(options, searchText);
|
|
100
|
+
const resultText = !allowSearch
|
|
101
|
+
? ''
|
|
102
|
+
: getFilteredOptionsResultText(optionsFiltered);
|
|
103
|
+
|
|
76
104
|
return (
|
|
77
105
|
<>
|
|
78
|
-
{
|
|
106
|
+
{allowSearch && (
|
|
107
|
+
<FormLabelSmall
|
|
108
|
+
className={css.filterOptionsResultText}
|
|
109
|
+
color="tertiary"
|
|
110
|
+
>
|
|
111
|
+
{resultText}
|
|
112
|
+
</FormLabelSmall>
|
|
113
|
+
)}
|
|
114
|
+
{optionsFiltered.map((option, idx) => (
|
|
79
115
|
<React.Fragment key={option.key}>
|
|
80
116
|
<MenuOptionButton
|
|
81
117
|
option={option}
|
|
82
118
|
classNames={classNames}
|
|
83
119
|
{...restProps}
|
|
120
|
+
isLastItem={idx === optionsFiltered.length - 1}
|
|
84
121
|
/>
|
|
85
122
|
</React.Fragment>
|
|
86
123
|
))}
|
|
@@ -92,17 +129,36 @@ const RenderOption = ({
|
|
|
92
129
|
Array.isArray(composeOptions) &&
|
|
93
130
|
composeOptions.length
|
|
94
131
|
) {
|
|
132
|
+
const optionsFiltered = !allowSearch
|
|
133
|
+
? composeOptions
|
|
134
|
+
: getFilteredComposeOptionsFromSearchText(composeOptions, searchText);
|
|
135
|
+
const resultText = !allowSearch
|
|
136
|
+
? ''
|
|
137
|
+
: getFilteredComposeOptionsResultText(optionsFiltered);
|
|
138
|
+
|
|
95
139
|
return (
|
|
96
140
|
<>
|
|
97
|
-
{
|
|
141
|
+
{allowSearch && (
|
|
142
|
+
<FormLabelSmall
|
|
143
|
+
className={css.filterOptionsResultText}
|
|
144
|
+
color="tertiary"
|
|
145
|
+
>
|
|
146
|
+
{resultText}
|
|
147
|
+
</FormLabelSmall>
|
|
148
|
+
)}
|
|
149
|
+
{optionsFiltered.map((composeMenuOptions, index) => (
|
|
98
150
|
// eslint-disable-next-line react/no-array-index-key
|
|
99
|
-
<span className={css.menuDivider}
|
|
100
|
-
{composeMenuOptions.map((option) => (
|
|
151
|
+
<span key={index} className={css.menuDivider}>
|
|
152
|
+
{composeMenuOptions.map((option, idx) => (
|
|
101
153
|
<React.Fragment key={option.key}>
|
|
102
154
|
<MenuOptionButton
|
|
103
155
|
option={option}
|
|
104
156
|
classNames={classNames}
|
|
105
157
|
{...restProps}
|
|
158
|
+
isLastItem={
|
|
159
|
+
index === optionsFiltered.length - 1 &&
|
|
160
|
+
idx === composeMenuOptions.length - 1
|
|
161
|
+
}
|
|
106
162
|
/>
|
|
107
163
|
</React.Fragment>
|
|
108
164
|
))}
|
|
@@ -116,9 +172,27 @@ const RenderOption = ({
|
|
|
116
172
|
Array.isArray(groupTitleOptions) &&
|
|
117
173
|
groupTitleOptions.length
|
|
118
174
|
) {
|
|
175
|
+
const optionsFiltered = !allowSearch
|
|
176
|
+
? groupTitleOptions
|
|
177
|
+
: getFilteredGroupTitleOptionsFromSearchText(
|
|
178
|
+
groupTitleOptions,
|
|
179
|
+
searchText,
|
|
180
|
+
);
|
|
181
|
+
const resultText = !allowSearch
|
|
182
|
+
? ''
|
|
183
|
+
: getFilteredGroupTitleOptionsResultText(optionsFiltered);
|
|
184
|
+
|
|
119
185
|
return (
|
|
120
186
|
<>
|
|
121
|
-
{
|
|
187
|
+
{allowSearch && (
|
|
188
|
+
<FormLabelSmall
|
|
189
|
+
className={css.filterOptionsResultText}
|
|
190
|
+
color="tertiary"
|
|
191
|
+
>
|
|
192
|
+
{resultText}
|
|
193
|
+
</FormLabelSmall>
|
|
194
|
+
)}
|
|
195
|
+
{optionsFiltered.map((optionsGroup, index) => (
|
|
122
196
|
// eslint-disable-next-line react/no-array-index-key
|
|
123
197
|
<React.Fragment key={index}>
|
|
124
198
|
{!!optionsGroup.groupTitle && (
|
|
@@ -132,12 +206,17 @@ const RenderOption = ({
|
|
|
132
206
|
</div>
|
|
133
207
|
)}
|
|
134
208
|
|
|
135
|
-
{optionsGroup.options?.map((option) => (
|
|
209
|
+
{optionsGroup.options?.map((option, idx) => (
|
|
136
210
|
<React.Fragment key={option.key}>
|
|
137
211
|
<MenuOptionButton
|
|
138
212
|
option={option}
|
|
139
213
|
classNames={classNames}
|
|
140
214
|
{...restProps}
|
|
215
|
+
isLastItem={
|
|
216
|
+
index === optionsFiltered.length - 1 &&
|
|
217
|
+
idx ===
|
|
218
|
+
(optionsGroup.options && optionsGroup.options.length - 1)
|
|
219
|
+
}
|
|
141
220
|
/>
|
|
142
221
|
</React.Fragment>
|
|
143
222
|
))}
|
|
@@ -152,7 +231,14 @@ const RenderOption = ({
|
|
|
152
231
|
export const Menu: React$AbstractComponent<MenuProps, HTMLDivElement> =
|
|
153
232
|
React.forwardRef<MenuProps, HTMLDivElement>(
|
|
154
233
|
(props: MenuProps, ref): React.Node => {
|
|
155
|
-
const {
|
|
234
|
+
const {
|
|
235
|
+
classNames,
|
|
236
|
+
size = 'medium',
|
|
237
|
+
width,
|
|
238
|
+
isFluid = true,
|
|
239
|
+
allowSearch,
|
|
240
|
+
} = props;
|
|
241
|
+
const [searchText, setSearchText] = React.useState('');
|
|
156
242
|
|
|
157
243
|
return (
|
|
158
244
|
<div
|
|
@@ -168,7 +254,14 @@ export const Menu: React$AbstractComponent<MenuProps, HTMLDivElement> =
|
|
|
168
254
|
style={{width}}
|
|
169
255
|
ref={ref}
|
|
170
256
|
>
|
|
171
|
-
|
|
257
|
+
{allowSearch && (
|
|
258
|
+
<SearchInput
|
|
259
|
+
value={searchText}
|
|
260
|
+
onChange={(e) => setSearchText(e.target.value)}
|
|
261
|
+
onClear={() => setSearchText('')}
|
|
262
|
+
/>
|
|
263
|
+
)}
|
|
264
|
+
<RenderOption {...props} searchText={searchText} />
|
|
172
265
|
</div>
|
|
173
266
|
);
|
|
174
267
|
},
|
|
@@ -191,6 +191,10 @@
|
|
|
191
191
|
padding-bottom: spaceXSmall;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
.hideDivider {
|
|
195
|
+
border-top: none;
|
|
196
|
+
}
|
|
197
|
+
|
|
194
198
|
.menuDivider:first-child {
|
|
195
199
|
padding-top: spaceNone;
|
|
196
200
|
}
|
|
@@ -213,3 +217,9 @@
|
|
|
213
217
|
color: colorTextTertiary;
|
|
214
218
|
padding-top: spaceSmall;
|
|
215
219
|
}
|
|
220
|
+
|
|
221
|
+
.filterOptionsResultText {
|
|
222
|
+
margin-top: calc(spaceXSmall * 2);
|
|
223
|
+
margin-bottom: spaceXSmall;
|
|
224
|
+
margin-left: spaceSmall;
|
|
225
|
+
}
|
|
@@ -15,8 +15,9 @@ var _MenuModule = _interopRequireDefault(require("./Menu.module.css"));
|
|
|
15
15
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
16
|
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); }
|
|
17
17
|
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; }
|
|
18
|
-
|
|
18
|
+
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); }
|
|
19
19
|
const MenuOptionButton = props => {
|
|
20
|
+
const lastMenuItemRef = React.useRef(null);
|
|
20
21
|
const {
|
|
21
22
|
option,
|
|
22
23
|
size,
|
|
@@ -25,7 +26,9 @@ const MenuOptionButton = props => {
|
|
|
25
26
|
menuDisabled,
|
|
26
27
|
classNames,
|
|
27
28
|
optionsVariant = 'normal',
|
|
28
|
-
selectedKeys
|
|
29
|
+
selectedKeys,
|
|
30
|
+
isLastItem,
|
|
31
|
+
onTabOut
|
|
29
32
|
} = props;
|
|
30
33
|
const {
|
|
31
34
|
key,
|
|
@@ -50,7 +53,19 @@ const MenuOptionButton = props => {
|
|
|
50
53
|
React.useEffect(() => {
|
|
51
54
|
setButtonSize(optionSize || size);
|
|
52
55
|
}, [optionSize, size]);
|
|
53
|
-
|
|
56
|
+
React.useEffect(() => {
|
|
57
|
+
const handleKeyDown = event => {
|
|
58
|
+
if (event.key === 'Tab' && !event.shiftKey) {
|
|
59
|
+
// Tab pressed without shift key, calling tab out callback
|
|
60
|
+
onTabOut?.();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
lastMenuItemRef.current?.addEventListener('keydown', handleKeyDown);
|
|
64
|
+
return () => {
|
|
65
|
+
lastMenuItemRef.current?.removeEventListener('keydown', handleKeyDown);
|
|
66
|
+
};
|
|
67
|
+
}, [isLastItem]);
|
|
68
|
+
return /*#__PURE__*/React.createElement(_Button.UnstyledButton, _extends({
|
|
54
69
|
className: (0, _classify.classify)(_MenuModule.default.option, {
|
|
55
70
|
[_MenuModule.default.selected]: isSelected() || key === selectedOption?.key,
|
|
56
71
|
[_MenuModule.default.optionSmall]: buttonSize === 'small',
|
|
@@ -62,7 +77,9 @@ const MenuOptionButton = props => {
|
|
|
62
77
|
disabled: menuDisabled || disabled,
|
|
63
78
|
onClick: () => onSelect && onSelect(option),
|
|
64
79
|
autoFocus: selectedOption?.key === key
|
|
65
|
-
},
|
|
80
|
+
}, isLastItem ? {
|
|
81
|
+
ref: lastMenuItemRef
|
|
82
|
+
} : {}), optionVariant === 'checkbox' && /*#__PURE__*/React.createElement(_Checkbox.Checkbox, {
|
|
66
83
|
tabIndex: -1,
|
|
67
84
|
disabled: menuDisabled || disabled,
|
|
68
85
|
checked: isSelected()
|