@kaizen/components 0.0.0-canary-fix-filter-select-jump-issue-useHasStableYPosition-20250120225815 → 0.0.0-canary-fix-filter-select-jump-issue-useHasStableYPosition-test-20250129223936
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/__rc__/Select/hooks/{useHasStableYPosition.cjs → useHasCalculatedListboxPosition.cjs} +15 -9
- package/dist/cjs/__rc__/Select/subcomponents/ListBox/ListBox.cjs +22 -9
- package/dist/esm/__rc__/Select/hooks/{useHasStableYPosition.mjs → useHasCalculatedListboxPosition.mjs} +15 -9
- package/dist/esm/__rc__/Select/subcomponents/ListBox/ListBox.mjs +22 -9
- package/dist/styles.css +8759 -8758
- package/dist/types/__rc__/Select/hooks/{useHasStableYPosition.d.ts → useHasCalculatedListboxPosition.d.ts} +1 -1
- package/package.json +1 -1
- package/src/Content/Content.module.scss +3 -2
- package/src/Filter/FilterDateRangePicker/_docs/FilterDateRangePicker.mdx +1 -1
- package/src/Filter/FilterMultiSelect/_docs/FilterMultiSelect.mdx +1 -1
- package/src/Filter/FilterSelect/_docs/FilterSelect.stories.tsx +24 -27
- package/src/__rc__/Select/Select.spec.tsx +14 -4
- package/src/__rc__/Select/hooks/{useHasStableYPosition.ts → useHasCalculatedListboxPosition.ts} +13 -7
- package/src/__rc__/Select/subcomponents/ListBox/ListBox.tsx +31 -10
|
@@ -6,10 +6,10 @@ var React = require('react');
|
|
|
6
6
|
* Due to the floating element's position starting as a negative value on render and then jumping to the correct position, this caused the focus to jump to the top of the page.
|
|
7
7
|
* This now polls to check if the element's position is stable by comparing the first and last position.
|
|
8
8
|
*/
|
|
9
|
-
var
|
|
9
|
+
var useHasCalculatedListboxPosition = function (ref) {
|
|
10
10
|
var _a = React.useState(false),
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
hasStablePosition = _a[0],
|
|
12
|
+
setHasStablePosition = _a[1];
|
|
13
13
|
var _b = React.useState(null),
|
|
14
14
|
lastYPosition = _b[0],
|
|
15
15
|
setLastYPosition = _b[1];
|
|
@@ -19,18 +19,24 @@ var useHasStableYPosition = function (ref) {
|
|
|
19
19
|
var y = ref.current.getBoundingClientRect().y;
|
|
20
20
|
if (lastYPosition === null) {
|
|
21
21
|
setLastYPosition(y);
|
|
22
|
-
} else if (y === lastYPosition) {
|
|
23
|
-
|
|
22
|
+
} else if (y === lastYPosition && y >= 0) {
|
|
23
|
+
setHasStablePosition(true);
|
|
24
24
|
} else {
|
|
25
25
|
setLastYPosition(y);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
|
-
var intervalId = setInterval(
|
|
29
|
+
var intervalId = setInterval(function () {
|
|
30
|
+
if (hasStablePosition) {
|
|
31
|
+
clearInterval(intervalId);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
checkPosition();
|
|
35
|
+
}, 1);
|
|
30
36
|
return function () {
|
|
31
37
|
return clearInterval(intervalId);
|
|
32
38
|
};
|
|
33
|
-
}, [ref, lastYPosition]);
|
|
34
|
-
return
|
|
39
|
+
}, [ref, lastYPosition, hasStablePosition]);
|
|
40
|
+
return hasStablePosition;
|
|
35
41
|
};
|
|
36
|
-
exports.
|
|
42
|
+
exports.useHasCalculatedListboxPosition = useHasCalculatedListboxPosition;
|
|
@@ -5,7 +5,7 @@ var React = require('react');
|
|
|
5
5
|
var listbox = require('@react-aria/listbox');
|
|
6
6
|
var classnames = require('classnames');
|
|
7
7
|
var SelectContext = require('../../context/SelectContext.cjs');
|
|
8
|
-
var
|
|
8
|
+
var useHasCalculatedListboxPosition = require('../../hooks/useHasCalculatedListboxPosition.cjs');
|
|
9
9
|
var ListBox_module = require('./ListBox.module.scss.cjs');
|
|
10
10
|
function _interopDefault(e) {
|
|
11
11
|
return e && e.__esModule ? e : {
|
|
@@ -15,17 +15,30 @@ function _interopDefault(e) {
|
|
|
15
15
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
16
16
|
var classnames__default = /*#__PURE__*/_interopDefault(classnames);
|
|
17
17
|
|
|
18
|
-
/**
|
|
18
|
+
/** determines is the first or last key passed in is a section. If not it will return the key, otherwise will return the first option key of that section */
|
|
19
|
+
var getOptionOrSectionKey = function (optionKey, state) {
|
|
20
|
+
var _a, _b;
|
|
21
|
+
if (!optionKey) return null;
|
|
22
|
+
var option = state.collection.getItem(optionKey);
|
|
23
|
+
var optionType = option === null || option === undefined ? undefined : option.type;
|
|
24
|
+
if (optionType === 'section') {
|
|
25
|
+
var sectionOptions = (_a = option === null || option === undefined ? undefined : option.value) === null || _a === undefined ? undefined : _a.options;
|
|
26
|
+
return sectionOptions ? (_b = Array.from(sectionOptions)[0]) === null || _b === undefined ? undefined : _b.value : null;
|
|
27
|
+
}
|
|
28
|
+
return optionKey;
|
|
29
|
+
};
|
|
30
|
+
/** A util to retrieve the key of the correct focusable option based of the focus strategy
|
|
19
31
|
* This is used to determine which element from the collection to focus to on open base on the keyboard event
|
|
20
32
|
* ie: UpArrow will set the focusStrategy to "last"
|
|
21
33
|
*/
|
|
22
34
|
var getOptionKeyFromCollection = function (state) {
|
|
23
35
|
if (state.selectedItem) {
|
|
24
36
|
return state.selectedItem.key;
|
|
25
|
-
} else if (state.focusStrategy === 'last') {
|
|
26
|
-
return state.collection.getLastKey();
|
|
27
37
|
}
|
|
28
|
-
|
|
38
|
+
if (state.focusStrategy === 'last') {
|
|
39
|
+
return getOptionOrSectionKey(state.collection.getLastKey(), state);
|
|
40
|
+
}
|
|
41
|
+
return getOptionOrSectionKey(state.collection.getFirstKey(), state);
|
|
29
42
|
};
|
|
30
43
|
/** This makes the use of query selector less brittle in instances where a failed selector is passed in
|
|
31
44
|
*/
|
|
@@ -45,18 +58,18 @@ var ListBox = function (_a) {
|
|
|
45
58
|
restProps = tslib.__rest(_a, ["children", "menuProps", "classNameOverride"]);
|
|
46
59
|
var state = SelectContext.useSelectContext().state;
|
|
47
60
|
var ref = React.useRef(null);
|
|
48
|
-
var
|
|
61
|
+
var hasCalculatedListboxPosition = useHasCalculatedListboxPosition.useHasCalculatedListboxPosition(ref);
|
|
49
62
|
var listBoxProps = listbox.useListBox(tslib.__assign(tslib.__assign({}, menuProps), {
|
|
50
63
|
disallowEmptySelection: true,
|
|
51
64
|
// This is to ensure that the listbox doesn't use React Aria's auto focus feature for Listbox, which creates a visual bug
|
|
52
65
|
autoFocus: false
|
|
53
66
|
}), state, ref).listBoxProps;
|
|
54
67
|
/**
|
|
55
|
-
*
|
|
68
|
+
* When the Listbox is opened the initial position starts above the window, which can cause the out of the box behaviour in react-aria's listbox to jump a user to the top of the page.
|
|
56
69
|
*/
|
|
57
70
|
React.useEffect(function () {
|
|
58
71
|
var _a;
|
|
59
|
-
if (
|
|
72
|
+
if (hasCalculatedListboxPosition) {
|
|
60
73
|
var optionKey = getOptionKeyFromCollection(state);
|
|
61
74
|
var focusToElement = safeQuerySelector("[data-key='".concat(optionKey, "']"));
|
|
62
75
|
if (focusToElement) {
|
|
@@ -67,7 +80,7 @@ var ListBox = function (_a) {
|
|
|
67
80
|
}
|
|
68
81
|
// Only run this effect for checking the first successful render
|
|
69
82
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
|
-
}, [
|
|
83
|
+
}, [hasCalculatedListboxPosition]);
|
|
71
84
|
return React__default.default.createElement("ul", tslib.__assign({
|
|
72
85
|
ref: ref,
|
|
73
86
|
className: classnames__default.default(ListBox_module.listBox, classNameOverride)
|
|
@@ -4,10 +4,10 @@ import { useState, useEffect } from 'react';
|
|
|
4
4
|
* Due to the floating element's position starting as a negative value on render and then jumping to the correct position, this caused the focus to jump to the top of the page.
|
|
5
5
|
* This now polls to check if the element's position is stable by comparing the first and last position.
|
|
6
6
|
*/
|
|
7
|
-
var
|
|
7
|
+
var useHasCalculatedListboxPosition = function (ref) {
|
|
8
8
|
var _a = useState(false),
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
hasStablePosition = _a[0],
|
|
10
|
+
setHasStablePosition = _a[1];
|
|
11
11
|
var _b = useState(null),
|
|
12
12
|
lastYPosition = _b[0],
|
|
13
13
|
setLastYPosition = _b[1];
|
|
@@ -17,18 +17,24 @@ var useHasStableYPosition = function (ref) {
|
|
|
17
17
|
var y = ref.current.getBoundingClientRect().y;
|
|
18
18
|
if (lastYPosition === null) {
|
|
19
19
|
setLastYPosition(y);
|
|
20
|
-
} else if (y === lastYPosition) {
|
|
21
|
-
|
|
20
|
+
} else if (y === lastYPosition && y >= 0) {
|
|
21
|
+
setHasStablePosition(true);
|
|
22
22
|
} else {
|
|
23
23
|
setLastYPosition(y);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
-
var intervalId = setInterval(
|
|
27
|
+
var intervalId = setInterval(function () {
|
|
28
|
+
if (hasStablePosition) {
|
|
29
|
+
clearInterval(intervalId);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
checkPosition();
|
|
33
|
+
}, 1);
|
|
28
34
|
return function () {
|
|
29
35
|
return clearInterval(intervalId);
|
|
30
36
|
};
|
|
31
|
-
}, [ref, lastYPosition]);
|
|
32
|
-
return
|
|
37
|
+
}, [ref, lastYPosition, hasStablePosition]);
|
|
38
|
+
return hasStablePosition;
|
|
33
39
|
};
|
|
34
|
-
export {
|
|
40
|
+
export { useHasCalculatedListboxPosition };
|
|
@@ -3,20 +3,33 @@ import React, { useRef, useEffect } from 'react';
|
|
|
3
3
|
import { useListBox } from '@react-aria/listbox';
|
|
4
4
|
import classnames from 'classnames';
|
|
5
5
|
import { useSelectContext } from '../../context/SelectContext.mjs';
|
|
6
|
-
import {
|
|
6
|
+
import { useHasCalculatedListboxPosition } from '../../hooks/useHasCalculatedListboxPosition.mjs';
|
|
7
7
|
import styles from './ListBox.module.scss.mjs';
|
|
8
8
|
|
|
9
|
-
/**
|
|
9
|
+
/** determines is the first or last key passed in is a section. If not it will return the key, otherwise will return the first option key of that section */
|
|
10
|
+
var getOptionOrSectionKey = function (optionKey, state) {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
if (!optionKey) return null;
|
|
13
|
+
var option = state.collection.getItem(optionKey);
|
|
14
|
+
var optionType = option === null || option === undefined ? undefined : option.type;
|
|
15
|
+
if (optionType === 'section') {
|
|
16
|
+
var sectionOptions = (_a = option === null || option === undefined ? undefined : option.value) === null || _a === undefined ? undefined : _a.options;
|
|
17
|
+
return sectionOptions ? (_b = Array.from(sectionOptions)[0]) === null || _b === undefined ? undefined : _b.value : null;
|
|
18
|
+
}
|
|
19
|
+
return optionKey;
|
|
20
|
+
};
|
|
21
|
+
/** A util to retrieve the key of the correct focusable option based of the focus strategy
|
|
10
22
|
* This is used to determine which element from the collection to focus to on open base on the keyboard event
|
|
11
23
|
* ie: UpArrow will set the focusStrategy to "last"
|
|
12
24
|
*/
|
|
13
25
|
var getOptionKeyFromCollection = function (state) {
|
|
14
26
|
if (state.selectedItem) {
|
|
15
27
|
return state.selectedItem.key;
|
|
16
|
-
} else if (state.focusStrategy === 'last') {
|
|
17
|
-
return state.collection.getLastKey();
|
|
18
28
|
}
|
|
19
|
-
|
|
29
|
+
if (state.focusStrategy === 'last') {
|
|
30
|
+
return getOptionOrSectionKey(state.collection.getLastKey(), state);
|
|
31
|
+
}
|
|
32
|
+
return getOptionOrSectionKey(state.collection.getFirstKey(), state);
|
|
20
33
|
};
|
|
21
34
|
/** This makes the use of query selector less brittle in instances where a failed selector is passed in
|
|
22
35
|
*/
|
|
@@ -37,18 +50,18 @@ const ListBox = /*#__PURE__*/function () {
|
|
|
37
50
|
restProps = __rest(_a, ["children", "menuProps", "classNameOverride"]);
|
|
38
51
|
var state = useSelectContext().state;
|
|
39
52
|
var ref = useRef(null);
|
|
40
|
-
var
|
|
53
|
+
var hasCalculatedListboxPosition = useHasCalculatedListboxPosition(ref);
|
|
41
54
|
var listBoxProps = useListBox(__assign(__assign({}, menuProps), {
|
|
42
55
|
disallowEmptySelection: true,
|
|
43
56
|
// This is to ensure that the listbox doesn't use React Aria's auto focus feature for Listbox, which creates a visual bug
|
|
44
57
|
autoFocus: false
|
|
45
58
|
}), state, ref).listBoxProps;
|
|
46
59
|
/**
|
|
47
|
-
*
|
|
60
|
+
* When the Listbox is opened the initial position starts above the window, which can cause the out of the box behaviour in react-aria's listbox to jump a user to the top of the page.
|
|
48
61
|
*/
|
|
49
62
|
useEffect(function () {
|
|
50
63
|
var _a;
|
|
51
|
-
if (
|
|
64
|
+
if (hasCalculatedListboxPosition) {
|
|
52
65
|
var optionKey = getOptionKeyFromCollection(state);
|
|
53
66
|
var focusToElement = safeQuerySelector("[data-key='".concat(optionKey, "']"));
|
|
54
67
|
if (focusToElement) {
|
|
@@ -59,7 +72,7 @@ const ListBox = /*#__PURE__*/function () {
|
|
|
59
72
|
}
|
|
60
73
|
// Only run this effect for checking the first successful render
|
|
61
74
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
62
|
-
}, [
|
|
75
|
+
}, [hasCalculatedListboxPosition]);
|
|
63
76
|
return /*#__PURE__*/React.createElement("ul", __assign({
|
|
64
77
|
ref: ref,
|
|
65
78
|
className: classnames(styles.listBox, classNameOverride)
|