@spaced-out/ui-design-system 0.3.46 → 0.3.47-beta.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 (48) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/lib/components/AvatarGroup/AvatarGroup.js.flow +2 -2
  3. package/lib/components/ButtonDropdown/ButtonDropdown.js +22 -10
  4. package/lib/components/ButtonDropdown/ButtonDropdown.js.flow +58 -33
  5. package/lib/components/ButtonDropdown/ButtonDropdown.module.css +8 -1
  6. package/lib/components/ButtonDropdown/SimpleButtonDropdown.js +3 -0
  7. package/lib/components/ButtonDropdown/SimpleButtonDropdown.js.flow +6 -1
  8. package/lib/components/ButtonTabs/ButtonTabDropdown.js +13 -6
  9. package/lib/components/ButtonTabs/ButtonTabDropdown.js.flow +40 -24
  10. package/lib/components/ButtonTabs/ButtonTabDropdown.module.css +4 -0
  11. package/lib/components/ButtonTabs/ButtonTabs.js +2 -0
  12. package/lib/components/ButtonTabs/ButtonTabs.js.flow +4 -0
  13. package/lib/components/Dropdown/Dropdown.js +23 -8
  14. package/lib/components/Dropdown/Dropdown.js.flow +57 -32
  15. package/lib/components/Dropdown/Dropdown.module.css +5 -0
  16. package/lib/components/Dropdown/SimpleDropdown.js +2 -0
  17. package/lib/components/Dropdown/SimpleDropdown.js.flow +4 -0
  18. package/lib/components/InlineDropdown/InlineDropdown.js +25 -8
  19. package/lib/components/InlineDropdown/InlineDropdown.js.flow +57 -30
  20. package/lib/components/InlineDropdown/InlineDropdown.module.css +5 -0
  21. package/lib/components/InlineDropdown/SimpleInlineDropdown.js +2 -0
  22. package/lib/components/InlineDropdown/SimpleInlineDropdown.js.flow +4 -0
  23. package/lib/components/Table/StaticTable.js +1 -1
  24. package/lib/components/Table/StaticTable.js.flow +1 -1
  25. package/lib/components/Table/Table.docs.js +1 -1
  26. package/lib/components/Table/Table.docs.js.flow +1 -1
  27. package/lib/components/Tabs/TabList/TabDropdown.js +14 -7
  28. package/lib/components/Tabs/TabList/TabDropdown.js.flow +38 -22
  29. package/lib/components/Tabs/TabList/TabDropdown.module.css +4 -0
  30. package/lib/components/Tabs/TabList/TabList.js +4 -2
  31. package/lib/components/Tabs/TabList/TabList.js.flow +4 -0
  32. package/lib/components/TokenListInput/TokenListInput.js +26 -7
  33. package/lib/components/TokenListInput/TokenListInput.js.flow +58 -32
  34. package/lib/components/TokenListInput/TokenListInput.module.css +5 -0
  35. package/lib/components/Tooltip/Tooltip.js +2 -1
  36. package/lib/components/Tooltip/Tooltip.js.flow +2 -2
  37. package/lib/components/Typeahead/SimpleTypeahead.js +3 -1
  38. package/lib/components/Typeahead/SimpleTypeahead.js.flow +4 -0
  39. package/lib/components/Typeahead/Typeahead.js +25 -8
  40. package/lib/components/Typeahead/Typeahead.js.flow +58 -30
  41. package/lib/components/Typeahead/Typeahead.module.css +5 -0
  42. package/lib/hooks/index.js +11 -0
  43. package/lib/hooks/index.js.flow +1 -0
  44. package/lib/hooks/useReferenceElementWidth/index.js +16 -0
  45. package/lib/hooks/useReferenceElementWidth/index.js.flow +3 -0
  46. package/lib/hooks/useReferenceElementWidth/useReferenceElementWidth.js +21 -0
  47. package/lib/hooks/useReferenceElementWidth/useReferenceElementWidth.js.flow +23 -0
  48. package/package.json +1 -1
@@ -6,13 +6,14 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.Dropdown = void 0;
7
7
  var React = _interopRequireWildcard(require("react"));
8
8
  var _react2 = require("@floating-ui/react");
9
- var _size = require("../../styles/variables/_size");
9
+ var _hooks = require("../../hooks");
10
10
  var _space = require("../../styles/variables/_space");
11
11
  var _classify = require("../../utils/classify");
12
12
  var _clickAway = require("../../utils/click-away");
13
13
  var _mergeRefs = require("../../utils/merge-refs");
14
14
  var _Input = require("../Input");
15
15
  var _Menu = require("../Menu");
16
+ var _Tooltip = require("../Tooltip");
16
17
  var _DropdownModule = _interopRequireDefault(require("./Dropdown.module.css"));
17
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
19
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -29,15 +30,16 @@ const Dropdown = exports.Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) =>
29
30
  scrollMenuToBottom = false,
30
31
  dropdownInputText = '',
31
32
  clickAwayRef,
33
+ elevation = 'modal',
32
34
  ...inputProps
33
35
  } = _ref;
34
- const dropdownRef = React.useRef();
35
36
  const menuRef = React.useRef();
36
37
  const {
37
38
  x,
38
39
  y,
39
40
  refs,
40
- strategy
41
+ strategy,
42
+ context
41
43
  } = (0, _react2.useFloating)({
42
44
  open: true,
43
45
  strategy: 'absolute',
@@ -45,6 +47,7 @@ const Dropdown = exports.Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) =>
45
47
  whileElementsMounted: _react2.autoUpdate,
46
48
  middleware: [(0, _react2.flip)(), (0, _react2.offset)(parseInt(_space.spaceXXSmall))]
47
49
  });
50
+ const dropdownWidth = (0, _hooks.useReferenceElementWidth)(refs.reference?.current);
48
51
  const onMenuToggle = isOpen => {
49
52
  isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
50
53
  if (scrollMenuToBottom && menuRef.current && isOpen) {
@@ -63,9 +66,8 @@ const Dropdown = exports.Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) =>
63
66
  triggerRef
64
67
  } = _ref2;
65
68
  return /*#__PURE__*/React.createElement("div", {
66
- "data-testid": "Dropdown",
67
69
  className: (0, _classify.classify)(_DropdownModule.default.dropdownContainer, classNames?.wrapper),
68
- ref: (0, _mergeRefs.mergeRefs)([dropdownRef, boundaryRef])
70
+ "data-testid": "Dropdown"
69
71
  }, /*#__PURE__*/React.createElement(_Input.Input, _extends({}, inputProps, {
70
72
  onKeyDown: e => {
71
73
  if (e.keyCode === 32) {
@@ -88,13 +90,26 @@ const Dropdown = exports.Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) =>
88
90
  onOpen();
89
91
  },
90
92
  ref: ref
91
- })), isOpen && menu && /*#__PURE__*/React.createElement("div", {
93
+ })), isOpen && menu && /*#__PURE__*/React.createElement(_react2.FloatingPortal, null, /*#__PURE__*/React.createElement(_react2.FloatingFocusManager, {
94
+ modal: false,
95
+ context: context,
96
+ initialFocus: refs.reference
97
+ }, /*#__PURE__*/React.createElement("div", {
92
98
  ref: (0, _mergeRefs.mergeRefs)([refs.setFloating, boundaryRef]),
99
+ className: _DropdownModule.default.menuWrapper,
93
100
  style: {
94
101
  position: strategy,
95
102
  top: y ?? _space.spaceNone,
96
103
  left: x ?? _space.spaceNone,
97
- width: _size.sizeFluid
104
+ /* NOTE(Sharad): The FloatingPortal renders the menu outside the normal DOM structure,
105
+ so its parent is effectively the <body> element. This means the menu
106
+ would otherwise default to the body's width. To support fluid width,
107
+ we must manually set the dropdown width here; otherwise, it uses a fixed width.
108
+ Also, Only treat menu as non-fluid if isFluid is strictly false, since default is true in menu and undefined means fluid. */
109
+ ...(menu.isFluid !== false && {
110
+ '--dropdown-width': dropdownWidth
111
+ }),
112
+ '--menu-elevation': (0, _Tooltip.getElevationValue)(elevation)
98
113
  }
99
114
  }, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
100
115
  onSelect: (option, e) => {
@@ -109,6 +124,6 @@ const Dropdown = exports.Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) =>
109
124
  size: menu.size || size,
110
125
  onTabOut: clickAway,
111
126
  ref: menuRef
112
- }))));
127
+ }))))));
113
128
  });
114
129
  });
@@ -7,12 +7,16 @@ import {
7
7
  // $FlowFixMe[untyped-import]
8
8
  flip,
9
9
  // $FlowFixMe[untyped-import]
10
+ FloatingFocusManager,
11
+ // $FlowFixMe[untyped-import]
12
+ FloatingPortal,
13
+ // $FlowFixMe[untyped-import]
10
14
  offset,
11
15
  // $FlowFixMe[untyped-import]
12
16
  useFloating,
13
17
  } from '@floating-ui/react';
14
18
 
15
- import {sizeFluid} from '../../styles/variables/_size';
19
+ import {useReferenceElementWidth} from '../../hooks';
16
20
  import {spaceNone, spaceXXSmall} from '../../styles/variables/_space';
17
21
  import {classify} from '../../utils/classify';
18
22
  import {type ClickAwayRefType, ClickAway} from '../../utils/click-away';
@@ -21,6 +25,7 @@ import type {InputProps} from '../Input';
21
25
  import {Input} from '../Input';
22
26
  import type {MenuOption, MenuProps} from '../Menu';
23
27
  import {Menu} from '../Menu';
28
+ import {type ElevationType, getElevationValue} from '../Tooltip';
24
29
 
25
30
  import css from './Dropdown.module.css';
26
31
 
@@ -40,6 +45,7 @@ export type DropdownProps = {
40
45
  scrollMenuToBottom?: boolean,
41
46
  dropdownInputText?: string,
42
47
  menu?: MenuProps,
48
+ elevation?: ElevationType,
43
49
  clickAwayRef?: ClickAwayRefType,
44
50
  ...
45
51
  };
@@ -60,19 +66,21 @@ export const Dropdown: React$AbstractComponent<
60
66
  scrollMenuToBottom = false,
61
67
  dropdownInputText = '',
62
68
  clickAwayRef,
69
+ elevation = 'modal',
63
70
  ...inputProps
64
71
  }: DropdownProps,
65
72
  ref,
66
73
  ): React.Node => {
67
- const dropdownRef = React.useRef();
68
74
  const menuRef = React.useRef();
69
- const {x, y, refs, strategy} = useFloating({
75
+
76
+ const {x, y, refs, strategy, context} = useFloating({
70
77
  open: true,
71
78
  strategy: 'absolute',
72
79
  placement: 'bottom-start',
73
80
  whileElementsMounted: autoUpdate,
74
81
  middleware: [flip(), offset(parseInt(spaceXXSmall))],
75
82
  });
83
+ const dropdownWidth = useReferenceElementWidth(refs.reference?.current);
76
84
 
77
85
  const onMenuToggle = (isOpen: boolean) => {
78
86
  isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
@@ -85,9 +93,8 @@ export const Dropdown: React$AbstractComponent<
85
93
  <ClickAway onChange={onMenuToggle} clickAwayRef={clickAwayRef}>
86
94
  {({isOpen, onOpen, clickAway, boundaryRef, triggerRef}) => (
87
95
  <div
88
- data-testid="Dropdown"
89
96
  className={classify(css.dropdownContainer, classNames?.wrapper)}
90
- ref={mergeRefs([dropdownRef, boundaryRef])}
97
+ data-testid="Dropdown"
91
98
  >
92
99
  <Input
93
100
  {...inputProps}
@@ -115,33 +122,51 @@ export const Dropdown: React$AbstractComponent<
115
122
  />
116
123
 
117
124
  {isOpen && menu && (
118
- <div
119
- ref={mergeRefs([refs.setFloating, boundaryRef])}
120
- style={{
121
- position: strategy,
122
- top: y ?? spaceNone,
123
- left: x ?? spaceNone,
124
- width: sizeFluid,
125
- }}
126
- >
127
- <Menu
128
- {...menu}
129
- onSelect={(option, e) => {
130
- onChange && onChange(option, e);
131
- if (
132
- // option.keepMenuOpenOnOptionSelect - to allow the menu persist its open stat upon option selection in normal variant
133
- !option.keepMenuOpenOnOptionSelect &&
134
- (!menu.optionsVariant || menu.optionsVariant === 'normal')
135
- ) {
136
- clickAway();
137
- refs.reference.current.querySelector('input').focus();
138
- }
139
- }}
140
- size={menu.size || size}
141
- onTabOut={clickAway}
142
- ref={menuRef}
143
- />
144
- </div>
125
+ <FloatingPortal>
126
+ <FloatingFocusManager
127
+ modal={false}
128
+ context={context}
129
+ initialFocus={refs.reference}
130
+ >
131
+ <div
132
+ ref={mergeRefs([refs.setFloating, boundaryRef])}
133
+ className={css.menuWrapper}
134
+ style={{
135
+ position: strategy,
136
+ top: y ?? spaceNone,
137
+ left: x ?? spaceNone,
138
+ /* NOTE(Sharad): The FloatingPortal renders the menu outside the normal DOM structure,
139
+ so its parent is effectively the <body> element. This means the menu
140
+ would otherwise default to the body's width. To support fluid width,
141
+ we must manually set the dropdown width here; otherwise, it uses a fixed width.
142
+ Also, Only treat menu as non-fluid if isFluid is strictly false, since default is true in menu and undefined means fluid. */
143
+ ...(menu.isFluid !== false && {
144
+ '--dropdown-width': dropdownWidth,
145
+ }),
146
+ '--menu-elevation': getElevationValue(elevation),
147
+ }}
148
+ >
149
+ <Menu
150
+ {...menu}
151
+ onSelect={(option, e) => {
152
+ onChange && onChange(option, e);
153
+ if (
154
+ // option.keepMenuOpenOnOptionSelect - to allow the menu persist its open stat upon option selection in normal variant
155
+ !option.keepMenuOpenOnOptionSelect &&
156
+ (!menu.optionsVariant ||
157
+ menu.optionsVariant === 'normal')
158
+ ) {
159
+ clickAway();
160
+ refs.reference.current.querySelector('input').focus();
161
+ }
162
+ }}
163
+ size={menu.size || size}
164
+ onTabOut={clickAway}
165
+ ref={menuRef}
166
+ />
167
+ </div>
168
+ </FloatingFocusManager>
169
+ </FloatingPortal>
145
170
  )}
146
171
  </div>
147
172
  )}
@@ -12,3 +12,8 @@
12
12
  .inputBox {
13
13
  cursor: pointer;
14
14
  }
15
+
16
+ .menuWrapper {
17
+ width: var(--dropdown-width);
18
+ z-index: var(--menu-elevation);
19
+ }
@@ -22,6 +22,7 @@ const SimpleDropdownBase = (props, ref) => {
22
22
  onMenuOpen,
23
23
  onMenuClose,
24
24
  resolveLabel,
25
+ elevation = 'modal',
25
26
  menuVirtualization,
26
27
  resolveSecondaryLabel,
27
28
  isMenuFluid = true,
@@ -61,6 +62,7 @@ const SimpleDropdownBase = (props, ref) => {
61
62
  return /*#__PURE__*/React.createElement(_Dropdown.Dropdown, _extends({}, inputProps, {
62
63
  classNames: classNames,
63
64
  size: size,
65
+ elevation: elevation,
64
66
  placeholder: placeholder,
65
67
  onChange: handleOptionChange,
66
68
  onMenuOpen: onMenuOpen,
@@ -10,6 +10,7 @@ import {
10
10
  } from '../../utils/menu';
11
11
  import type {InputProps} from '../Input';
12
12
  import type {MenuOption, MenuOptionsVariant, Virtualization} from '../Menu';
13
+ import type {ElevationType} from '../Tooltip';
13
14
 
14
15
  import {Dropdown} from './Dropdown';
15
16
 
@@ -27,6 +28,7 @@ export type SimpleDropdownProps = {
27
28
  // Input props
28
29
  ...InputProps,
29
30
 
31
+ elevation?: ElevationType,
30
32
  classNames?: ClassNames,
31
33
  clickAwayRef?: ClickAwayRefType,
32
34
 
@@ -67,6 +69,7 @@ const SimpleDropdownBase = (props: SimpleDropdownProps, ref) => {
67
69
  onMenuOpen,
68
70
  onMenuClose,
69
71
  resolveLabel,
72
+ elevation = 'modal',
70
73
  menuVirtualization,
71
74
  resolveSecondaryLabel,
72
75
  isMenuFluid = true,
@@ -125,6 +128,7 @@ const SimpleDropdownBase = (props: SimpleDropdownProps, ref) => {
125
128
  {...inputProps}
126
129
  classNames={classNames}
127
130
  size={size}
131
+ elevation={elevation}
128
132
  placeholder={placeholder}
129
133
  onChange={handleOptionChange}
130
134
  onMenuOpen={onMenuOpen}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.InlineDropdown = void 0;
7
7
  var React = _interopRequireWildcard(require("react"));
8
8
  var _react2 = require("@floating-ui/react");
9
+ var _hooks = require("../../hooks");
9
10
  var _space = require("../../styles/variables/_space");
10
11
  var _classify = require("../../utils/classify");
11
12
  var _clickAway = require("../../utils/click-away");
@@ -13,6 +14,7 @@ var _mergeRefs = require("../../utils/merge-refs");
13
14
  var _Button = require("../Button");
14
15
  var _Icon = require("../Icon");
15
16
  var _Menu = require("../Menu");
17
+ var _Tooltip = require("../Tooltip");
16
18
  var _Truncate = require("../Truncate");
17
19
  var _InlineDropdownModule = _interopRequireDefault(require("./InlineDropdown.module.css"));
18
20
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -30,15 +32,15 @@ const InlineDropdown = exports.InlineDropdown = /*#__PURE__*/React.forwardRef((_
30
32
  onMenuClose,
31
33
  children,
32
34
  clickAwayRef,
35
+ elevation = 'modal',
33
36
  ...restButtonProps
34
37
  } = _ref;
35
- const menuBtnRef = React.useRef(null);
36
- React.useImperativeHandle(ref, () => menuBtnRef.current);
37
38
  const {
38
39
  x,
39
40
  y,
40
41
  refs,
41
- strategy
42
+ strategy,
43
+ context
42
44
  } = (0, _react2.useFloating)({
43
45
  open: true,
44
46
  strategy: 'absolute',
@@ -46,8 +48,9 @@ const InlineDropdown = exports.InlineDropdown = /*#__PURE__*/React.forwardRef((_
46
48
  whileElementsMounted: _react2.autoUpdate,
47
49
  middleware: [(0, _react2.shift)(), (0, _react2.flip)(), (0, _react2.offset)(parseInt(_space.spaceXXSmall))]
48
50
  });
51
+ const dropdownWidth = (0, _hooks.useReferenceElementWidth)(refs.reference?.current);
49
52
  const onMenuToggle = isOpen => {
50
- isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
53
+ isOpen ? onMenuOpen?.() : onMenuClose?.();
51
54
  };
52
55
  return /*#__PURE__*/React.createElement(_clickAway.ClickAway, {
53
56
  onChange: onMenuToggle,
@@ -63,7 +66,7 @@ const InlineDropdown = exports.InlineDropdown = /*#__PURE__*/React.forwardRef((_
63
66
  return /*#__PURE__*/React.createElement("div", {
64
67
  "data-testid": "InlineDropdown",
65
68
  className: (0, _classify.classify)(_InlineDropdownModule.default.inlineDropdownContainer, classNames?.dropdownContainer),
66
- ref: menuBtnRef
69
+ ref: ref
67
70
  }, /*#__PURE__*/React.createElement(_Button.UnstyledButton, _extends({}, restButtonProps, {
68
71
  disabled: disabled,
69
72
  ref: (0, _mergeRefs.mergeRefs)([refs.setReference, triggerRef]),
@@ -81,13 +84,27 @@ const InlineDropdown = exports.InlineDropdown = /*#__PURE__*/React.forwardRef((_
81
84
  className: (0, _classify.classify)({
82
85
  [_InlineDropdownModule.default.disabled]: disabled
83
86
  })
84
- })), isOpen && menu && /*#__PURE__*/React.createElement("div", {
87
+ })), isOpen && menu && /*#__PURE__*/React.createElement(_react2.FloatingPortal, null, /*#__PURE__*/React.createElement(_react2.FloatingFocusManager, {
88
+ modal: false,
89
+ context: context,
90
+ initialFocus: triggerRef
91
+ }, /*#__PURE__*/React.createElement("div", {
92
+ className: _InlineDropdownModule.default.menuWrapper,
85
93
  ref: (0, _mergeRefs.mergeRefs)([refs.setFloating, boundaryRef]),
86
94
  style: {
87
95
  display: 'flex',
88
96
  position: strategy,
89
97
  top: y ?? _space.spaceNone,
90
- left: x ?? _space.spaceNone
98
+ left: x ?? _space.spaceNone,
99
+ /* NOTE(Sharad): The FloatingPortal renders the menu outside the normal DOM structure,
100
+ so its parent is effectively the <body> element. This means the menu
101
+ would otherwise default to the body's width. To support fluid width,
102
+ we must manually set the dropdown width here; otherwise, it uses a fixed width.
103
+ Also, Only treat menu as non-fluid if isFluid is strictly false, since default is true in menu and undefined means fluid. */
104
+ ...(menu.isFluid !== false && {
105
+ '--dropdown-width': dropdownWidth
106
+ }),
107
+ '--menu-elevation': (0, _Tooltip.getElevationValue)(elevation)
91
108
  }
92
109
  }, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
93
110
  onSelect: (option, e) => {
@@ -100,6 +117,6 @@ const InlineDropdown = exports.InlineDropdown = /*#__PURE__*/React.forwardRef((_
100
117
  },
101
118
  size: menu.size || 'medium',
102
119
  onTabOut: clickAway
103
- }))));
120
+ }))))));
104
121
  });
105
122
  });
@@ -7,6 +7,10 @@ import {
7
7
  // $FlowFixMe[untyped-import]
8
8
  flip,
9
9
  // $FlowFixMe[untyped-import]
10
+ FloatingFocusManager,
11
+ // $FlowFixMe[untyped-import]
12
+ FloatingPortal,
13
+ // $FlowFixMe[untyped-import]
10
14
  offset,
11
15
  // $FlowFixMe[untyped-import]
12
16
  shift,
@@ -14,6 +18,7 @@ import {
14
18
  useFloating,
15
19
  } from '@floating-ui/react';
16
20
 
21
+ import {useReferenceElementWidth} from '../../hooks';
17
22
  import {spaceNone, spaceXXSmall} from '../../styles/variables/_space';
18
23
  import {classify} from '../../utils/classify';
19
24
  import {type ClickAwayRefType, ClickAway} from '../../utils/click-away';
@@ -24,6 +29,7 @@ import type {AnchorType} from '../ButtonDropdown';
24
29
  import {Icon} from '../Icon';
25
30
  import type {MenuOption, MenuProps} from '../Menu';
26
31
  import {Menu} from '../Menu';
32
+ import {type ElevationType, getElevationValue} from '../Tooltip';
27
33
  import {Truncate} from '../Truncate';
28
34
 
29
35
  import css from './InlineDropdown.module.css';
@@ -43,6 +49,7 @@ export type InlineDropdownProps = {
43
49
  onMenuOpen?: () => mixed,
44
50
  onMenuClose?: () => mixed,
45
51
  size?: 'medium' | 'small' | 'extraSmall',
52
+ elevation?: ElevationType,
46
53
  clickAwayRef?: ClickAwayRefType,
47
54
  ...
48
55
  };
@@ -63,13 +70,12 @@ export const InlineDropdown: React$AbstractComponent<
63
70
  onMenuClose,
64
71
  children,
65
72
  clickAwayRef,
73
+ elevation = 'modal',
66
74
  ...restButtonProps
67
75
  }: InlineDropdownProps,
68
76
  ref,
69
77
  ): React.Node => {
70
- const menuBtnRef = React.useRef(null);
71
- React.useImperativeHandle(ref, () => menuBtnRef.current);
72
- const {x, y, refs, strategy} = useFloating({
78
+ const {x, y, refs, strategy, context} = useFloating({
73
79
  open: true,
74
80
  strategy: 'absolute',
75
81
  placement: anchorPosition,
@@ -77,8 +83,10 @@ export const InlineDropdown: React$AbstractComponent<
77
83
  middleware: [shift(), flip(), offset(parseInt(spaceXXSmall))],
78
84
  });
79
85
 
86
+ const dropdownWidth = useReferenceElementWidth(refs.reference?.current);
87
+
80
88
  const onMenuToggle = (isOpen: boolean) => {
81
- isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
89
+ isOpen ? onMenuOpen?.() : onMenuClose?.();
82
90
  };
83
91
 
84
92
  return (
@@ -90,7 +98,7 @@ export const InlineDropdown: React$AbstractComponent<
90
98
  css.inlineDropdownContainer,
91
99
  classNames?.dropdownContainer,
92
100
  )}
93
- ref={menuBtnRef}
101
+ ref={ref}
94
102
  >
95
103
  <UnstyledButton
96
104
  {...restButtonProps}
@@ -120,31 +128,50 @@ export const InlineDropdown: React$AbstractComponent<
120
128
  />
121
129
  </UnstyledButton>
122
130
  {isOpen && menu && (
123
- <div
124
- ref={mergeRefs([refs.setFloating, boundaryRef])}
125
- style={{
126
- display: 'flex',
127
- position: strategy,
128
- top: y ?? spaceNone,
129
- left: x ?? spaceNone,
130
- }}
131
- >
132
- <Menu
133
- {...menu}
134
- onSelect={(option, e) => {
135
- onOptionSelect && onOptionSelect(option, e);
136
- if (
137
- // option.keepMenuOpenOnOptionSelect - to allow the menu persist its open stat upon option selection in normal variant
138
- !option.keepMenuOpenOnOptionSelect &&
139
- (!menu.optionsVariant || menu.optionsVariant === 'normal')
140
- ) {
141
- clickAway();
142
- }
143
- }}
144
- size={menu.size || 'medium'}
145
- onTabOut={clickAway}
146
- />
147
- </div>
131
+ <FloatingPortal>
132
+ <FloatingFocusManager
133
+ modal={false}
134
+ context={context}
135
+ initialFocus={triggerRef}
136
+ >
137
+ <div
138
+ className={css.menuWrapper}
139
+ ref={mergeRefs([refs.setFloating, boundaryRef])}
140
+ style={{
141
+ display: 'flex',
142
+ position: strategy,
143
+ top: y ?? spaceNone,
144
+ left: x ?? spaceNone,
145
+ /* NOTE(Sharad): The FloatingPortal renders the menu outside the normal DOM structure,
146
+ so its parent is effectively the <body> element. This means the menu
147
+ would otherwise default to the body's width. To support fluid width,
148
+ we must manually set the dropdown width here; otherwise, it uses a fixed width.
149
+ Also, Only treat menu as non-fluid if isFluid is strictly false, since default is true in menu and undefined means fluid. */ ...(menu.isFluid !==
150
+ false && {
151
+ '--dropdown-width': dropdownWidth,
152
+ }),
153
+ '--menu-elevation': getElevationValue(elevation),
154
+ }}
155
+ >
156
+ <Menu
157
+ {...menu}
158
+ onSelect={(option, e) => {
159
+ onOptionSelect && onOptionSelect(option, e);
160
+ if (
161
+ // option.keepMenuOpenOnOptionSelect - to allow the menu persist its open stat upon option selection in normal variant
162
+ !option.keepMenuOpenOnOptionSelect &&
163
+ (!menu.optionsVariant ||
164
+ menu.optionsVariant === 'normal')
165
+ ) {
166
+ clickAway();
167
+ }
168
+ }}
169
+ size={menu.size || 'medium'}
170
+ onTabOut={clickAway}
171
+ />
172
+ </div>
173
+ </FloatingFocusManager>
174
+ </FloatingPortal>
148
175
  )}
149
176
  </div>
150
177
  )}
@@ -42,3 +42,8 @@
42
42
  color: colorTextDisabled;
43
43
  cursor: not-allowed;
44
44
  }
45
+
46
+ .menuWrapper {
47
+ width: var(--dropdown-width);
48
+ z-index: var(--menu-elevation);
49
+ }
@@ -32,6 +32,7 @@ const SimpleInlineDropdownBase = (props, ref) => {
32
32
  showLabelTooltip,
33
33
  clickAwayRef,
34
34
  allowWrap = false,
35
+ elevation = 'modal',
35
36
  ...buttonProps
36
37
  } = props;
37
38
  const [btnText, setBtnText] = React.useState('');
@@ -67,6 +68,7 @@ const SimpleInlineDropdownBase = (props, ref) => {
67
68
  onMenuOpen: onMenuOpen,
68
69
  onMenuClose: onMenuClose,
69
70
  clickAwayRef: clickAwayRef,
71
+ elevation: elevation,
70
72
  menu: {
71
73
  isFluid,
72
74
  options,
@@ -11,6 +11,7 @@ import {
11
11
  import type {ButtonProps} from '../Button';
12
12
  import type {AnchorType} from '../ButtonDropdown';
13
13
  import type {MenuOption, MenuOptionsVariant, Virtualization} from '../Menu';
14
+ import type {ElevationType} from '../Tooltip';
14
15
 
15
16
  import {InlineDropdown} from './InlineDropdown';
16
17
 
@@ -28,6 +29,7 @@ export type SimpleInlineDropdownProps = {
28
29
  // Input props
29
30
  ...ButtonProps,
30
31
 
32
+ elevation?: ElevationType,
31
33
  classNames?: ClassNames,
32
34
  anchorPosition?: AnchorType,
33
35
 
@@ -79,6 +81,7 @@ const SimpleInlineDropdownBase = (props: SimpleInlineDropdownProps, ref) => {
79
81
  showLabelTooltip,
80
82
  clickAwayRef,
81
83
  allowWrap = false,
84
+ elevation = 'modal',
82
85
  ...buttonProps
83
86
  } = props;
84
87
 
@@ -133,6 +136,7 @@ const SimpleInlineDropdownBase = (props: SimpleInlineDropdownProps, ref) => {
133
136
  onMenuOpen={onMenuOpen}
134
137
  onMenuClose={onMenuClose}
135
138
  clickAwayRef={clickAwayRef}
139
+ elevation={elevation}
136
140
  menu={{
137
141
  isFluid,
138
142
  options,
@@ -74,7 +74,7 @@ function StaticTable(props) {
74
74
  }, [width]);
75
75
 
76
76
  /**
77
- * this function is also used to decide weather to show checkbox in header or not. so it's value is undefined incase selectedKeys is not there.
77
+ * this function is also used to decide weather to show checkbox in header or not. so it's value is undefined in case selectedKeys is not there.
78
78
  */
79
79
 
80
80
  const handleHeaderCheckboxClick = selectedKeys ? ({
@@ -89,7 +89,7 @@ export function StaticTable<Data: GenericObject, Extras: GenericObject>(props: {
89
89
  }, [width]);
90
90
 
91
91
  /**
92
- * this function is also used to decide weather to show checkbox in header or not. so it's value is undefined incase selectedKeys is not there.
92
+ * this function is also used to decide weather to show checkbox in header or not. so it's value is undefined in case selectedKeys is not there.
93
93
  */
94
94
 
95
95
  const handleHeaderCheckboxClick = selectedKeys
@@ -104,7 +104,7 @@ const TABLE_DOCS = exports.TABLE_DOCS = {
104
104
  }
105
105
  },
106
106
  selectedKeys: {
107
- description: 'array of keys which are selected. This prop is also used to decide weather to show checkboxes or not. So, pass an empty array incase no row is selected.',
107
+ description: 'array of keys which are selected. This prop is also used to decide weather to show checkboxes or not. So, pass an empty array in case no row is selected.',
108
108
  control: {
109
109
  type: 'object'
110
110
  },
@@ -89,7 +89,7 @@ export const TABLE_DOCS = {
89
89
  },
90
90
  selectedKeys: {
91
91
  description:
92
- 'array of keys which are selected. This prop is also used to decide weather to show checkboxes or not. So, pass an empty array incase no row is selected.',
92
+ 'array of keys which are selected. This prop is also used to decide weather to show checkboxes or not. So, pass an empty array in case no row is selected.',
93
93
  control: {
94
94
  type: 'object',
95
95
  },