@telus-uds/components-base 1.34.0 → 1.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,20 @@
1
1
  # Change Log - @telus-uds/components-base
2
2
 
3
- This log was last generated on Thu, 13 Apr 2023 05:51:59 GMT and should not be manually modified.
3
+ This log was last generated on Tue, 18 Apr 2023 11:46:09 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 1.34.1
8
+
9
+ Tue, 18 Apr 2023 11:46:09 GMT
10
+
11
+ ### Patches
12
+
13
+ - multi-select-filter not showing modal fix (srikanthkhari@gmail.com)
14
+
7
15
  ## 1.34.0
8
16
 
9
- Thu, 13 Apr 2023 05:51:59 GMT
17
+ Thu, 13 Apr 2023 05:59:09 GMT
10
18
 
11
19
  ### Minor changes
12
20
 
@@ -41,7 +41,6 @@ const staticStyles = _StyleSheet.default.create({
41
41
  // Grow to maxWidth when possible, shrink when not possible
42
42
  position: 'absolute',
43
43
  height: 330,
44
- paddingTop: 5,
45
44
  zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
46
45
 
47
46
  },
@@ -50,6 +49,11 @@ const staticStyles = _StyleSheet.default.create({
50
49
  top: 0,
51
50
  right: 0,
52
51
  zIndex: 1
52
+ },
53
+ hidden: {
54
+ // Use opacity not visibility to hide the dropdown during positioning
55
+ // so on web, children may be focused from the first render
56
+ opacity: 0
53
57
  }
54
58
  });
55
59
 
@@ -81,8 +85,11 @@ const selectPaddingContainerStyles = _ref2 => {
81
85
  const ModalOverlay = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
82
86
  let {
83
87
  children,
84
- tokens,
88
+ isReady = false,
89
+ overlaidPosition,
90
+ onLayout,
85
91
  variant,
92
+ tokens,
86
93
  copy,
87
94
  onClose
88
95
  } = _ref3;
@@ -100,26 +107,25 @@ const ModalOverlay = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
100
107
  copy
101
108
  });
102
109
  const closeLabel = getCopy('closeButton');
103
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
104
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_portal.Portal, {
110
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_portal.Portal, {
111
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
105
112
  ref: ref,
106
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
107
- style: [{
108
- minWidth: maxWidth
109
- }, staticStyles.positioner],
110
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Card.default, {
111
- tokens: selectPaddingContainerStyles(themeTokens),
112
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
113
- style: [staticStyles.closeButtonContainer, selectCloseButtonContainerStyles(themeTokens)],
114
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
115
- onPress: onClose,
116
- icon: CloseIconComponent,
117
- accessibilityRole: "button",
118
- accessibilityLabel: closeLabel,
119
- tokens: (0, _utils.selectTokens)('IconButton', themeTokens, 'close')
120
- })
121
- }), children]
122
- })
113
+ onLayout: onLayout,
114
+ style: [overlaidPosition, {
115
+ minWidth: maxWidth
116
+ }, staticStyles.positioner, !isReady && staticStyles.hidden],
117
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Card.default, {
118
+ tokens: selectPaddingContainerStyles(themeTokens),
119
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
120
+ style: [staticStyles.closeButtonContainer, selectCloseButtonContainerStyles(themeTokens)],
121
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
122
+ onPress: onClose,
123
+ icon: CloseIconComponent,
124
+ accessibilityRole: "button",
125
+ accessibilityLabel: closeLabel,
126
+ tokens: (0, _utils.selectTokens)('IconButton', themeTokens, 'close')
127
+ })
128
+ }), children]
123
129
  })
124
130
  })
125
131
  });
@@ -127,6 +133,13 @@ const ModalOverlay = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
127
133
  ModalOverlay.displayName = 'ModalOverlay';
128
134
  ModalOverlay.propTypes = {
129
135
  children: _propTypes.default.node.isRequired,
136
+ isReady: _propTypes.default.bool,
137
+ overlaidPosition: _propTypes.default.shape({
138
+ top: _propTypes.default.number,
139
+ left: _propTypes.default.number,
140
+ width: _propTypes.default.number
141
+ }),
142
+ onLayout: _propTypes.default.func,
130
143
  variant: _utils.variantProp.propType,
131
144
  tokens: (0, _utils.getTokensPropType)('Modal'),
132
145
  copy: _utils.copyPropTypes,
@@ -72,7 +72,7 @@ const selectDividerToknes = _ref2 => {
72
72
  };
73
73
  };
74
74
 
75
- const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
75
+ const MultiSelectFilter = _ref3 => {
76
76
  let {
77
77
  label,
78
78
  subtitle,
@@ -136,9 +136,41 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
136
136
  setIsOpen(false);
137
137
  };
138
138
 
139
+ const {
140
+ align,
141
+ offsets
142
+ } = (0, _utils.useResponsiveProp)({
143
+ xs: {
144
+ align: {
145
+ top: 'top',
146
+ left: 'left',
147
+ bottom: 'bottom',
148
+ right: 'right'
149
+ }
150
+ },
151
+ sm: {
152
+ align: {
153
+ top: 'bottom',
154
+ left: 'left'
155
+ },
156
+ offsets: {
157
+ vertical: 4
158
+ }
159
+ }
160
+ });
161
+ const {
162
+ overlaidPosition,
163
+ onTargetLayout,
164
+ isReady,
165
+ sourceRef
166
+ } = (0, _utils.useOverlaidPosition)({
167
+ isShown: isOpen,
168
+ offsets,
169
+ align
170
+ });
139
171
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
140
172
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.ButtonDropdown, {
141
- ref: ref,
173
+ ref: sourceRef,
142
174
  ...pressHandlers,
143
175
  value: isOpen,
144
176
  selected: isSelected,
@@ -147,10 +179,15 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
147
179
  tokens: getButtonTokens,
148
180
  inactive: inactive
149
181
  }, id), isOpen && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_ModalOverlay.default, {
182
+ overlaidPosition: overlaidPosition,
150
183
  variant: {
151
184
  width: colSize > 1 ? 'size576' : 's'
152
185
  },
153
186
  onClose: () => setIsOpen(false),
187
+ tokens: tokens,
188
+ copy: copy,
189
+ isReady: isReady,
190
+ onLayout: onTargetLayout,
154
191
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
155
192
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
156
193
  variant: {
@@ -216,7 +253,8 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
216
253
  })]
217
254
  })]
218
255
  });
219
- });
256
+ };
257
+
220
258
  MultiSelectFilter.displayName = 'MultiSelectFilter';
221
259
  MultiSelectFilter.propTypes = {
222
260
  /**
@@ -9,6 +9,7 @@ var _exportNames = {
9
9
  useHash: true,
10
10
  useSpacingScale: true,
11
11
  useResponsiveProp: true,
12
+ useOverlaidPosition: true,
12
13
  useSafeLayoutEffect: true,
13
14
  useScrollBlocking: true,
14
15
  useUniqueId: true,
@@ -46,6 +47,12 @@ Object.defineProperty(exports, "useHash", {
46
47
  return _useHash.default;
47
48
  }
48
49
  });
50
+ Object.defineProperty(exports, "useOverlaidPosition", {
51
+ enumerable: true,
52
+ get: function () {
53
+ return _useOverlaidPosition.default;
54
+ }
55
+ });
49
56
  Object.defineProperty(exports, "useResponsiveProp", {
50
57
  enumerable: true,
51
58
  get: function () {
@@ -189,6 +196,8 @@ Object.keys(_useResponsiveProp).forEach(function (key) {
189
196
  });
190
197
  });
191
198
 
199
+ var _useOverlaidPosition = _interopRequireDefault(require("./useOverlaidPosition"));
200
+
192
201
  var _useSafeLayoutEffect = _interopRequireDefault(require("./useSafeLayoutEffect"));
193
202
 
194
203
  var _useScrollBlocking = _interopRequireDefault(require("./useScrollBlocking"));
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _react = require("react");
9
+
10
+ var _Dimensions = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Dimensions"));
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ const adjustHorizontalToFit = (initialOffset, windowWidth, sourceWidth) => {
15
+ const offset = Math.max(0, initialOffset);
16
+ const otherEdgeOverflow = Math.max(0, offset + sourceWidth - windowWidth);
17
+ const tooWideBy = Math.max(0, otherEdgeOverflow - offset);
18
+ const adjusted = {
19
+ offset: Math.max(0, offset - otherEdgeOverflow)
20
+ };
21
+ if (tooWideBy) adjusted.width = Math.max(0, sourceWidth - tooWideBy);
22
+ return adjusted;
23
+ };
24
+
25
+ const getPosition = _ref => {
26
+ let {
27
+ edge,
28
+ fromEdge,
29
+ sourceSize
30
+ } = _ref;
31
+
32
+ switch (edge) {
33
+ case 'near':
34
+ return fromEdge;
35
+
36
+ case 'mid':
37
+ return fromEdge + sourceSize / 2;
38
+
39
+ case 'far':
40
+ return fromEdge + sourceSize;
41
+
42
+ default:
43
+ return 0;
44
+ }
45
+ };
46
+
47
+ const getEdgeType = (align, alignSide) => {
48
+ const alignTo = align[alignSide];
49
+ const edge = ['center', 'middle'].includes(alignTo) && 'mid' || (alignSide === alignTo ? 'near' : 'far');
50
+ return edge;
51
+ };
52
+ /**
53
+ * Based on UDS's private getTooltipPosition but generalised.
54
+ *
55
+ * Used for absolute positioning of the tooltip. Since the tooltip is always centered relatively
56
+ * to the source (button) and we have a limited set of positions, an easy and consistent way
57
+ * of positioning it is to check all of the possible positions and pick one that will be rendered
58
+ * within the window bounds. This way we can also rely on the tooltip being actually rendered
59
+ * before it is shown, which makes it account for the width being limiting in styles, custom font
60
+ * rendering, etc.
61
+ */
62
+
63
+
64
+ function getOverlaidPosition(_ref2) {
65
+ let {
66
+ sourceLayout,
67
+ targetDimensions,
68
+ windowDimensions,
69
+ offsets = {},
70
+ align
71
+ } = _ref2;
72
+ // Web-only: this will be difficult to mimic on native because there's no global scroll position.
73
+ // TODO: wire something in e.g. a scroll ref accessible from a provider included in Allium provider
74
+ // that can be passed to the appropriate ScrollView?
75
+ const {
76
+ scrollX = 0,
77
+ scrollY = 0
78
+ } = typeof window === 'object' ? window : {}; // Will have top, bottom, left and/or right offsets depending on `align`
79
+
80
+ const positioning = {};
81
+ if (align.top) positioning.top = getPosition({
82
+ edge: getEdgeType(align, 'top'),
83
+ fromEdge: sourceLayout.y + scrollY + (offsets.vertical ?? 0),
84
+ sourceSize: sourceLayout.height
85
+ });
86
+ if (align.middle) positioning.top = getPosition({
87
+ edge: getEdgeType(align, 'middle'),
88
+ fromEdge: sourceLayout.y + scrollY + (offsets.vertical ?? 0) - targetDimensions.height / 2,
89
+ sourceSize: sourceLayout.height
90
+ });
91
+ if (align.bottom) positioning.bottom = getPosition({
92
+ edge: getEdgeType(align, 'bottom'),
93
+ fromEdge: windowDimensions.height - (sourceLayout.y + scrollY + sourceLayout.height - (offsets.vertical ?? 0)),
94
+ sourceSize: sourceLayout.height
95
+ });
96
+ if (align.left) positioning.left = getPosition({
97
+ edge: getEdgeType(align, 'left'),
98
+ fromEdge: sourceLayout.x + scrollX + (offsets.horizontal ?? 0),
99
+ sourceSize: sourceLayout.width
100
+ });
101
+ if (align.center) positioning.left = getPosition({
102
+ edge: getEdgeType(align, 'center'),
103
+ fromEdge: sourceLayout.x + scrollX + (offsets.horizontal ?? 0) - targetDimensions.width / 2,
104
+ sourceSize: sourceLayout.width
105
+ });
106
+ if (align.right) positioning.right = getPosition({
107
+ edge: getEdgeType(align, 'right'),
108
+ fromEdge: windowDimensions.width - (sourceLayout.x + scrollX + sourceLayout.width - (offsets.horizontal ?? 0)),
109
+ sourceSize: sourceLayout.width
110
+ });
111
+
112
+ if (!(align.left && align.right)) {
113
+ // Check if the position and/or width need adjusting to fit on the screen
114
+ const side = align.right ? 'right' : 'left';
115
+ const adjusted = adjustHorizontalToFit(positioning[side], windowDimensions.width, sourceLayout.width);
116
+ if (typeof adjusted.width === 'number') positioning.width = adjusted.width;
117
+
118
+ if (typeof adjusted.offset === 'number') {
119
+ positioning[side] = adjusted.offset;
120
+ }
121
+ }
122
+
123
+ return positioning;
124
+ }
125
+ /**
126
+ * Positions an element in a modal or portal so that it appears tooltip-like below the
127
+ * target element.
128
+ *
129
+ * @TODO - add support for positioning other than 'below' like UDS's tooltip (this is not
130
+ * a small task because UDS's tooltip logic only really works for short text - it might be
131
+ * better to use a third-party library).
132
+ */
133
+
134
+
135
+ const useOverlaidPosition = _ref3 => {
136
+ let {
137
+ isShown = false,
138
+ offsets,
139
+ // By default, align the overlaid target's `top` to the bottom of the source, and center horizontally.
140
+ align = {
141
+ center: 'center',
142
+ top: 'bottom'
143
+ }
144
+ } = _ref3;
145
+ // Element in main document flow that the targetRef element is positioned around
146
+ const sourceRef = (0, _react.useRef)(null);
147
+ const [sourceLayout, setSourceLayout] = (0, _react.useState)(null); // Element in a modal or portal overlay positioned to appear adjacent to sourceRef
148
+
149
+ const targetRef = (0, _react.useRef)(null);
150
+ const [targetDimensions, setTargetDimensions] = (0, _react.useState)(null);
151
+ const [windowDimensions, setWindowDimensions] = (0, _react.useState)(null);
152
+ const onTargetLayout = (0, _react.useCallback)(_ref4 => {
153
+ let {
154
+ nativeEvent: {
155
+ layout: {
156
+ width,
157
+ height
158
+ }
159
+ }
160
+ } = _ref4;
161
+ // NOTE: UDS's Tooltip logic injects some additional width to allow for antialiasing etc of text,
162
+ // avoiding adding unnecessary line breaks to text that is slightly wider than it thinks it is.
163
+ // That is probably something specific to text tooltips that doesn't belong in a generic hook.
164
+ setTargetDimensions(previousDimensions => {
165
+ // Re-render on first non-zero width / height: avoid infinite loops on changes, or mispositioning
166
+ // if user scrolls while a slidedown animation is changing the height and recalculating position.
167
+ if (!previousDimensions && width && height) {
168
+ return {
169
+ width,
170
+ height
171
+ };
172
+ }
173
+
174
+ return previousDimensions;
175
+ });
176
+ }, []);
177
+ const readyToShow = Boolean(isShown && sourceRef.current);
178
+ (0, _react.useEffect)(() => {
179
+ const handleDimensionsChange = _ref5 => {
180
+ var _sourceRef$current;
181
+
182
+ let {
183
+ window
184
+ } = _ref5;
185
+ (_sourceRef$current = sourceRef.current) === null || _sourceRef$current === void 0 ? void 0 : _sourceRef$current.measureInWindow((x, y, width, height) => {
186
+ // Could add a debouncer here if there's too many rerenders during gradual resizes
187
+ setWindowDimensions(window);
188
+ setSourceLayout({
189
+ x,
190
+ y,
191
+ width,
192
+ height
193
+ });
194
+ });
195
+ };
196
+
197
+ let subscription;
198
+
199
+ const unsubscribe = () => {
200
+ var _subscription;
201
+
202
+ if (typeof ((_subscription = subscription) === null || _subscription === void 0 ? void 0 : _subscription.remove) === 'function') {
203
+ // React Native >=0.65.0
204
+ subscription.remove();
205
+ } else if (typeof _Dimensions.default.removeEventListener === 'function') {
206
+ // React Native <0.65.0
207
+ _Dimensions.default.removeEventListener('change', handleDimensionsChange);
208
+ }
209
+
210
+ setSourceLayout(null);
211
+ setTargetDimensions(null);
212
+ };
213
+
214
+ if (readyToShow) {
215
+ subscription = _Dimensions.default.addEventListener('change', handleDimensionsChange);
216
+ handleDimensionsChange({
217
+ window: _Dimensions.default.get('window')
218
+ });
219
+ } else {
220
+ unsubscribe();
221
+ }
222
+
223
+ return unsubscribe;
224
+ }, [readyToShow]);
225
+ const isReady = Boolean(isShown && sourceLayout && windowDimensions && targetDimensions);
226
+ const overlaidPosition = isReady ? getOverlaidPosition({
227
+ sourceLayout,
228
+ targetDimensions,
229
+ windowDimensions,
230
+ offsets,
231
+ align
232
+ }) : {};
233
+ return {
234
+ overlaidPosition,
235
+ sourceRef,
236
+ targetRef,
237
+ onTargetLayout,
238
+ isReady
239
+ };
240
+ };
241
+
242
+ var _default = useOverlaidPosition;
243
+ exports.default = _default;
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import View from "react-native-web/dist/exports/View";
4
4
  import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
5
  import { Portal } from '@gorhom/portal';
6
- import { copyPropTypes, getTokensPropType, selectTokens, useCopy, variantProp } from '../utils';
6
+ import { selectTokens, useCopy, copyPropTypes, getTokensPropType, variantProp } from '../utils';
7
7
  import { useViewport } from '../ViewportProvider';
8
8
  import { useThemeTokens } from '../ThemeProvider';
9
9
  import dictionary from './dictionary';
@@ -11,14 +11,12 @@ import Card from '../Card';
11
11
  import IconButton from '../IconButton';
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { jsxs as _jsxs } from "react/jsx-runtime";
14
- import { Fragment as _Fragment } from "react/jsx-runtime";
15
14
  const staticStyles = StyleSheet.create({
16
15
  positioner: {
17
16
  flex: 1,
18
17
  // Grow to maxWidth when possible, shrink when not possible
19
18
  position: 'absolute',
20
19
  height: 330,
21
- paddingTop: 5,
22
20
  zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
23
21
 
24
22
  },
@@ -27,6 +25,11 @@ const staticStyles = StyleSheet.create({
27
25
  top: 0,
28
26
  right: 0,
29
27
  zIndex: 1
28
+ },
29
+ hidden: {
30
+ // Use opacity not visibility to hide the dropdown during positioning
31
+ // so on web, children may be focused from the first render
32
+ opacity: 0
30
33
  }
31
34
  });
32
35
 
@@ -58,8 +61,11 @@ const selectPaddingContainerStyles = _ref2 => {
58
61
  const ModalOverlay = /*#__PURE__*/forwardRef((_ref3, ref) => {
59
62
  let {
60
63
  children,
61
- tokens,
64
+ isReady = false,
65
+ overlaidPosition,
66
+ onLayout,
62
67
  variant,
68
+ tokens,
63
69
  copy,
64
70
  onClose
65
71
  } = _ref3;
@@ -77,26 +83,25 @@ const ModalOverlay = /*#__PURE__*/forwardRef((_ref3, ref) => {
77
83
  copy
78
84
  });
79
85
  const closeLabel = getCopy('closeButton');
80
- return /*#__PURE__*/_jsx(_Fragment, {
81
- children: /*#__PURE__*/_jsx(Portal, {
86
+ return /*#__PURE__*/_jsx(Portal, {
87
+ children: /*#__PURE__*/_jsx(View, {
82
88
  ref: ref,
83
- children: /*#__PURE__*/_jsx(View, {
84
- style: [{
85
- minWidth: maxWidth
86
- }, staticStyles.positioner],
87
- children: /*#__PURE__*/_jsxs(Card, {
88
- tokens: selectPaddingContainerStyles(themeTokens),
89
- children: [/*#__PURE__*/_jsx(View, {
90
- style: [staticStyles.closeButtonContainer, selectCloseButtonContainerStyles(themeTokens)],
91
- children: /*#__PURE__*/_jsx(IconButton, {
92
- onPress: onClose,
93
- icon: CloseIconComponent,
94
- accessibilityRole: "button",
95
- accessibilityLabel: closeLabel,
96
- tokens: selectTokens('IconButton', themeTokens, 'close')
97
- })
98
- }), children]
99
- })
89
+ onLayout: onLayout,
90
+ style: [overlaidPosition, {
91
+ minWidth: maxWidth
92
+ }, staticStyles.positioner, !isReady && staticStyles.hidden],
93
+ children: /*#__PURE__*/_jsxs(Card, {
94
+ tokens: selectPaddingContainerStyles(themeTokens),
95
+ children: [/*#__PURE__*/_jsx(View, {
96
+ style: [staticStyles.closeButtonContainer, selectCloseButtonContainerStyles(themeTokens)],
97
+ children: /*#__PURE__*/_jsx(IconButton, {
98
+ onPress: onClose,
99
+ icon: CloseIconComponent,
100
+ accessibilityRole: "button",
101
+ accessibilityLabel: closeLabel,
102
+ tokens: selectTokens('IconButton', themeTokens, 'close')
103
+ })
104
+ }), children]
100
105
  })
101
106
  })
102
107
  });
@@ -104,6 +109,13 @@ const ModalOverlay = /*#__PURE__*/forwardRef((_ref3, ref) => {
104
109
  ModalOverlay.displayName = 'ModalOverlay';
105
110
  ModalOverlay.propTypes = {
106
111
  children: PropTypes.node.isRequired,
112
+ isReady: PropTypes.bool,
113
+ overlaidPosition: PropTypes.shape({
114
+ top: PropTypes.number,
115
+ left: PropTypes.number,
116
+ width: PropTypes.number
117
+ }),
118
+ onLayout: PropTypes.func,
107
119
  variant: variantProp.propType,
108
120
  tokens: getTokensPropType('Modal'),
109
121
  copy: copyPropTypes,
@@ -1,7 +1,7 @@
1
- import React, { forwardRef, useState } from 'react';
1
+ import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider';
4
- import { containUniqueFields, getTokensPropType, getPressHandlersWithArgs, selectTokens, useCopy, useMultipleInputValues, variantProp } from '../utils';
4
+ import { containUniqueFields, getTokensPropType, getPressHandlersWithArgs, selectTokens, useOverlaidPosition, useCopy, useMultipleInputValues, useResponsiveProp, variantProp } from '../utils';
5
5
  import dictionary from './dictionary';
6
6
  import Box from '../Box';
7
7
  import { Button, ButtonDropdown } from '../Button';
@@ -45,7 +45,7 @@ const selectDividerToknes = _ref2 => {
45
45
  };
46
46
  };
47
47
 
48
- const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref3, ref) => {
48
+ const MultiSelectFilter = _ref3 => {
49
49
  let {
50
50
  label,
51
51
  subtitle,
@@ -109,9 +109,41 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref3, ref) => {
109
109
  setIsOpen(false);
110
110
  };
111
111
 
112
+ const {
113
+ align,
114
+ offsets
115
+ } = useResponsiveProp({
116
+ xs: {
117
+ align: {
118
+ top: 'top',
119
+ left: 'left',
120
+ bottom: 'bottom',
121
+ right: 'right'
122
+ }
123
+ },
124
+ sm: {
125
+ align: {
126
+ top: 'bottom',
127
+ left: 'left'
128
+ },
129
+ offsets: {
130
+ vertical: 4
131
+ }
132
+ }
133
+ });
134
+ const {
135
+ overlaidPosition,
136
+ onTargetLayout,
137
+ isReady,
138
+ sourceRef
139
+ } = useOverlaidPosition({
140
+ isShown: isOpen,
141
+ offsets,
142
+ align
143
+ });
112
144
  return /*#__PURE__*/_jsxs(_Fragment, {
113
145
  children: [/*#__PURE__*/_jsx(ButtonDropdown, {
114
- ref: ref,
146
+ ref: sourceRef,
115
147
  ...pressHandlers,
116
148
  value: isOpen,
117
149
  selected: isSelected,
@@ -120,10 +152,15 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref3, ref) => {
120
152
  tokens: getButtonTokens,
121
153
  inactive: inactive
122
154
  }, id), isOpen && /*#__PURE__*/_jsxs(ModalOverlay, {
155
+ overlaidPosition: overlaidPosition,
123
156
  variant: {
124
157
  width: colSize > 1 ? 'size576' : 's'
125
158
  },
126
159
  onClose: () => setIsOpen(false),
160
+ tokens: tokens,
161
+ copy: copy,
162
+ isReady: isReady,
163
+ onLayout: onTargetLayout,
127
164
  children: [/*#__PURE__*/_jsx(Row, {
128
165
  children: /*#__PURE__*/_jsx(Typography, {
129
166
  variant: {
@@ -189,7 +226,8 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref3, ref) => {
189
226
  })]
190
227
  })]
191
228
  });
192
- });
229
+ };
230
+
193
231
  MultiSelectFilter.displayName = 'MultiSelectFilter';
194
232
  MultiSelectFilter.propTypes = {
195
233
  /**
@@ -9,6 +9,7 @@ export { default as useCopy } from './useCopy';
9
9
  export { default as useHash } from './useHash';
10
10
  export { default as useSpacingScale } from './useSpacingScale';
11
11
  export { default as useResponsiveProp } from './useResponsiveProp';
12
+ export { default as useOverlaidPosition } from './useOverlaidPosition';
12
13
  export { default as useSafeLayoutEffect } from './useSafeLayoutEffect';
13
14
  export { default as useScrollBlocking } from './useScrollBlocking';
14
15
  export * from './useResponsiveProp';