@kaizen/components 0.0.0-canary-test-fms-popover-api-update-20250624021814 → 0.0.0-canary-fix-tab-20250626012516
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/dist/cjs/src/Filter/FilterMultiSelect/FilterMultiSelect.cjs +3 -7
- package/dist/cjs/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.cjs +1 -1
- package/dist/cjs/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.module.scss.cjs +9 -0
- package/dist/cjs/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.cjs +38 -57
- package/dist/cjs/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/{MenuPopup.module.css.cjs → MenuPopup.module.scss.cjs} +1 -1
- package/dist/esm/src/Filter/FilterMultiSelect/FilterMultiSelect.mjs +3 -7
- package/dist/esm/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.mjs +1 -1
- package/dist/esm/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.module.scss.mjs +7 -0
- package/dist/esm/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.mjs +41 -58
- package/dist/esm/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.module.scss.mjs +4 -0
- package/dist/styles.css +22 -29
- package/dist/types/Filter/FilterMultiSelect/FilterMultiSelect.d.ts +1 -1
- package/dist/types/Filter/FilterMultiSelect/_docs/MockData.d.ts +0 -1
- package/dist/types/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.d.ts +4 -7
- package/package.json +1 -1
- package/src/Filter/FilterBar/subcomponents/FilterBarMultiSelect/FilterBarMultiSelect.spec.tsx +0 -1
- package/src/Filter/FilterMultiSelect/FilterMultiSelect.tsx +2 -3
- package/src/Filter/FilterMultiSelect/_docs/FilterMultiSelect.mdx +0 -8
- package/src/Filter/FilterMultiSelect/_docs/FilterMultiSelect.stories.tsx +1 -89
- package/src/Filter/FilterMultiSelect/_docs/MockData.ts +0 -39
- package/src/Filter/FilterMultiSelect/context/MenuTriggerProvider/MenuTriggerProvider.spec.tsx +18 -2
- package/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.module.scss +25 -0
- package/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.tsx +1 -1
- package/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.module.scss +24 -0
- package/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.tsx +42 -62
- package/src/__next__/Tabs/subcomponents/TabList/TabList.module.css +1 -1
- package/dist/cjs/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.module.css.cjs +0 -9
- package/dist/esm/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.module.css.mjs +0 -7
- package/dist/esm/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.module.css.mjs +0 -4
- package/src/Filter/FilterMultiSelect/subcomponents/ListBox/ListBox.module.css +0 -22
- package/src/Filter/FilterMultiSelect/subcomponents/MenuPopup/MenuPopup.module.css +0 -22
|
@@ -41,8 +41,7 @@ var FilterMultiSelect = function (_a) {
|
|
|
41
41
|
selectionMode = _b === void 0 ? 'multiple' : _b,
|
|
42
42
|
onSearchInputChange = _a.onSearchInputChange,
|
|
43
43
|
triggerRef = _a.triggerRef,
|
|
44
|
-
className = _a.className
|
|
45
|
-
floatingOptions = _a.floatingOptions;
|
|
44
|
+
className = _a.className;
|
|
46
45
|
var menuTriggerProps = {
|
|
47
46
|
isOpen: isOpen,
|
|
48
47
|
defaultOpen: defaultOpen,
|
|
@@ -51,8 +50,7 @@ var FilterMultiSelect = function (_a) {
|
|
|
51
50
|
};
|
|
52
51
|
var menuPopupProps = {
|
|
53
52
|
isLoading: isLoading,
|
|
54
|
-
loadingSkeleton: loadingSkeleton
|
|
55
|
-
floatingOptions: floatingOptions
|
|
53
|
+
loadingSkeleton: loadingSkeleton
|
|
56
54
|
};
|
|
57
55
|
var disabledKeys = new Set(items === null || items === void 0 ? void 0 : items.filter(function (item) {
|
|
58
56
|
return item.isDisabled === true;
|
|
@@ -71,9 +69,7 @@ var FilterMultiSelect = function (_a) {
|
|
|
71
69
|
};
|
|
72
70
|
return React__default.default.createElement(MenuTriggerProvider.MenuTriggerProvider, tslib.__assign({}, menuTriggerProps), React__default.default.createElement("div", {
|
|
73
71
|
className: className
|
|
74
|
-
}, React__default.default.createElement(MenuTriggerProvider.MenuTriggerConsumer, null, trigger), React__default.default.createElement(MenuPopup.MenuPopup, tslib.__assign({
|
|
75
|
-
"aria-label": label
|
|
76
|
-
}, menuPopupProps), React__default.default.createElement(SelectionProvider.SelectionProvider, tslib.__assign({}, selectionProps), React__default.default.createElement(SelectionProvider.SelectionConsumer, null, children)))));
|
|
72
|
+
}, React__default.default.createElement(MenuTriggerProvider.MenuTriggerConsumer, null, trigger), React__default.default.createElement(MenuPopup.MenuPopup, tslib.__assign({}, menuPopupProps), React__default.default.createElement(SelectionProvider.SelectionProvider, tslib.__assign({}, selectionProps), React__default.default.createElement(SelectionProvider.SelectionConsumer, null, children)))));
|
|
77
73
|
};
|
|
78
74
|
FilterMultiSelect.displayName = 'FilterMultiSelect';
|
|
79
75
|
FilterMultiSelect.TriggerButton = FilterTriggerButton.FilterTriggerButton;
|
|
@@ -4,7 +4,7 @@ var tslib = require('tslib');
|
|
|
4
4
|
var React = require('react');
|
|
5
5
|
var classnames = require('classnames');
|
|
6
6
|
var SelectionProvider = require('../../context/SelectionProvider/SelectionProvider.cjs');
|
|
7
|
-
var ListBox_module = require('./ListBox.module.
|
|
7
|
+
var ListBox_module = require('./ListBox.module.scss.cjs');
|
|
8
8
|
function _interopDefault(e) {
|
|
9
9
|
return e && e.__esModule ? e : {
|
|
10
10
|
default: e
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var styles = {
|
|
4
|
+
"listBox": "ListBox-module_listBox__q95MO",
|
|
5
|
+
"overflown": "ListBox-module_overflown__wChQA",
|
|
6
|
+
"hidden": "ListBox-module_hidden__eYdXv",
|
|
7
|
+
"noResultsWrapper": "ListBox-module_noResultsWrapper__WcLRm"
|
|
8
|
+
};
|
|
9
|
+
module.exports = styles;
|
|
@@ -2,74 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
var tslib = require('tslib');
|
|
4
4
|
var React = require('react');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var reactFocusOn = require('react-focus-on');
|
|
5
|
+
var focus = require('@react-aria/focus');
|
|
6
|
+
var overlays = require('@react-aria/overlays');
|
|
8
7
|
var MenuTriggerProvider = require('../../context/MenuTriggerProvider/MenuTriggerProvider.cjs');
|
|
9
8
|
require('../../context/SelectionProvider/SelectionProvider.cjs');
|
|
10
|
-
var MenuPopup_module = require('./MenuPopup.module.
|
|
9
|
+
var MenuPopup_module = require('./MenuPopup.module.scss.cjs');
|
|
11
10
|
function _interopDefault(e) {
|
|
12
11
|
return e && e.__esModule ? e : {
|
|
13
12
|
default: e
|
|
14
13
|
};
|
|
15
14
|
}
|
|
16
15
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
17
|
-
var classnames__default = /*#__PURE__*/_interopDefault(classnames);
|
|
18
16
|
var MenuPopup = function (_a) {
|
|
19
|
-
var
|
|
20
|
-
floatingOptions = _a.floatingOptions,
|
|
21
|
-
classNameOverride = _a.classNameOverride,
|
|
22
|
-
isLoading = _a.isLoading,
|
|
17
|
+
var isLoading = _a.isLoading,
|
|
23
18
|
loadingSkeleton = _a.loadingSkeleton,
|
|
24
|
-
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
var _c = MenuTriggerProvider.useMenuTriggerContext(),
|
|
29
|
-
menuTriggerState = _c.menuTriggerState,
|
|
30
|
-
buttonRef = _c.buttonRef;
|
|
31
|
-
var referenceElement = buttonRef.current;
|
|
32
|
-
var _d = reactDom.useFloating(tslib.__assign({
|
|
33
|
-
placement: 'bottom-start',
|
|
34
|
-
elements: {
|
|
35
|
-
reference: referenceElement,
|
|
36
|
-
floating: floatingElement
|
|
37
|
-
},
|
|
38
|
-
strategy: 'absolute',
|
|
39
|
-
middleware: [reactDom.offset(6)],
|
|
40
|
-
whileElementsMounted: reactDom.autoUpdate
|
|
41
|
-
}, floatingOptions)),
|
|
42
|
-
floatingStyles = _d.floatingStyles,
|
|
43
|
-
update = _d.update;
|
|
44
|
-
var handleReturnFocus = function () {
|
|
45
|
-
requestAnimationFrame(function () {
|
|
46
|
-
var _a;
|
|
47
|
-
(_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
48
|
-
});
|
|
19
|
+
children = _a.children;
|
|
20
|
+
var menuTriggerState = MenuTriggerProvider.useMenuTriggerContext().menuTriggerState;
|
|
21
|
+
var onClose = function () {
|
|
22
|
+
return menuTriggerState.close();
|
|
49
23
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
24
|
+
// Handle events that should cause the menu to close,
|
|
25
|
+
// e.g. blur, clicking outside, or pressing the escape key.
|
|
26
|
+
var overlayRef = React__default.default.createRef();
|
|
27
|
+
var overlayProps = overlays.useOverlay({
|
|
28
|
+
onClose: onClose,
|
|
29
|
+
isOpen: menuTriggerState.isOpen,
|
|
30
|
+
isDismissable: true
|
|
31
|
+
}, overlayRef).overlayProps;
|
|
32
|
+
// Wrap in <FocusScope> so that focus is restored back to the trigger when the menu is closed
|
|
33
|
+
// and auto focus on the first focusable item after loading. (disable eslint no-autofocus error for it)
|
|
34
|
+
// In addition, add hidden <DismissButton> components at the start and end of the list
|
|
35
|
+
// to allow screen reader users to dismiss the popup easily.
|
|
36
|
+
return menuTriggerState.isOpen ? React__default.default.createElement("div", tslib.__assign({}, overlayProps, {
|
|
37
|
+
ref: overlayRef,
|
|
38
|
+
className: MenuPopup_module.menuPopup
|
|
39
|
+
}), isLoading && loadingSkeleton ? React__default.default.createElement(React__default.default.Fragment, null, React__default.default.createElement(overlays.DismissButton, {
|
|
40
|
+
onDismiss: onClose
|
|
41
|
+
}), loadingSkeleton, React__default.default.createElement(overlays.DismissButton, {
|
|
42
|
+
onDismiss: onClose
|
|
43
|
+
})) :
|
|
44
|
+
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
45
|
+
React__default.default.createElement(focus.FocusScope, {
|
|
46
|
+
contain: true,
|
|
47
|
+
autoFocus: true,
|
|
48
|
+
restoreFocus: true
|
|
49
|
+
}, React__default.default.createElement(overlays.DismissButton, {
|
|
50
|
+
onDismiss: onClose
|
|
51
|
+
}), children, React__default.default.createElement(overlays.DismissButton, {
|
|
52
|
+
onDismiss: onClose
|
|
53
|
+
}))) : React__default.default.createElement(React__default.default.Fragment, null);
|
|
73
54
|
};
|
|
74
55
|
MenuPopup.displayName = 'FilterMultiSelect.MenuPopup';
|
|
75
56
|
exports.MenuPopup = MenuPopup;
|
|
@@ -34,8 +34,7 @@ const FilterMultiSelect = /*#__PURE__*/function () {
|
|
|
34
34
|
selectionMode = _b === void 0 ? 'multiple' : _b,
|
|
35
35
|
onSearchInputChange = _a.onSearchInputChange,
|
|
36
36
|
triggerRef = _a.triggerRef,
|
|
37
|
-
className = _a.className
|
|
38
|
-
floatingOptions = _a.floatingOptions;
|
|
37
|
+
className = _a.className;
|
|
39
38
|
var menuTriggerProps = {
|
|
40
39
|
isOpen: isOpen,
|
|
41
40
|
defaultOpen: defaultOpen,
|
|
@@ -44,8 +43,7 @@ const FilterMultiSelect = /*#__PURE__*/function () {
|
|
|
44
43
|
};
|
|
45
44
|
var menuPopupProps = {
|
|
46
45
|
isLoading: isLoading,
|
|
47
|
-
loadingSkeleton: loadingSkeleton
|
|
48
|
-
floatingOptions: floatingOptions
|
|
46
|
+
loadingSkeleton: loadingSkeleton
|
|
49
47
|
};
|
|
50
48
|
var disabledKeys = new Set(items === null || items === void 0 ? void 0 : items.filter(function (item) {
|
|
51
49
|
return item.isDisabled === true;
|
|
@@ -64,9 +62,7 @@ const FilterMultiSelect = /*#__PURE__*/function () {
|
|
|
64
62
|
};
|
|
65
63
|
return /*#__PURE__*/React.createElement(MenuTriggerProvider, __assign({}, menuTriggerProps), /*#__PURE__*/React.createElement("div", {
|
|
66
64
|
className: className
|
|
67
|
-
}, /*#__PURE__*/React.createElement(MenuTriggerConsumer, null, trigger), /*#__PURE__*/React.createElement(MenuPopup, __assign({
|
|
68
|
-
"aria-label": label
|
|
69
|
-
}, menuPopupProps), /*#__PURE__*/React.createElement(SelectionProvider, __assign({}, selectionProps), /*#__PURE__*/React.createElement(SelectionConsumer, null, children)))));
|
|
65
|
+
}, /*#__PURE__*/React.createElement(MenuTriggerConsumer, null, trigger), /*#__PURE__*/React.createElement(MenuPopup, __assign({}, menuPopupProps), /*#__PURE__*/React.createElement(SelectionProvider, __assign({}, selectionProps), /*#__PURE__*/React.createElement(SelectionConsumer, null, children)))));
|
|
70
66
|
};
|
|
71
67
|
FilterMultiSelect.displayName = 'FilterMultiSelect';
|
|
72
68
|
FilterMultiSelect.TriggerButton = FilterTriggerButton;
|
|
@@ -2,7 +2,7 @@ import { __assign, __spreadArray } from 'tslib';
|
|
|
2
2
|
import React, { useState, useEffect } from 'react';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
4
|
import { useSelectionContext } from '../../context/SelectionProvider/SelectionProvider.mjs';
|
|
5
|
-
import styles from './ListBox.module.
|
|
5
|
+
import styles from './ListBox.module.scss.mjs';
|
|
6
6
|
var getItemsFromKeys = function (items, keys) {
|
|
7
7
|
var itemKeys = Array.from(keys);
|
|
8
8
|
return itemKeys.reduce(function (acc, itemKey) {
|
|
@@ -1,67 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import React
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import { FocusOn } from 'react-focus-on';
|
|
1
|
+
import { __assign } from 'tslib';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { FocusScope } from '@react-aria/focus';
|
|
4
|
+
import { useOverlay, DismissButton } from '@react-aria/overlays';
|
|
6
5
|
import { useMenuTriggerContext } from '../../context/MenuTriggerProvider/MenuTriggerProvider.mjs';
|
|
7
6
|
import '../../context/SelectionProvider/SelectionProvider.mjs';
|
|
8
|
-
import styles from './MenuPopup.module.
|
|
7
|
+
import styles from './MenuPopup.module.scss.mjs';
|
|
9
8
|
const MenuPopup = /*#__PURE__*/function () {
|
|
10
9
|
const MenuPopup = function (_a) {
|
|
11
|
-
var
|
|
12
|
-
floatingOptions = _a.floatingOptions,
|
|
13
|
-
classNameOverride = _a.classNameOverride,
|
|
14
|
-
isLoading = _a.isLoading,
|
|
10
|
+
var isLoading = _a.isLoading,
|
|
15
11
|
loadingSkeleton = _a.loadingSkeleton,
|
|
16
|
-
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
var _c = useMenuTriggerContext(),
|
|
21
|
-
menuTriggerState = _c.menuTriggerState,
|
|
22
|
-
buttonRef = _c.buttonRef;
|
|
23
|
-
var referenceElement = buttonRef.current;
|
|
24
|
-
var _d = useFloating(__assign({
|
|
25
|
-
placement: 'bottom-start',
|
|
26
|
-
elements: {
|
|
27
|
-
reference: referenceElement,
|
|
28
|
-
floating: floatingElement
|
|
29
|
-
},
|
|
30
|
-
strategy: 'absolute',
|
|
31
|
-
middleware: [offset(6)],
|
|
32
|
-
whileElementsMounted: autoUpdate
|
|
33
|
-
}, floatingOptions)),
|
|
34
|
-
floatingStyles = _d.floatingStyles,
|
|
35
|
-
update = _d.update;
|
|
36
|
-
var handleReturnFocus = function () {
|
|
37
|
-
requestAnimationFrame(function () {
|
|
38
|
-
var _a;
|
|
39
|
-
(_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
40
|
-
});
|
|
12
|
+
children = _a.children;
|
|
13
|
+
var menuTriggerState = useMenuTriggerContext().menuTriggerState;
|
|
14
|
+
var onClose = function () {
|
|
15
|
+
return menuTriggerState.close();
|
|
41
16
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
17
|
+
// Handle events that should cause the menu to close,
|
|
18
|
+
// e.g. blur, clicking outside, or pressing the escape key.
|
|
19
|
+
var overlayRef = /*#__PURE__*/React.createRef();
|
|
20
|
+
var overlayProps = useOverlay({
|
|
21
|
+
onClose: onClose,
|
|
22
|
+
isOpen: menuTriggerState.isOpen,
|
|
23
|
+
isDismissable: true
|
|
24
|
+
}, overlayRef).overlayProps;
|
|
25
|
+
// Wrap in <FocusScope> so that focus is restored back to the trigger when the menu is closed
|
|
26
|
+
// and auto focus on the first focusable item after loading. (disable eslint no-autofocus error for it)
|
|
27
|
+
// In addition, add hidden <DismissButton> components at the start and end of the list
|
|
28
|
+
// to allow screen reader users to dismiss the popup easily.
|
|
29
|
+
return menuTriggerState.isOpen ? (/*#__PURE__*/React.createElement("div", __assign({}, overlayProps, {
|
|
30
|
+
ref: overlayRef,
|
|
31
|
+
className: styles.menuPopup
|
|
32
|
+
}), isLoading && loadingSkeleton ? (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DismissButton, {
|
|
33
|
+
onDismiss: onClose
|
|
34
|
+
}), loadingSkeleton, /*#__PURE__*/React.createElement(DismissButton, {
|
|
35
|
+
onDismiss: onClose
|
|
36
|
+
}))) : (
|
|
37
|
+
/*#__PURE__*/
|
|
38
|
+
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
39
|
+
React.createElement(FocusScope, {
|
|
40
|
+
contain: true,
|
|
41
|
+
autoFocus: true,
|
|
42
|
+
restoreFocus: true
|
|
43
|
+
}, /*#__PURE__*/React.createElement(DismissButton, {
|
|
44
|
+
onDismiss: onClose
|
|
45
|
+
}), children, /*#__PURE__*/React.createElement(DismissButton, {
|
|
46
|
+
onDismiss: onClose
|
|
47
|
+
}))))) : (/*#__PURE__*/React.createElement(React.Fragment, null));
|
|
65
48
|
};
|
|
66
49
|
MenuPopup.displayName = 'FilterMultiSelect.MenuPopup';
|
|
67
50
|
return MenuPopup;
|
package/dist/styles.css
CHANGED
|
@@ -3743,29 +3743,26 @@
|
|
|
3743
3743
|
}
|
|
3744
3744
|
}
|
|
3745
3745
|
|
|
3746
|
+
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3746
3747
|
@layer kz-components {
|
|
3747
|
-
.ListBox-
|
|
3748
|
+
.ListBox-module_listBox__q95MO {
|
|
3748
3749
|
list-style: none;
|
|
3749
|
-
padding: var(--spacing-
|
|
3750
|
-
margin: 0 var(--spacing-
|
|
3750
|
+
padding: var(--spacing-sm, 0.75rem);
|
|
3751
|
+
margin: 0 var(--spacing-sm, 0.75rem) 0 0;
|
|
3751
3752
|
display: grid;
|
|
3752
3753
|
max-height: 22rem;
|
|
3753
3754
|
overflow-y: auto;
|
|
3754
3755
|
}
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
padding-right: var(--spacing-12);
|
|
3756
|
+
.ListBox-module_overflown__wChQA {
|
|
3757
|
+
padding-right: var(--spacing-sm, 0.75rem);
|
|
3758
3758
|
}
|
|
3759
|
-
|
|
3760
|
-
.ListBox-module_hidden__mO-oL {
|
|
3759
|
+
.ListBox-module_hidden__eYdXv {
|
|
3761
3760
|
display: none;
|
|
3762
3761
|
}
|
|
3763
|
-
|
|
3764
|
-
.ListBox-module_noResultsWrapper__RnMj0 {
|
|
3762
|
+
.ListBox-module_noResultsWrapper__WcLRm {
|
|
3765
3763
|
list-style: none;
|
|
3766
3764
|
}
|
|
3767
3765
|
}
|
|
3768
|
-
|
|
3769
3766
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3770
3767
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3771
3768
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
@@ -3810,29 +3807,25 @@
|
|
|
3810
3807
|
margin-right: var(--spacing-sm, 0.75rem);
|
|
3811
3808
|
}
|
|
3812
3809
|
}
|
|
3810
|
+
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3811
|
+
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3812
|
+
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3813
|
+
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3813
3814
|
@layer kz-components {
|
|
3814
|
-
.MenuPopup-
|
|
3815
|
-
|
|
3815
|
+
.MenuPopup-module_menuPopup__UVgnP {
|
|
3816
|
+
position: absolute;
|
|
3816
3817
|
z-index: 1000;
|
|
3817
3818
|
box-sizing: border-box;
|
|
3818
|
-
background: var(--color-white);
|
|
3819
|
-
color: var(--color-purple-800);
|
|
3820
|
-
border-radius: var(--border-solid-border-radius);
|
|
3821
|
-
box-shadow: var(--shadow-large-box-shadow);
|
|
3822
|
-
padding: var(--spacing-
|
|
3823
|
-
margin-top: var(--spacing-
|
|
3819
|
+
background: var(--color-white, #ffffff);
|
|
3820
|
+
color: var(--color-purple-800, #2f2438);
|
|
3821
|
+
border-radius: var(--border-solid-border-radius, 7px);
|
|
3822
|
+
box-shadow: var(--shadow-large-box-shadow, 0 3px 9px 0 rgba(0, 0, 0, 0.1), 0 8px 40px 0 rgba(0, 0, 0, 0.08));
|
|
3823
|
+
padding: var(--spacing-sm, 0.75rem) 0;
|
|
3824
|
+
margin-top: var(--spacing-xs, 0.375rem);
|
|
3824
3825
|
text-align: start;
|
|
3825
|
-
width:
|
|
3826
|
-
max-height: var(--menu-container-height, 500px);
|
|
3827
|
-
}
|
|
3828
|
-
|
|
3829
|
-
.MenuPopup-module_menuPopup__QgGEa[popover]:popover-open {
|
|
3830
|
-
z-index: unset;
|
|
3831
|
-
margin: 0;
|
|
3832
|
-
inset: unset;
|
|
3826
|
+
width: 294px;
|
|
3833
3827
|
}
|
|
3834
3828
|
}
|
|
3835
|
-
|
|
3836
3829
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3837
3830
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3838
3831
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
@@ -5069,7 +5062,7 @@
|
|
|
5069
5062
|
align-items: center;
|
|
5070
5063
|
justify-content: center;
|
|
5071
5064
|
position: absolute;
|
|
5072
|
-
z-index:
|
|
5065
|
+
z-index: 1030;
|
|
5073
5066
|
background: var(--color-white);
|
|
5074
5067
|
inset-block: 0 1px;
|
|
5075
5068
|
width: 48px;
|
|
@@ -19,7 +19,7 @@ export type FilterMultiSelectProps = {
|
|
|
19
19
|
className?: string;
|
|
20
20
|
} & Omit<MenuPopupProps, 'children'> & Omit<MenuTriggerProviderProps, 'children'> & SelectionProps;
|
|
21
21
|
export declare const FilterMultiSelect: {
|
|
22
|
-
({ trigger, children, isOpen, defaultOpen, onOpenChange, isLoading, loadingSkeleton, label, items, selectedKeys, defaultSelectedKeys, onSelectionChange, selectionMode, onSearchInputChange, triggerRef, className,
|
|
22
|
+
({ trigger, children, isOpen, defaultOpen, onOpenChange, isLoading, loadingSkeleton, label, items, selectedKeys, defaultSelectedKeys, onSelectionChange, selectionMode, onSearchInputChange, triggerRef, className, }: FilterMultiSelectProps): JSX.Element;
|
|
23
23
|
displayName: string;
|
|
24
24
|
TriggerButton: {
|
|
25
25
|
({ selectedOptionLabels, label, classNameOverride, labelCharacterLimitBeforeTruncate, }: import("./subcomponents/Trigger").FilterTriggerButtonProps): JSX.Element;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { type UseFloatingOptions } from '@floating-ui/react-dom';
|
|
3
|
-
import { type OverrideClassName } from "../../../../types/OverrideClassName";
|
|
1
|
+
import React from 'react';
|
|
4
2
|
export type MenuPopupProps = {
|
|
5
|
-
children: React.ReactNode;
|
|
6
|
-
floatingOptions?: Partial<UseFloatingOptions>;
|
|
7
3
|
isLoading?: boolean;
|
|
8
4
|
loadingSkeleton?: React.ReactNode;
|
|
9
|
-
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
};
|
|
10
7
|
export declare const MenuPopup: {
|
|
11
|
-
({
|
|
8
|
+
({ isLoading, loadingSkeleton, children, }: MenuPopupProps): JSX.Element;
|
|
12
9
|
displayName: string;
|
|
13
10
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaizen/components",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-fix-tab-20250626012516",
|
|
4
4
|
"description": "Kaizen component library",
|
|
5
5
|
"author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
|
|
6
6
|
"homepage": "https://cultureamp.design",
|
package/src/Filter/FilterBar/subcomponents/FilterBarMultiSelect/FilterBarMultiSelect.spec.tsx
CHANGED
|
@@ -180,7 +180,6 @@ describe('<FilterBarMultiSelect />', () => {
|
|
|
180
180
|
})
|
|
181
181
|
|
|
182
182
|
await user.click(getByRole('option', { name: 'Fruit Jelly' }))
|
|
183
|
-
await user.keyboard('{Escape}')
|
|
184
183
|
await waitFor(() => {
|
|
185
184
|
expect(getByRole('button', { name: 'Toppings : Pearls, Fruit Jelly' })).toBeInTheDocument()
|
|
186
185
|
})
|
|
@@ -58,10 +58,9 @@ export const FilterMultiSelect = ({
|
|
|
58
58
|
onSearchInputChange,
|
|
59
59
|
triggerRef,
|
|
60
60
|
className,
|
|
61
|
-
floatingOptions,
|
|
62
61
|
}: FilterMultiSelectProps): JSX.Element => {
|
|
63
62
|
const menuTriggerProps = { isOpen, defaultOpen, onOpenChange, triggerRef }
|
|
64
|
-
const menuPopupProps = { isLoading, loadingSkeleton
|
|
63
|
+
const menuPopupProps = { isLoading, loadingSkeleton }
|
|
65
64
|
const disabledKeys: Selection = new Set(
|
|
66
65
|
items?.filter((item) => item.isDisabled === true).map((disabledItem) => disabledItem.value),
|
|
67
66
|
)
|
|
@@ -80,7 +79,7 @@ export const FilterMultiSelect = ({
|
|
|
80
79
|
<MenuTriggerProvider {...menuTriggerProps}>
|
|
81
80
|
<div className={className}>
|
|
82
81
|
<MenuTriggerConsumer>{trigger}</MenuTriggerConsumer>
|
|
83
|
-
<MenuPopup
|
|
82
|
+
<MenuPopup {...menuPopupProps}>
|
|
84
83
|
<SelectionProvider {...selectionProps}>
|
|
85
84
|
<SelectionConsumer>{children}</SelectionConsumer>
|
|
86
85
|
</SelectionProvider>
|
|
@@ -30,14 +30,6 @@ The FilterMultiSelect is a component relies heavily on consumer implemntation. I
|
|
|
30
30
|
|
|
31
31
|
<Canvas of={FilterMultiSelectStories.WithSectionHeaders} />
|
|
32
32
|
|
|
33
|
-
### With floatingOptions
|
|
34
|
-
|
|
35
|
-
You can also use the `floatingOptions` to leverage any of `Floating UI's` [configurable options](https://floating-ui.com/docs/usefloating). While in most cases the default behavior should satisfy most scenarios, the `middleware` for `autoplace` and `size` can be useful when there is limited screen space available.
|
|
36
|
-
|
|
37
|
-
The following example showcases how to use the [autoPlacement](https://floating-ui.com/docs/autoPlacement) and [size](https://floating-ui.com/docs/size) and spread the options in with the default values.
|
|
38
|
-
|
|
39
|
-
<Canvas of={FilterMultiSelectStories.WithFloatingOptions} />
|
|
40
|
-
|
|
41
33
|
### Async
|
|
42
34
|
|
|
43
35
|
The following is an example of how you may create an async FilterMultiSelect using `@tanstack/react-query`.
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
|
-
import { autoPlacement, offset, size } from '@floating-ui/react-dom'
|
|
3
2
|
import type { Selection } from '@react-types/shared'
|
|
4
3
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
5
4
|
import isChromatic from 'chromatic'
|
|
6
5
|
import { InlineNotification } from '~components/Notification'
|
|
7
6
|
import { TextField } from '~components/TextField'
|
|
8
7
|
import { FilterMultiSelect, getSelectedOptionLabels } from '..'
|
|
9
|
-
import { mockItems
|
|
8
|
+
import { mockItems } from './MockData'
|
|
10
9
|
|
|
11
10
|
const IS_CHROMATIC = isChromatic()
|
|
12
11
|
|
|
@@ -309,90 +308,3 @@ export const WithSectionNotification: Story = {
|
|
|
309
308
|
chromatic: { disable: false },
|
|
310
309
|
},
|
|
311
310
|
}
|
|
312
|
-
|
|
313
|
-
export const WithManyOptions: Story = {
|
|
314
|
-
...FilterMultiSelectTemplate,
|
|
315
|
-
name: 'With many options',
|
|
316
|
-
args: {
|
|
317
|
-
items: mockManyItems,
|
|
318
|
-
},
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const floatingOptionsSourceCode = `
|
|
322
|
-
import { autoPlacement, size, offset } from '@floating-ui/react-dom'
|
|
323
|
-
|
|
324
|
-
// ...source code
|
|
325
|
-
|
|
326
|
-
<FilterMultiSelect
|
|
327
|
-
{...args}
|
|
328
|
-
floatingOptions={{
|
|
329
|
-
...{
|
|
330
|
-
middleware: [
|
|
331
|
-
size({
|
|
332
|
-
apply({ availableHeight, elements }) {
|
|
333
|
-
Object.assign(elements.floating.style, {
|
|
334
|
-
maxHeight: Math.max(250, Math.min(availableHeight - 12, 500)) + "px",
|
|
335
|
-
})
|
|
336
|
-
},
|
|
337
|
-
}),
|
|
338
|
-
autoPlacement({
|
|
339
|
-
allowedPlacements: ['bottom-start', 'top-start'],
|
|
340
|
-
}),
|
|
341
|
-
offset(6),
|
|
342
|
-
],
|
|
343
|
-
},
|
|
344
|
-
}}
|
|
345
|
-
/>
|
|
346
|
-
`
|
|
347
|
-
|
|
348
|
-
export const WithFloatingOptions: Story = {
|
|
349
|
-
...FilterMultiSelectTemplate,
|
|
350
|
-
name: 'With floatingOptions',
|
|
351
|
-
args: {
|
|
352
|
-
floatingOptions: {
|
|
353
|
-
middleware: [
|
|
354
|
-
size({
|
|
355
|
-
apply({ availableHeight, elements }) {
|
|
356
|
-
Object.assign(elements.floating.style, {
|
|
357
|
-
maxHeight: Math.max(250, Math.min(availableHeight - 12, 500)) + 'px',
|
|
358
|
-
})
|
|
359
|
-
},
|
|
360
|
-
}),
|
|
361
|
-
autoPlacement({
|
|
362
|
-
allowedPlacements: ['bottom-start', 'top-start'],
|
|
363
|
-
}),
|
|
364
|
-
offset(6),
|
|
365
|
-
],
|
|
366
|
-
},
|
|
367
|
-
},
|
|
368
|
-
parameters: {
|
|
369
|
-
docs: { source: { code: floatingOptionsSourceCode } },
|
|
370
|
-
},
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
export const AboveIfAvailable: Story = {
|
|
374
|
-
...FilterMultiSelectTemplate,
|
|
375
|
-
...WithFloatingOptions,
|
|
376
|
-
name: 'With limited viewport and autoplacement above',
|
|
377
|
-
parameters: {
|
|
378
|
-
viewport: {
|
|
379
|
-
viewports: {
|
|
380
|
-
LimitedViewportAutoPlace: {
|
|
381
|
-
name: 'Limited vertical space',
|
|
382
|
-
styles: {
|
|
383
|
-
width: '1024px',
|
|
384
|
-
height: '500px',
|
|
385
|
-
},
|
|
386
|
-
},
|
|
387
|
-
},
|
|
388
|
-
defaultViewport: 'LimitedViewportAutoPlace',
|
|
389
|
-
},
|
|
390
|
-
},
|
|
391
|
-
decorators: [
|
|
392
|
-
(Story) => (
|
|
393
|
-
<div className="mt-[350px]">
|
|
394
|
-
<Story />
|
|
395
|
-
</div>
|
|
396
|
-
),
|
|
397
|
-
],
|
|
398
|
-
}
|
|
@@ -58,42 +58,3 @@ export const locationDemographicValues = [
|
|
|
58
58
|
label: 'London',
|
|
59
59
|
},
|
|
60
60
|
]
|
|
61
|
-
|
|
62
|
-
export const mockManyItems: ItemType[] = [
|
|
63
|
-
{ label: 'Front-End', value: 'id-fe', count: '1245' },
|
|
64
|
-
{ label: 'Back-End', value: 'id-be', count: '4', isDisabled: true },
|
|
65
|
-
{ label: 'SRE', value: 'id-sre', count: '4', isDisabled: true },
|
|
66
|
-
{ label: 'Dev-ops', value: 'id-devops' },
|
|
67
|
-
{ label: 'Others', value: 'id-others' },
|
|
68
|
-
{
|
|
69
|
-
label: 'Engineer-type-1 has a really really long label',
|
|
70
|
-
value: 'id-type-1',
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
label: 'Engineer-type-2 also has a really really long label',
|
|
74
|
-
value: 'id-type-2',
|
|
75
|
-
count: '156',
|
|
76
|
-
},
|
|
77
|
-
{ label: 'Engineer-type-3', value: 'id-type-3' },
|
|
78
|
-
{
|
|
79
|
-
label: 'Engineer-type-4',
|
|
80
|
-
value: 'id-type-4',
|
|
81
|
-
count: '4',
|
|
82
|
-
isDisabled: true,
|
|
83
|
-
},
|
|
84
|
-
{ label: 'Engineer-type-5', value: 'id-type-5' },
|
|
85
|
-
{ label: 'UI Designer', value: 'id-ui', count: '42' },
|
|
86
|
-
{ label: 'UX Researcher', value: 'id-ux', count: '15' },
|
|
87
|
-
{ label: 'Product Manager', value: 'id-pm', count: '28' },
|
|
88
|
-
{ label: 'Project Manager', value: 'id-project', count: '19', isDisabled: true },
|
|
89
|
-
{ label: 'Data Scientist', value: 'id-ds', count: '11' },
|
|
90
|
-
{ label: 'Machine Learning Engineer', value: 'id-ml', count: '7' },
|
|
91
|
-
{ label: 'QA Tester', value: 'id-qa', count: '22' },
|
|
92
|
-
{
|
|
93
|
-
label: 'Technical Writer with documentation expertise',
|
|
94
|
-
value: 'id-tech-writer',
|
|
95
|
-
count: '5',
|
|
96
|
-
},
|
|
97
|
-
{ label: 'DevSecOps Engineer', value: 'id-devsecops', count: '3', isDisabled: true },
|
|
98
|
-
{ label: 'Cloud Architect', value: 'id-cloud', count: '8' },
|
|
99
|
-
]
|
package/src/Filter/FilterMultiSelect/context/MenuTriggerProvider/MenuTriggerProvider.spec.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { render, screen, waitFor } from '@testing-library/react'
|
|
3
3
|
import userEvent from '@testing-library/user-event'
|
|
4
|
+
import { vi } from 'vitest'
|
|
4
5
|
import { FilterTriggerButton } from '~components/Filter/FilterMultiSelect/subcomponents/Trigger'
|
|
5
6
|
import { MenuPopup } from '../../subcomponents/MenuPopup'
|
|
6
7
|
import { MenuTriggerProvider, type MenuTriggerProviderProps } from './MenuTriggerProvider'
|
|
@@ -52,11 +53,15 @@ describe('<MenuTriggerProvider /> - Visual content', () => {
|
|
|
52
53
|
rerender(<MenuTriggerProviderWrapper isOpen={false} />)
|
|
53
54
|
expect(screen.queryByText('menu-content-mock')).not.toBeInTheDocument()
|
|
54
55
|
})
|
|
55
|
-
|
|
56
|
+
|
|
57
|
+
it('fires the onOpenChange callback when the trigger is interacted', async () => {
|
|
56
58
|
const onOpenChange = vi.fn()
|
|
57
59
|
render(<MenuTriggerProviderWrapper isOpen onOpenChange={onOpenChange} />)
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
const trigger = screen.getByRole('button', {
|
|
62
|
+
name: 'trigger-display-label-mock',
|
|
63
|
+
})
|
|
64
|
+
await user.click(trigger)
|
|
60
65
|
|
|
61
66
|
await waitFor(() => {
|
|
62
67
|
expect(onOpenChange).toBeCalledTimes(1)
|
|
@@ -81,6 +86,17 @@ describe('<MenuTriggerProvider /> - Mouse interaction', () => {
|
|
|
81
86
|
})
|
|
82
87
|
|
|
83
88
|
describe('Given the menu is opened', () => {
|
|
89
|
+
it('is closed when user clicks on the trigger', async () => {
|
|
90
|
+
render(<MenuTriggerProviderWrapper defaultOpen />)
|
|
91
|
+
const trigger = screen.getByRole('button', {
|
|
92
|
+
name: 'trigger-display-label-mock',
|
|
93
|
+
})
|
|
94
|
+
await user.click(trigger)
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(screen.queryByText('menu-content-mock')).not.toBeInTheDocument()
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
84
100
|
it('is closed when user clicks outside of the menu', async () => {
|
|
85
101
|
render(<MenuTriggerProviderWrapper defaultOpen />)
|
|
86
102
|
await user.click(document.body)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@import '~@kaizen/design-tokens/sass/spacing';
|
|
2
|
+
|
|
3
|
+
@layer kz-components {
|
|
4
|
+
.listBox {
|
|
5
|
+
list-style: none;
|
|
6
|
+
padding: $spacing-sm;
|
|
7
|
+
margin: 0 $spacing-sm 0 0;
|
|
8
|
+
display: grid;
|
|
9
|
+
max-height: 22rem;
|
|
10
|
+
overflow-y: auto;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.overflown {
|
|
14
|
+
padding-right: $spacing-sm;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.hidden {
|
|
18
|
+
display: none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// this is a div but remove styles briefly flickering to a bullet list as the sections are removed
|
|
22
|
+
.noResultsWrapper {
|
|
23
|
+
list-style: none;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -3,7 +3,7 @@ import { type Collection, type Key } from '@react-types/shared'
|
|
|
3
3
|
import classnames from 'classnames'
|
|
4
4
|
import { useSelectionContext } from '../../context/SelectionProvider'
|
|
5
5
|
import { type MultiSelectItem } from '../../types'
|
|
6
|
-
import styles from './ListBox.module.
|
|
6
|
+
import styles from './ListBox.module.scss'
|
|
7
7
|
|
|
8
8
|
export type ListBoxItems = {
|
|
9
9
|
selectedItems: MultiSelectItem[]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@import '~@kaizen/design-tokens/sass/spacing';
|
|
2
|
+
@import '~@kaizen/design-tokens/sass/shadow';
|
|
3
|
+
@import '~@kaizen/design-tokens/sass/border';
|
|
4
|
+
@import '~@kaizen/design-tokens/sass/color';
|
|
5
|
+
|
|
6
|
+
@layer kz-components {
|
|
7
|
+
// figma hard coded: https://www.figma.com/file/eZKEE5kXbEMY3lx84oz8iN/%E2%9D%A4%EF%B8%8F-UI-Kit%3A-Heart?node-id=22814%3A96966
|
|
8
|
+
$menu-container-width: 294px;
|
|
9
|
+
$menu-container-max-height: 312px;
|
|
10
|
+
|
|
11
|
+
.menuPopup {
|
|
12
|
+
position: absolute;
|
|
13
|
+
z-index: 1000; // from $ca-z-index-dropdown
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
background: $color-white;
|
|
16
|
+
color: $color-purple-800;
|
|
17
|
+
border-radius: $border-solid-border-radius;
|
|
18
|
+
box-shadow: $shadow-large-box-shadow;
|
|
19
|
+
padding: $spacing-sm 0;
|
|
20
|
+
margin-top: $spacing-xs;
|
|
21
|
+
text-align: start;
|
|
22
|
+
width: $menu-container-width;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,78 +1,58 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { FocusOn } from 'react-focus-on'
|
|
5
|
-
import { type OverrideClassName } from '~components/types/OverrideClassName'
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { FocusScope } from '@react-aria/focus'
|
|
3
|
+
import { DismissButton, useOverlay } from '@react-aria/overlays'
|
|
6
4
|
import { useMenuTriggerContext } from '../../context'
|
|
7
|
-
import styles from './MenuPopup.module.
|
|
5
|
+
import styles from './MenuPopup.module.scss'
|
|
8
6
|
|
|
9
7
|
export type MenuPopupProps = {
|
|
10
|
-
children: React.ReactNode
|
|
11
|
-
floatingOptions?: Partial<UseFloatingOptions>
|
|
12
8
|
isLoading?: boolean
|
|
13
9
|
loadingSkeleton?: React.ReactNode
|
|
14
|
-
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
}
|
|
15
12
|
|
|
16
13
|
export const MenuPopup = ({
|
|
17
|
-
children,
|
|
18
|
-
floatingOptions,
|
|
19
|
-
classNameOverride,
|
|
20
14
|
isLoading,
|
|
21
15
|
loadingSkeleton,
|
|
22
|
-
|
|
16
|
+
children,
|
|
23
17
|
}: MenuPopupProps): JSX.Element => {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
const { menuTriggerState } = useMenuTriggerContext()
|
|
19
|
+
|
|
20
|
+
const onClose = (): void => menuTriggerState.close()
|
|
21
|
+
|
|
22
|
+
// Handle events that should cause the menu to close,
|
|
23
|
+
// e.g. blur, clicking outside, or pressing the escape key.
|
|
24
|
+
const overlayRef = React.createRef<HTMLDivElement>()
|
|
25
|
+
const { overlayProps } = useOverlay(
|
|
26
|
+
{
|
|
27
|
+
onClose,
|
|
28
|
+
isOpen: menuTriggerState.isOpen,
|
|
29
|
+
isDismissable: true,
|
|
34
30
|
},
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
whileElementsMounted: autoUpdate,
|
|
38
|
-
...floatingOptions,
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const handleReturnFocus = (): void => {
|
|
42
|
-
requestAnimationFrame(() => {
|
|
43
|
-
buttonRef.current?.focus()
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
if (floatingElement && referenceElement) {
|
|
49
|
-
floatingElement.showPopover?.()
|
|
50
|
-
update()
|
|
51
|
-
}
|
|
52
|
-
}, [floatingElement, referenceElement, update])
|
|
31
|
+
overlayRef,
|
|
32
|
+
)
|
|
53
33
|
|
|
34
|
+
// Wrap in <FocusScope> so that focus is restored back to the trigger when the menu is closed
|
|
35
|
+
// and auto focus on the first focusable item after loading. (disable eslint no-autofocus error for it)
|
|
36
|
+
// In addition, add hidden <DismissButton> components at the start and end of the list
|
|
37
|
+
// to allow screen reader users to dismiss the popup easily.
|
|
54
38
|
return menuTriggerState.isOpen ? (
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
>
|
|
73
|
-
{isLoading && loadingSkeleton ? loadingSkeleton : children}
|
|
74
|
-
</div>
|
|
75
|
-
</FocusOn>
|
|
39
|
+
<div {...overlayProps} ref={overlayRef} className={styles.menuPopup}>
|
|
40
|
+
{isLoading && loadingSkeleton ? (
|
|
41
|
+
<>
|
|
42
|
+
<DismissButton onDismiss={onClose} />
|
|
43
|
+
{loadingSkeleton}
|
|
44
|
+
<DismissButton onDismiss={onClose} />
|
|
45
|
+
</>
|
|
46
|
+
) : (
|
|
47
|
+
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
48
|
+
<FocusScope contain autoFocus restoreFocus>
|
|
49
|
+
<DismissButton onDismiss={onClose} />
|
|
50
|
+
|
|
51
|
+
{children}
|
|
52
|
+
<DismissButton onDismiss={onClose} />
|
|
53
|
+
</FocusScope>
|
|
54
|
+
)}
|
|
55
|
+
</div>
|
|
76
56
|
) : (
|
|
77
57
|
<></>
|
|
78
58
|
)
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var styles = {
|
|
4
|
-
"listBox": "ListBox-module_listBox__HBScm",
|
|
5
|
-
"overflown": "ListBox-module_overflown__PdKED",
|
|
6
|
-
"hidden": "ListBox-module_hidden__mO-oL",
|
|
7
|
-
"noResultsWrapper": "ListBox-module_noResultsWrapper__RnMj0"
|
|
8
|
-
};
|
|
9
|
-
module.exports = styles;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
@layer kz-components {
|
|
2
|
-
.listBox {
|
|
3
|
-
list-style: none;
|
|
4
|
-
padding: var(--spacing-12);
|
|
5
|
-
margin: 0 var(--spacing-12) 0 0;
|
|
6
|
-
display: grid;
|
|
7
|
-
max-height: 22rem;
|
|
8
|
-
overflow-y: auto;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.overflown {
|
|
12
|
-
padding-right: var(--spacing-12);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.hidden {
|
|
16
|
-
display: none;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.noResultsWrapper {
|
|
20
|
-
list-style: none;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
@layer kz-components {
|
|
2
|
-
.menuPopup {
|
|
3
|
-
/* from $ca-z-index-dropdown */
|
|
4
|
-
z-index: 1000;
|
|
5
|
-
box-sizing: border-box;
|
|
6
|
-
background: var(--color-white);
|
|
7
|
-
color: var(--color-purple-800);
|
|
8
|
-
border-radius: var(--border-solid-border-radius);
|
|
9
|
-
box-shadow: var(--shadow-large-box-shadow);
|
|
10
|
-
padding: var(--spacing-6) 0;
|
|
11
|
-
margin-top: var(--spacing-6);
|
|
12
|
-
text-align: start;
|
|
13
|
-
width: var(--menu-container-width, 294px);
|
|
14
|
-
max-height: var(--menu-container-height, 500px);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.menuPopup[popover]:popover-open {
|
|
18
|
-
z-index: unset;
|
|
19
|
-
margin: 0;
|
|
20
|
-
inset: unset;
|
|
21
|
-
}
|
|
22
|
-
}
|