@spaced-out/ui-design-system 0.3.49 → 0.3.51-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 (52) hide show
  1. package/CHANGELOG.md +14 -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/FilterButtonOverlay/FilterButtonOverlay.js +23 -8
  19. package/lib/components/FilterButtonOverlay/FilterButtonOverlay.js.flow +56 -26
  20. package/lib/components/InlineDropdown/InlineDropdown.js +25 -8
  21. package/lib/components/InlineDropdown/InlineDropdown.js.flow +57 -30
  22. package/lib/components/InlineDropdown/InlineDropdown.module.css +5 -0
  23. package/lib/components/InlineDropdown/SimpleInlineDropdown.js +2 -0
  24. package/lib/components/InlineDropdown/SimpleInlineDropdown.js.flow +4 -0
  25. package/lib/components/Table/StaticTable.js +1 -1
  26. package/lib/components/Table/StaticTable.js.flow +1 -1
  27. package/lib/components/Table/Table.docs.js +1 -1
  28. package/lib/components/Table/Table.docs.js.flow +1 -1
  29. package/lib/components/Tabs/TabList/TabDropdown.js +14 -7
  30. package/lib/components/Tabs/TabList/TabDropdown.js.flow +38 -22
  31. package/lib/components/Tabs/TabList/TabDropdown.module.css +4 -0
  32. package/lib/components/Tabs/TabList/TabList.js +4 -2
  33. package/lib/components/Tabs/TabList/TabList.js.flow +4 -0
  34. package/lib/components/TokenListInput/TokenListInput.js +26 -7
  35. package/lib/components/TokenListInput/TokenListInput.js.flow +58 -32
  36. package/lib/components/TokenListInput/TokenListInput.module.css +5 -0
  37. package/lib/components/Tooltip/Tooltip.js +2 -1
  38. package/lib/components/Tooltip/Tooltip.js.flow +2 -2
  39. package/lib/components/Typeahead/SimpleTypeahead.js +3 -1
  40. package/lib/components/Typeahead/SimpleTypeahead.js.flow +4 -0
  41. package/lib/components/Typeahead/Typeahead.js +25 -8
  42. package/lib/components/Typeahead/Typeahead.js.flow +58 -30
  43. package/lib/components/Typeahead/Typeahead.module.css +5 -0
  44. package/lib/hooks/index.js +11 -0
  45. package/lib/hooks/index.js.flow +1 -0
  46. package/lib/hooks/useReferenceElementWidth/index.js +16 -0
  47. package/lib/hooks/useReferenceElementWidth/index.js.flow +3 -0
  48. package/lib/hooks/useReferenceElementWidth/useReferenceElementWidth.js +21 -0
  49. package/lib/hooks/useReferenceElementWidth/useReferenceElementWidth.js.flow +23 -0
  50. package/lib/utils/click-away/click-away.js +4 -0
  51. package/lib/utils/click-away/click-away.js.flow +34 -0
  52. package/package.json +5 -5
@@ -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,12 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.FilterButtonOverlay = 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 _utils = require("../../utils");
12
12
  var _classify = _interopRequireDefault(require("../../utils/classify"));
13
13
  var _Button = require("../Button");
14
14
  var _ButtonDropdown = require("../ButtonDropdown");
15
+ var _Tooltip = require("../Tooltip");
15
16
  var _FilterButtonOverlayModule = _interopRequireDefault(require("./FilterButtonOverlay.module.css"));
16
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
18
  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); }
@@ -28,13 +29,15 @@ const FilterButtonOverlay = exports.FilterButtonOverlay = /*#__PURE__*/React.for
28
29
  buttonLabel,
29
30
  buttonIsFluid,
30
31
  buttonSize,
32
+ elevation = 'modal',
31
33
  ...restProps
32
34
  } = _ref;
33
35
  const {
34
36
  x,
35
37
  y,
36
38
  refs,
37
- strategy
39
+ strategy,
40
+ context
38
41
  } = (0, _react2.useFloating)({
39
42
  open: true,
40
43
  strategy: positionStrategy,
@@ -42,9 +45,11 @@ const FilterButtonOverlay = exports.FilterButtonOverlay = /*#__PURE__*/React.for
42
45
  whileElementsMounted: _react2.autoUpdate,
43
46
  middleware: [(0, _react2.shift)(), (0, _react2.flip)(), (0, _react2.offset)(parseInt(_space.spaceXXSmall))]
44
47
  });
48
+ const dropdownWidth = (0, _hooks.useReferenceElementWidth)(refs.reference?.current);
45
49
  return /*#__PURE__*/React.createElement(_utils.ClickAway, {
46
50
  clickAwayRef: clickAwayRef,
47
- closeOnEscapeKeypress: true
51
+ closeOnEscapeKeypress: true,
52
+ containsNestedFloatingPortals: true
48
53
  }, _ref2 => {
49
54
  let {
50
55
  isOpen,
@@ -66,16 +71,26 @@ const FilterButtonOverlay = exports.FilterButtonOverlay = /*#__PURE__*/React.for
66
71
  },
67
72
  isFluid: buttonIsFluid,
68
73
  size: buttonSize
69
- }), buttonLabel), isOpen && /*#__PURE__*/React.createElement("div", {
74
+ }), buttonLabel), isOpen && /*#__PURE__*/React.createElement(_react2.FloatingPortal, null, /*#__PURE__*/React.createElement(_react2.FloatingFocusManager, {
75
+ modal: false,
76
+ context: context,
77
+ initialFocus: refs.reference
78
+ }, /*#__PURE__*/React.createElement("div", {
70
79
  ref: (0, _utils.mergeRefs)([refs.setFloating, boundaryRef]),
71
80
  style: {
72
81
  display: 'flex',
73
82
  position: strategy,
74
83
  top: y ?? _space.spaceNone,
75
84
  left: x ?? _space.spaceNone,
76
- ...(isFluid && {
77
- width: _size.sizeFluid
78
- })
85
+ /* NOTE(Sharad): The FloatingPortal renders the menu outside the normal DOM structure,
86
+ so its parent is effectively the <body> element. This means the menu
87
+ would otherwise default to the body's width. To support fluid width,
88
+ we must manually set the dropdown width here; otherwise, it uses a fixed width.
89
+ Also, Only treat menu as non-fluid if isFluid is strictly false, since default is true in menu and undefined means fluid. */
90
+ ...(isFluid !== false && {
91
+ '--dropdown-width': dropdownWidth
92
+ }),
93
+ '--menu-elevation': (0, _Tooltip.getElevationValue)(elevation)
79
94
  }
80
95
  }, /*#__PURE__*/React.createElement("div", {
81
96
  className: (0, _classify.default)(_FilterButtonOverlayModule.default.overlayWrapper, {
@@ -83,6 +98,6 @@ const FilterButtonOverlay = exports.FilterButtonOverlay = /*#__PURE__*/React.for
83
98
  [_FilterButtonOverlayModule.default.medium]: size === 'medium',
84
99
  [_FilterButtonOverlayModule.default.small]: size === 'small'
85
100
  }, classNames?.overlayContainer)
86
- }, children)));
101
+ }, children)))));
87
102
  });
88
103
  });
@@ -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,7 +18,7 @@ import {
14
18
  useFloating,
15
19
  } from '@floating-ui/react';
16
20
 
17
- import {sizeFluid} from '../../styles/variables/_size';
21
+ import {useReferenceElementWidth} from '../../hooks';
18
22
  import {spaceNone, spaceXXSmall} from '../../styles/variables/_space';
19
23
  import type {ClickAwayRefType} from '../../utils';
20
24
  import {ClickAway, mergeRefs} from '../../utils';
@@ -23,6 +27,8 @@ import type {ButtonProps, ButtonSize} from '../Button';
23
27
  import {Button} from '../Button';
24
28
  import type {AnchorType, Strategy} from '../ButtonDropdown';
25
29
  import {ANCHOR_POSITION_TYPE, STRATEGY_TYPE} from '../ButtonDropdown';
30
+ import type {ElevationType} from '../Tooltip';
31
+ import {getElevationValue} from '../Tooltip';
26
32
 
27
33
  import css from './FilterButtonOverlay.module.css';
28
34
 
@@ -43,6 +49,7 @@ export type FilterButtonOverlayProps = {
43
49
  size?: FilterButtonOverlaySizeTypes,
44
50
  buttonLabel?: React.Node,
45
51
  buttonSize?: ButtonSize,
52
+ elevation?: ElevationType,
46
53
  buttonIsFluid?: boolean,
47
54
  ...
48
55
  };
@@ -63,11 +70,12 @@ export const FilterButtonOverlay: React$AbstractComponent<
63
70
  buttonLabel,
64
71
  buttonIsFluid,
65
72
  buttonSize,
73
+ elevation = 'modal',
66
74
  ...restProps
67
75
  }: FilterButtonOverlayProps,
68
76
  ref,
69
77
  ) => {
70
- const {x, y, refs, strategy} = useFloating({
78
+ const {x, y, refs, strategy, context} = useFloating({
71
79
  open: true,
72
80
  strategy: positionStrategy,
73
81
  placement: anchorPosition,
@@ -75,8 +83,14 @@ export const FilterButtonOverlay: React$AbstractComponent<
75
83
  middleware: [shift(), flip(), offset(parseInt(spaceXXSmall))],
76
84
  });
77
85
 
86
+ const dropdownWidth = useReferenceElementWidth(refs.reference?.current);
87
+
78
88
  return (
79
- <ClickAway clickAwayRef={clickAwayRef} closeOnEscapeKeypress>
89
+ <ClickAway
90
+ clickAwayRef={clickAwayRef}
91
+ closeOnEscapeKeypress
92
+ containsNestedFloatingPortals
93
+ >
80
94
  {({isOpen, onOpen, boundaryRef, triggerRef}) => (
81
95
  <div
82
96
  data-testid="FilterButtonOverlay"
@@ -102,30 +116,46 @@ export const FilterButtonOverlay: React$AbstractComponent<
102
116
  </Button>
103
117
 
104
118
  {isOpen && (
105
- <div
106
- ref={mergeRefs([refs.setFloating, boundaryRef])}
107
- style={{
108
- display: 'flex',
109
- position: strategy,
110
- top: y ?? spaceNone,
111
- left: x ?? spaceNone,
112
- ...(isFluid && {width: sizeFluid}),
113
- }}
114
- >
115
- <div
116
- className={classify(
117
- css.overlayWrapper,
118
- {
119
- [css.fluid]: isFluid,
120
- [css.medium]: size === 'medium',
121
- [css.small]: size === 'small',
122
- },
123
- classNames?.overlayContainer,
124
- )}
119
+ <FloatingPortal>
120
+ <FloatingFocusManager
121
+ modal={false}
122
+ context={context}
123
+ initialFocus={refs.reference}
125
124
  >
126
- {children}
127
- </div>
128
- </div>
125
+ <div
126
+ ref={mergeRefs([refs.setFloating, boundaryRef])}
127
+ style={{
128
+ display: 'flex',
129
+ position: strategy,
130
+ top: y ?? spaceNone,
131
+ left: x ?? spaceNone,
132
+ /* NOTE(Sharad): The FloatingPortal renders the menu outside the normal DOM structure,
133
+ so its parent is effectively the <body> element. This means the menu
134
+ would otherwise default to the body's width. To support fluid width,
135
+ we must manually set the dropdown width here; otherwise, it uses a fixed width.
136
+ Also, Only treat menu as non-fluid if isFluid is strictly false, since default is true in menu and undefined means fluid. */
137
+ ...(isFluid !== false && {
138
+ '--dropdown-width': dropdownWidth,
139
+ }),
140
+ '--menu-elevation': getElevationValue(elevation),
141
+ }}
142
+ >
143
+ <div
144
+ className={classify(
145
+ css.overlayWrapper,
146
+ {
147
+ [css.fluid]: isFluid,
148
+ [css.medium]: size === 'medium',
149
+ [css.small]: size === 'small',
150
+ },
151
+ classNames?.overlayContainer,
152
+ )}
153
+ >
154
+ {children}
155
+ </div>
156
+ </div>
157
+ </FloatingFocusManager>
158
+ </FloatingPortal>
129
159
  )}
130
160
  </div>
131
161
  )}
@@ -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
  });