@spaced-out/ui-design-system 0.0.68 → 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.
Files changed (30) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/lib/components/ButtonDropdown/ButtonDropdown.js +4 -2
  3. package/lib/components/ButtonDropdown/ButtonDropdown.js.flow +8 -3
  4. package/lib/components/Checkbox/Checkbox.js +3 -2
  5. package/lib/components/Checkbox/Checkbox.js.flow +3 -1
  6. package/lib/components/Chip/Chip.module.css +1 -0
  7. package/lib/components/Dropdown/Dropdown.js +22 -28
  8. package/lib/components/Dropdown/Dropdown.js.flow +30 -47
  9. package/lib/components/InlineDropdown/InlineDropdown.js +5 -2
  10. package/lib/components/InlineDropdown/InlineDropdown.js.flow +8 -2
  11. package/lib/components/Input/Input.js +2 -1
  12. package/lib/components/Input/Input.js.flow +1 -0
  13. package/lib/components/Input/Input.module.css +15 -2
  14. package/lib/components/Menu/Menu.js +8 -4
  15. package/lib/components/Menu/Menu.js.flow +43 -13
  16. package/lib/components/Menu/Menu.module.css +19 -2
  17. package/lib/components/Menu/MenuOptionButton.js +22 -3
  18. package/lib/components/Menu/MenuOptionButton.js.flow +37 -13
  19. package/lib/components/RadioButton/RadioButton.js +2 -1
  20. package/lib/components/RadioButton/RadioButton.js.flow +3 -1
  21. package/lib/components/SearchInput/SearchInput.js.flow +2 -22
  22. package/lib/components/Tabs/Tab/Tab.js +1 -1
  23. package/lib/components/Tabs/Tab/Tab.js.flow +1 -1
  24. package/lib/components/Tabs/TabList/TabList.js +2 -5
  25. package/lib/components/Tabs/TabList/TabList.js.flow +4 -7
  26. package/lib/components/Typeahead/Typeahead.js +23 -18
  27. package/lib/components/Typeahead/Typeahead.js.flow +32 -33
  28. package/lib/utils/menu.js +52 -0
  29. package/lib/utils/menu.js.flow +81 -0
  30. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
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.0](https://github.com/spaced-out/ui-design-system/compare/v0.0.68...v0.1.0) (2023-03-31)
6
+
7
+
8
+ ### Features
9
+
10
+ * ⚠️ menu component extension dropdown and typeahead refactor ⚠️ ([#86](https://github.com/spaced-out/ui-design-system/issues/86)) ([621e61c](https://github.com/spaced-out/ui-design-system/commit/621e61c33e45a507c8e5da1c42b075a30fb45331))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * chip transition states ([f526338](https://github.com/spaced-out/ui-design-system/commit/f52633859e11facdc5ff5663026f26b0b0260c62))
16
+ * color swatch fix ([77de191](https://github.com/spaced-out/ui-design-system/commit/77de191670d0538b09dea8d7a4a130416e5f9361))
17
+
5
18
  ### [0.0.68](https://github.com/spaced-out/ui-design-system/compare/v0.0.67...v0.0.68) (2023-03-30)
6
19
 
7
20
 
@@ -29,7 +29,7 @@ exports.ANCHOR_POSITION_TYPE = ANCHOR_POSITION_TYPE;
29
29
  const ButtonDropdown = /*#__PURE__*/React.forwardRef((_ref, forwardRef) => {
30
30
  let {
31
31
  anchorPosition = 'bottom-start',
32
- size,
32
+ size = 'medium',
33
33
  onOptionSelect,
34
34
  menu,
35
35
  classNames,
@@ -103,7 +103,9 @@ const ButtonDropdown = /*#__PURE__*/React.forwardRef((_ref, forwardRef) => {
103
103
  }, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
104
104
  onSelect: option => {
105
105
  onOptionSelect && onOptionSelect(option);
106
- clickAway();
106
+ if (!menu.optionsVariant || menu.optionsVariant === 'normal') {
107
+ clickAway();
108
+ }
107
109
  },
108
110
  size: menu.size || size
109
111
  }))));
@@ -44,7 +44,7 @@ type ClassNames = $ReadOnly<{
44
44
  export type ButtonDropdownProps = {
45
45
  ...ButtonProps,
46
46
  classNames?: ClassNames,
47
- menu: MenuProps,
47
+ menu?: MenuProps,
48
48
  anchorPosition?: AnchorType,
49
49
  onOptionSelect?: (option: MenuOption) => mixed,
50
50
  onMenuOpen?: () => mixed,
@@ -59,7 +59,7 @@ export const ButtonDropdown: React$AbstractComponent<
59
59
  (
60
60
  {
61
61
  anchorPosition = 'bottom-start',
62
- size,
62
+ size = 'medium',
63
63
  onOptionSelect,
64
64
  menu,
65
65
  classNames,
@@ -138,7 +138,12 @@ export const ButtonDropdown: React$AbstractComponent<
138
138
  {...menu}
139
139
  onSelect={(option) => {
140
140
  onOptionSelect && onOptionSelect(option);
141
- clickAway();
141
+ if (
142
+ !menu.optionsVariant ||
143
+ menu.optionsVariant === 'normal'
144
+ ) {
145
+ clickAway();
146
+ }
142
147
  }}
143
148
  size={menu.size || size}
144
149
  />
@@ -25,7 +25,8 @@ const Checkbox = _ref => {
25
25
  error = false,
26
26
  onChange,
27
27
  align,
28
- classNames
28
+ classNames,
29
+ tabIndex = 0
29
30
  } = _ref;
30
31
  const checkboxInput = /*#__PURE__*/React.createRef();
31
32
  const handleOnChange = () => {
@@ -61,12 +62,12 @@ const Checkbox = _ref => {
61
62
  [_CheckboxModule.default.disabled]: disabled
62
63
  })
63
64
  }, /*#__PURE__*/React.createElement("input", {
65
+ tabIndex: disabled ? -1 : tabIndex,
64
66
  type: "checkbox",
65
67
  value: value,
66
68
  checked: checked,
67
69
  ref: checkboxInput,
68
70
  onChange: handleOnChange,
69
- tabIndex: disabled ? '-1' : 0,
70
71
  className: (0, _classify.default)(_CheckboxModule.default.inputCheckbox),
71
72
  disabled: disabled,
72
73
  name: name
@@ -29,6 +29,7 @@ export type CheckboxProps = {
29
29
  onChange?: ({value: string, checked: boolean}) => mixed,
30
30
  align?: GroupAlign,
31
31
  classNames?: ClassNames,
32
+ tabIndex?: number,
32
33
  };
33
34
 
34
35
  export const Checkbox = ({
@@ -43,6 +44,7 @@ export const Checkbox = ({
43
44
  onChange,
44
45
  align,
45
46
  classNames,
47
+ tabIndex = 0,
46
48
  }: CheckboxProps): React.Node => {
47
49
  const checkboxInput = React.createRef<HTMLInputElement>();
48
50
 
@@ -90,12 +92,12 @@ export const Checkbox = ({
90
92
  })}
91
93
  >
92
94
  <input
95
+ tabIndex={disabled ? -1 : tabIndex}
93
96
  type="checkbox"
94
97
  value={value}
95
98
  checked={checked}
96
99
  ref={checkboxInput}
97
100
  onChange={handleOnChange}
98
- tabIndex={disabled ? '-1' : 0}
99
101
  className={classify(css.inputCheckbox)}
100
102
  disabled={disabled}
101
103
  name={name}
@@ -30,6 +30,7 @@
30
30
 
31
31
  .chipWrapper {
32
32
  composes: formLabelSmall from '../../styles/typography.module.css';
33
+ composes: motionEaseInEaseOut from '../../styles/animation.module.css';
33
34
  display: flex;
34
35
  background-color: colorNeutralLightest;
35
36
  align-items: center;
@@ -20,18 +20,17 @@ 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 Dropdown = _ref => {
22
22
  let {
23
- options,
24
- composeOptions,
25
- groupTitleOptions,
26
- size,
23
+ size = 'medium',
27
24
  classNames,
28
25
  placeholder = 'Select...',
29
26
  onChange,
30
- selectedOption,
31
- menuSize,
27
+ menu,
28
+ onMenuOpen,
29
+ onMenuClose,
30
+ dropdownInputText,
32
31
  ...inputProps
33
32
  } = _ref;
34
- const [inputValue, setInputValue] = React.useState(selectedOption?.label || '');
33
+ const [inputValue, setInputValue] = React.useState(dropdownInputText || '');
35
34
  const dropdownRef = React.useRef();
36
35
  const {
37
36
  x,
@@ -45,18 +44,15 @@ const Dropdown = _ref => {
45
44
  whileElementsMounted: _reactDom.autoUpdate,
46
45
  middleware: [(0, _reactDom.flip)(), (0, _reactDom.offset)(parseInt(_space.spaceXXSmall))]
47
46
  });
48
- const handleSelect = option => {
49
- if (option?.key) {
50
- onChange && onChange(option);
51
- setInputValue(option.label || '');
52
- }
53
- };
54
47
  React.useEffect(() => {
55
- if (selectedOption?.key) {
56
- setInputValue(selectedOption.label || '');
57
- }
58
- }, [selectedOption]);
59
- return /*#__PURE__*/React.createElement(_clickAway.ClickAway, null, _ref2 => {
48
+ setInputValue(dropdownInputText || '');
49
+ }, [dropdownInputText]);
50
+ const onMenuToggle = isOpen => {
51
+ isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
52
+ };
53
+ return /*#__PURE__*/React.createElement(_clickAway.ClickAway, {
54
+ onChange: onMenuToggle
55
+ }, _ref2 => {
60
56
  let {
61
57
  isOpen,
62
58
  onOpen,
@@ -82,7 +78,7 @@ const Dropdown = _ref => {
82
78
  e.stopPropagation();
83
79
  onOpen();
84
80
  }
85
- })), isOpen && (options || composeOptions || groupTitleOptions) && /*#__PURE__*/React.createElement("div", {
81
+ })), isOpen && menu && /*#__PURE__*/React.createElement("div", {
86
82
  onClickCapture: cancelNext,
87
83
  ref: floating,
88
84
  style: {
@@ -92,17 +88,15 @@ const Dropdown = _ref => {
92
88
  width: _size.sizeFluid,
93
89
  backgroundColor: _color.colorBackgroundTertiary
94
90
  }
95
- }, /*#__PURE__*/React.createElement(_Menu.Menu, {
96
- isFluid: true,
97
- options: options,
98
- composeOptions: composeOptions,
99
- groupTitleOptions: groupTitleOptions,
91
+ }, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
100
92
  onSelect: option => {
101
- handleSelect(option);
102
- clickAway();
93
+ onChange && onChange(option);
94
+ if (!menu.optionsVariant || menu.optionsVariant === 'normal') {
95
+ clickAway();
96
+ }
103
97
  },
104
- size: menuSize || size
105
- })));
98
+ size: menu.size || size
99
+ }))));
106
100
  });
107
101
  };
108
102
  exports.Dropdown = Dropdown;
@@ -17,8 +17,9 @@ 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 {InputProps} from '../Input';
20
21
  import {Input} from '../Input';
21
- import type {MenuGroupTitleOption, MenuOption} from '../Menu';
22
+ import type {MenuOption, MenuProps} from '../Menu';
22
23
  import {Menu} from '../Menu';
23
24
 
24
25
  import css from './Dropdown.module.css';
@@ -27,42 +28,27 @@ import css from './Dropdown.module.css';
27
28
  type ClassNames = $ReadOnly<{wrapper?: string, box?: string}>;
28
29
 
29
30
  export type DropdownProps = {
31
+ ...InputProps,
30
32
  classNames?: ClassNames,
31
33
  onChange?: (option: MenuOption) => mixed,
32
- onFocus?: (e: SyntheticInputEvent<HTMLInputElement>) => mixed,
33
- onBlur?: (e: SyntheticInputEvent<HTMLInputElement>) => mixed,
34
- name?: string,
35
- disabled?: boolean,
36
- placeholder?: string,
37
- locked?: boolean,
38
- error?: boolean,
39
- errorText?: string,
40
- label?: string | React.Node,
41
- helperText?: string | React.Node,
42
- size?: 'medium' | 'small',
43
- required?: boolean,
44
- options?: Array<MenuOption>,
45
- composeOptions?: Array<Array<MenuOption>>,
46
- groupTitleOptions?: Array<MenuGroupTitleOption>,
47
- selectedOption?: MenuOption,
48
- menuSize?: 'medium' | 'small',
34
+ onMenuOpen?: () => mixed,
35
+ onMenuClose?: () => mixed,
36
+ dropdownInputText?: string,
37
+ menu?: MenuProps,
49
38
  };
50
39
 
51
40
  export const Dropdown = ({
52
- options,
53
- composeOptions,
54
- groupTitleOptions,
55
- size,
41
+ size = 'medium',
56
42
  classNames,
57
43
  placeholder = 'Select...',
58
44
  onChange,
59
- selectedOption,
60
- menuSize,
45
+ menu,
46
+ onMenuOpen,
47
+ onMenuClose,
48
+ dropdownInputText,
61
49
  ...inputProps
62
50
  }: DropdownProps): React.Node => {
63
- const [inputValue, setInputValue] = React.useState(
64
- selectedOption?.label || '',
65
- );
51
+ const [inputValue, setInputValue] = React.useState(dropdownInputText || '');
66
52
  const dropdownRef = React.useRef();
67
53
  const {x, y, reference, floating, strategy} = useFloating({
68
54
  strategy: 'absolute',
@@ -71,21 +57,16 @@ export const Dropdown = ({
71
57
  middleware: [flip(), offset(parseInt(spaceXXSmall))],
72
58
  });
73
59
 
74
- const handleSelect = (option?: MenuOption) => {
75
- if (option?.key) {
76
- onChange && onChange(option);
77
- setInputValue(option.label || '');
78
- }
79
- };
80
-
81
60
  React.useEffect(() => {
82
- if (selectedOption?.key) {
83
- setInputValue(selectedOption.label || '');
84
- }
85
- }, [selectedOption]);
61
+ setInputValue(dropdownInputText || '');
62
+ }, [dropdownInputText]);
63
+
64
+ const onMenuToggle = (isOpen: boolean) => {
65
+ isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
66
+ };
86
67
 
87
68
  return (
88
- <ClickAway>
69
+ <ClickAway onChange={onMenuToggle}>
89
70
  {({isOpen, onOpen, cancelNext, clickAway}) => (
90
71
  <div
91
72
  data-testid="Dropdown"
@@ -107,7 +88,7 @@ export const Dropdown = ({
107
88
  }}
108
89
  />
109
90
 
110
- {isOpen && (options || composeOptions || groupTitleOptions) && (
91
+ {isOpen && menu && (
111
92
  <div
112
93
  onClickCapture={cancelNext}
113
94
  ref={floating}
@@ -120,15 +101,17 @@ export const Dropdown = ({
120
101
  }}
121
102
  >
122
103
  <Menu
123
- isFluid
124
- options={options}
125
- composeOptions={composeOptions}
126
- groupTitleOptions={groupTitleOptions}
104
+ {...menu}
127
105
  onSelect={(option) => {
128
- handleSelect(option);
129
- clickAway();
106
+ onChange && onChange(option);
107
+ if (
108
+ !menu.optionsVariant ||
109
+ menu.optionsVariant === 'normal'
110
+ ) {
111
+ clickAway();
112
+ }
130
113
  }}
131
- size={menuSize || size}
114
+ size={menu.size || size}
132
115
  />
133
116
  </div>
134
117
  )}
@@ -89,8 +89,11 @@ const InlineDropdown = _ref => {
89
89
  }, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
90
90
  onSelect: option => {
91
91
  onOptionSelect && onOptionSelect(option);
92
- clickAway();
93
- }
92
+ if (!menu.optionsVariant || menu.optionsVariant === 'normal') {
93
+ clickAway();
94
+ }
95
+ },
96
+ size: menu.size || 'medium'
94
97
  }))));
95
98
  });
96
99
  };
@@ -36,7 +36,7 @@ type ClassNames = $ReadOnly<{
36
36
  export type InlineDropdownProps = {
37
37
  ...UnstyledButtonProps,
38
38
  classNames?: ClassNames,
39
- menu: MenuProps,
39
+ menu?: MenuProps,
40
40
  anchorPosition?: AnchorType,
41
41
  onOptionSelect?: (option: MenuOption) => mixed,
42
42
  onMenuOpen?: () => mixed,
@@ -122,8 +122,14 @@ export const InlineDropdown = ({
122
122
  {...menu}
123
123
  onSelect={(option) => {
124
124
  onOptionSelect && onOptionSelect(option);
125
- clickAway();
125
+ if (
126
+ !menu.optionsVariant ||
127
+ menu.optionsVariant === 'normal'
128
+ ) {
129
+ clickAway();
130
+ }
126
131
  }}
132
+ size={menu.size || 'medium'}
127
133
  />
128
134
  </div>
129
135
  )}
@@ -86,7 +86,8 @@ const Input_ = (props, ref) => {
86
86
  [_InputModule.default.inputDisabled]: disabled ?? false,
87
87
  [_InputModule.default.medium]: size === 'medium',
88
88
  [_InputModule.default.small]: size === 'small',
89
- [_InputModule.default.locked]: locked
89
+ [_InputModule.default.locked]: locked,
90
+ [_InputModule.default.color]: type === 'color'
90
91
  }),
91
92
  onClick: !(disabled || locked) ? onContainerClick : null,
92
93
  ref: boxRef
@@ -141,6 +141,7 @@ const Input_ = (props: InputProps, ref): React.Node => {
141
141
  [css.medium]: size === 'medium',
142
142
  [css.small]: size === 'small',
143
143
  [css.locked]: locked,
144
+ [css.color]: type === 'color',
144
145
  })}
145
146
  onClick={!(disabled || locked) ? onContainerClick : null}
146
147
  ref={boxRef}
@@ -1,4 +1,5 @@
1
1
  @value (
2
+ size18,
2
3
  size42,
3
4
  size30,
4
5
  size34,
@@ -9,6 +10,7 @@
9
10
  spaceNone,
10
11
  spaceXSmall,
11
12
  spaceSmall,
13
+ spaceMedium,
12
14
  spaceXXSmall
13
15
  ) from '../../styles/variables/_space.css';
14
16
 
@@ -134,17 +136,28 @@ input::placeholder {
134
136
  pointer-events: none;
135
137
  }
136
138
 
139
+ .box.color {
140
+ padding-right: spaceMedium;
141
+ }
142
+
137
143
  .box > input[type='color'] {
138
144
  display: flex;
139
145
  cursor: pointer;
140
146
  align-items: center;
141
147
  width: fit-content;
142
148
  gap: spaceXSmall;
149
+ padding: spaceNone;
150
+ width: size18;
151
+ height: size18;
152
+ margin: spaceNone;
143
153
  }
144
154
 
145
155
  .box > input[type='color']::-webkit-color-swatch {
156
+ display: flex;
157
+ padding: spaceNone;
158
+ align-self: center;
146
159
  border: none;
147
- min-width: size30;
148
- max-width: size30;
160
+ min-width: size18;
161
+ min-height: size18;
149
162
  border-radius: borderRadiusXSmall;
150
163
  }
@@ -17,13 +17,15 @@ const RenderOption = _ref => {
17
17
  options,
18
18
  composeOptions,
19
19
  groupTitleOptions,
20
+ classNames,
20
21
  ...restProps
21
22
  } = _ref;
22
23
  if (options && Array.isArray(options) && options.length) {
23
24
  return /*#__PURE__*/React.createElement(React.Fragment, null, options.map(option => /*#__PURE__*/React.createElement(React.Fragment, {
24
25
  key: option.key
25
26
  }, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
26
- option: option
27
+ option: option,
28
+ classNames: classNames
27
29
  }, restProps)))));
28
30
  }
29
31
  if (composeOptions && Array.isArray(composeOptions) && composeOptions.length) {
@@ -36,7 +38,8 @@ const RenderOption = _ref => {
36
38
  }, composeMenuOptions.map(option => /*#__PURE__*/React.createElement(React.Fragment, {
37
39
  key: option.key
38
40
  }, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
39
- option: option
41
+ option: option,
42
+ classNames: classNames
40
43
  }, restProps)))))));
41
44
  }
42
45
  if (groupTitleOptions && Array.isArray(groupTitleOptions) && groupTitleOptions.length) {
@@ -46,11 +49,12 @@ const RenderOption = _ref => {
46
49
  React.createElement(React.Fragment, {
47
50
  key: index
48
51
  }, !!optionsGroup.groupTitle && /*#__PURE__*/React.createElement("div", {
49
- className: _MenuModule.default.groupTitleWrapper
52
+ className: (0, _classify.classify)(_MenuModule.default.groupTitleWrapper, classNames?.groupTitle)
50
53
  }, optionsGroup.groupTitle), optionsGroup.options?.map(option => /*#__PURE__*/React.createElement(React.Fragment, {
51
54
  key: option.key
52
55
  }, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
53
- option: option
56
+ option: option,
57
+ classNames: classNames
54
58
  }, restProps)))))));
55
59
  }
56
60
  return /*#__PURE__*/React.createElement(React.Fragment, null);
@@ -9,10 +9,14 @@ import {MenuOptionButton} from './MenuOptionButton';
9
9
  import css from './Menu.module.css';
10
10
 
11
11
 
12
- type ClassNames = $ReadOnly<{wrapper?: string, option?: string}>;
12
+ type ClassNames = $ReadOnly<{
13
+ wrapper?: string,
14
+ option?: string,
15
+ groupTitle?: string,
16
+ }>;
13
17
 
14
18
  export type MenuOption = {
15
- key?: string,
19
+ key: string,
16
20
  label?: string,
17
21
  secondaryLabel?: string,
18
22
  customComponent?: React.Node,
@@ -26,34 +30,43 @@ export type MenuOption = {
26
30
 
27
31
  // Render first available option set
28
32
 
29
- export type MenuProps = {
33
+ export type BaseMenuProps = {
30
34
  onSelect?: (option: MenuOption) => mixed,
31
- selectedOption?: MenuOption,
35
+ selectedOption?: ?MenuOption,
36
+ optionsVariant?: MenuOptionsVariant,
37
+ selectedKeys?: Array<string>,
32
38
  classNames?: ClassNames,
33
39
  size?: MenuSizeTypes,
34
40
  width?: string,
35
41
  menuDisabled?: boolean,
36
42
  isFluid?: boolean,
37
- ...MenuOptionTypes,
43
+ };
44
+
45
+ export type MenuOptionTypes = {
46
+ options?: Array<MenuOption>,
47
+ composeOptions?: Array<Array<MenuOption>>,
48
+ groupTitleOptions?: Array<MenuGroupTitleOption>,
38
49
  };
39
50
 
40
51
  export type MenuSizeTypes = 'medium' | 'small';
52
+ export type MenuOptionsVariant = 'checkbox' | 'radio' | 'normal';
41
53
 
42
54
  export type MenuGroupTitleOption = {
43
55
  groupTitle?: React.Node,
44
56
  options?: Array<MenuOption>,
57
+ showLineDivider?: boolean,
45
58
  };
46
59
 
47
- export type MenuOptionTypes = {
48
- options?: Array<MenuOption>,
49
- composeOptions?: Array<Array<MenuOption>>,
50
- groupTitleOptions?: Array<MenuGroupTitleOption>,
60
+ export type MenuProps = {
61
+ ...BaseMenuProps,
62
+ ...MenuOptionTypes,
51
63
  };
52
64
 
53
65
  const RenderOption = ({
54
66
  options,
55
67
  composeOptions,
56
68
  groupTitleOptions,
69
+ classNames,
57
70
  ...restProps
58
71
  }: MenuProps): React.Node => {
59
72
  if (options && Array.isArray(options) && options.length) {
@@ -61,7 +74,11 @@ const RenderOption = ({
61
74
  <>
62
75
  {options.map((option) => (
63
76
  <React.Fragment key={option.key}>
64
- <MenuOptionButton option={option} {...restProps} />
77
+ <MenuOptionButton
78
+ option={option}
79
+ classNames={classNames}
80
+ {...restProps}
81
+ />
65
82
  </React.Fragment>
66
83
  ))}
67
84
  </>
@@ -79,7 +96,11 @@ const RenderOption = ({
79
96
  <span className={css.menuDivider} key={index}>
80
97
  {composeMenuOptions.map((option) => (
81
98
  <React.Fragment key={option.key}>
82
- <MenuOptionButton option={option} {...restProps} />
99
+ <MenuOptionButton
100
+ option={option}
101
+ classNames={classNames}
102
+ {...restProps}
103
+ />
83
104
  </React.Fragment>
84
105
  ))}
85
106
  </span>
@@ -98,14 +119,23 @@ const RenderOption = ({
98
119
  // eslint-disable-next-line react/no-array-index-key
99
120
  <React.Fragment key={index}>
100
121
  {!!optionsGroup.groupTitle && (
101
- <div className={css.groupTitleWrapper}>
122
+ <div
123
+ className={classify(
124
+ css.groupTitleWrapper,
125
+ classNames?.groupTitle,
126
+ )}
127
+ >
102
128
  {optionsGroup.groupTitle}
103
129
  </div>
104
130
  )}
105
131
 
106
132
  {optionsGroup.options?.map((option) => (
107
133
  <React.Fragment key={option.key}>
108
- <MenuOptionButton option={option} {...restProps} />
134
+ <MenuOptionButton
135
+ option={option}
136
+ classNames={classNames}
137
+ {...restProps}
138
+ />
109
139
  </React.Fragment>
110
140
  ))}
111
141
  </React.Fragment>
@@ -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
- margin-bottom: spaceXSmall;
210
+ padding-bottom: spaceXSmall;
194
211
  padding-left: spaceSmall;
195
212
  padding-right: calc(spaceXSmall / 2);
196
213
  color: colorTextTertiary;
197
- margin-top: spaceSmall;
214
+ padding-top: spaceSmall;
198
215
  }