@kaizen/components 0.0.0-canary-fix-filter-select-jump-issue-useHasStableYPosition-20250120225815 → 0.0.0-canary-test-1-20250201010717
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/Calendar/CalendarRange/CalendarRange.cjs +7 -4
- package/dist/cjs/Calendar/CalendarRange/CalendarRange.module.scss.cjs +1 -0
- package/dist/cjs/Filter/FilterDateRangePicker/FilterDateRangePicker.cjs +6 -1
- package/dist/cjs/Filter/FilterDateRangePicker/FilterDateRangePicker.module.css.cjs +6 -0
- package/dist/cjs/Filter/FilterDateRangePicker/subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.cjs +4 -1
- package/dist/cjs/__rc__/Select/subcomponents/ListBox/ListBox.cjs +6 -5
- package/dist/cjs/__utilities__/useIsClientReady/useIsClientReady.cjs +20 -0
- package/dist/esm/Calendar/CalendarRange/CalendarRange.mjs +7 -4
- package/dist/esm/Calendar/CalendarRange/CalendarRange.module.scss.mjs +1 -0
- package/dist/esm/Filter/FilterDateRangePicker/FilterDateRangePicker.mjs +5 -1
- package/dist/esm/Filter/FilterDateRangePicker/FilterDateRangePicker.module.css.mjs +4 -0
- package/dist/esm/Filter/FilterDateRangePicker/subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.mjs +4 -1
- package/dist/esm/__rc__/Select/subcomponents/ListBox/ListBox.mjs +6 -5
- package/dist/esm/__utilities__/useIsClientReady/useIsClientReady.mjs +18 -0
- package/dist/styles.css +15 -2
- package/dist/types/Calendar/CalendarRange/CalendarRange.d.ts +1 -1
- package/package.json +8 -1
- package/src/Calendar/CalendarRange/CalendarRange.module.scss +5 -0
- package/src/Calendar/CalendarRange/CalendarRange.tsx +3 -1
- package/src/Content/Content.module.scss +3 -2
- package/src/Filter/FilterDateRangePicker/FilterDateRangePicker.module.css +7 -0
- package/src/Filter/FilterDateRangePicker/FilterDateRangePicker.tsx +3 -1
- package/src/Filter/FilterDateRangePicker/_docs/FilterDateRangePicker.mdx +1 -1
- package/src/Filter/FilterDateRangePicker/_docs/FilterDateRangePicker.stories.tsx +36 -1
- package/src/Filter/FilterDateRangePicker/subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.tsx +5 -1
- package/src/Filter/FilterMultiSelect/_docs/FilterMultiSelect.mdx +1 -1
- package/src/Filter/FilterSelect/_docs/FilterSelect.stories.tsx +0 -45
- package/src/__rc__/Select/subcomponents/ListBox/ListBox.tsx +6 -5
- package/dist/cjs/__rc__/Select/hooks/useHasStableYPosition.cjs +0 -36
- package/dist/esm/__rc__/Select/hooks/useHasStableYPosition.mjs +0 -34
- package/dist/types/__rc__/Select/hooks/useHasStableYPosition.d.ts +0 -5
- package/src/__rc__/Select/hooks/useHasStableYPosition.ts +0 -31
|
@@ -24,9 +24,11 @@ var CalendarRange = function (_a) {
|
|
|
24
24
|
classNameOverride = _a.classNameOverride,
|
|
25
25
|
selected = _a.selected,
|
|
26
26
|
defaultMonth = _a.defaultMonth,
|
|
27
|
-
_d = _a.
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
_d = _a.numberOfMonths,
|
|
28
|
+
numberOfMonths = _d === undefined ? 2 : _d,
|
|
29
|
+
_e = _a.locale,
|
|
30
|
+
locale$1 = _e === undefined ? locale.enAU : _e,
|
|
31
|
+
restProps = tslib.__rest(_a, ["id", "onMount", "hasDivider", "classNameOverride", "selected", "defaultMonth", "numberOfMonths", "locale"]);
|
|
30
32
|
var calendarRef = React.useRef(null);
|
|
31
33
|
React.useEffect(function () {
|
|
32
34
|
if (calendarRef.current) onMount === null || onMount === undefined ? undefined : onMount(calendarRef.current);
|
|
@@ -37,6 +39,7 @@ var CalendarRange = function (_a) {
|
|
|
37
39
|
var classNames = tslib.__assign(tslib.__assign({}, baseCalendarClassNames.baseCalendarClassNames), {
|
|
38
40
|
month: hasDivider ? CalendarRange_module.monthWithDivider : CalendarRange_module.month,
|
|
39
41
|
caption_end: CalendarRange_module.captionEnd,
|
|
42
|
+
caption_start: CalendarRange_module.captionStart,
|
|
40
43
|
nav: CalendarRange_module.nav,
|
|
41
44
|
day_range_start: CalendarRange_module.dayRangeStart,
|
|
42
45
|
day_range_end: CalendarRange_module.dayRangeEnd,
|
|
@@ -68,7 +71,7 @@ var CalendarRange = function (_a) {
|
|
|
68
71
|
});
|
|
69
72
|
}
|
|
70
73
|
},
|
|
71
|
-
numberOfMonths:
|
|
74
|
+
numberOfMonths: numberOfMonths,
|
|
72
75
|
locale: locale$1
|
|
73
76
|
}, restProps)));
|
|
74
77
|
};
|
|
@@ -5,6 +5,7 @@ var styles = {
|
|
|
5
5
|
"monthWithDivider": "CalendarRange-module_monthWithDivider__JY-56",
|
|
6
6
|
"nav": "CalendarRange-module_nav__OtaVb",
|
|
7
7
|
"captionEnd": "CalendarRange-module_captionEnd__GSLQO",
|
|
8
|
+
"captionStart": "CalendarRange-module_captionStart__K5hlF",
|
|
8
9
|
"dayRangeStart": "CalendarRange-module_dayRangeStart__TwdDT",
|
|
9
10
|
"dayRangeEnd": "CalendarRange-module_dayRangeEnd__y6dEB",
|
|
10
11
|
"dayRangeMiddle": "CalendarRange-module_dayRangeMiddle__SybKY"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var tslib = require('tslib');
|
|
4
4
|
var React = require('react');
|
|
5
|
+
var classnames = require('classnames');
|
|
5
6
|
var getLocale = require('../../DatePicker/utils/getLocale.cjs');
|
|
6
7
|
var Filter = require('../Filter/Filter.cjs');
|
|
7
8
|
var FilterContents = require('../Filter/subcomponents/FilterContents/FilterContents.cjs');
|
|
@@ -9,12 +10,14 @@ var DateRangeDisplayLabel = require('./subcomponents/DateRangeDisplayLabel/DateR
|
|
|
9
10
|
var FilterDateRangePickerField = require('./subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.cjs');
|
|
10
11
|
var isValidRange = require('./subcomponents/FilterDateRangePickerField/utils/isValidRange.cjs');
|
|
11
12
|
var isCompleteDateRange = require('./utils/isCompleteDateRange.cjs');
|
|
13
|
+
var FilterDateRangePicker_module = require('./FilterDateRangePicker.module.css.cjs');
|
|
12
14
|
function _interopDefault(e) {
|
|
13
15
|
return e && e.__esModule ? e : {
|
|
14
16
|
default: e
|
|
15
17
|
};
|
|
16
18
|
}
|
|
17
19
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
20
|
+
var classnames__default = /*#__PURE__*/_interopDefault(classnames);
|
|
18
21
|
var FilterDateRangePicker = function (_a) {
|
|
19
22
|
var propsId = _a.id,
|
|
20
23
|
isOpen = _a.isOpen,
|
|
@@ -38,7 +41,9 @@ var FilterDateRangePicker = function (_a) {
|
|
|
38
41
|
label: label
|
|
39
42
|
}, triggerProps));
|
|
40
43
|
}
|
|
41
|
-
}, React__default.default.createElement(FilterContents.FilterContents,
|
|
44
|
+
}, React__default.default.createElement(FilterContents.FilterContents, {
|
|
45
|
+
classNameOverride: classnames__default.default(FilterDateRangePicker_module.filterDateRangePickerContents)
|
|
46
|
+
}, React__default.default.createElement(FilterDateRangePickerField.FilterDateRangePickerField, tslib.__assign({
|
|
42
47
|
id: "".concat(id, "--input"),
|
|
43
48
|
label: label,
|
|
44
49
|
locale: locale,
|
|
@@ -13,6 +13,7 @@ require('react-day-picker');
|
|
|
13
13
|
var parseDateFromTextFormatValue = require('../../../../Calendar/utils/parseDateFromTextFormatValue.cjs');
|
|
14
14
|
var getLocale = require('../../../../DatePicker/utils/getLocale.cjs');
|
|
15
15
|
var useDateInputHandlers = require('../../../FilterDatePicker/hooks/useDateInputHandlers.cjs');
|
|
16
|
+
var useMediaQueries = require('../../../../utils/useMediaQueries.cjs');
|
|
16
17
|
var DateRangeInputField = require('../DateRangeInputField/DateRangeInputField.cjs');
|
|
17
18
|
var filterDateRangePickerFieldReducer = require('./filterDateRangePickerFieldReducer.cjs');
|
|
18
19
|
var useEndDateValidation = require('./hooks/useEndDateValidation.cjs');
|
|
@@ -44,6 +45,7 @@ var FilterDateRangePickerField = function (_a) {
|
|
|
44
45
|
restProps = tslib.__rest(_a, ["id", "label", "locale", "defaultMonth", "selectedRange", "onRangeChange", "disabledDays", "inputStartDateProps", "inputEndDateProps", "description", "validationMessage", "onValidate", "classNameOverride"]);
|
|
45
46
|
var formatMessage = i18nReactIntl.useIntl().formatMessage;
|
|
46
47
|
var locale = getLocale.getLocale(propsLocale);
|
|
48
|
+
var queries = useMediaQueries.useMediaQueries().queries;
|
|
47
49
|
var translatedDateFrom = formatMessage({
|
|
48
50
|
id: 'filterDateRangePicker.dateFrom',
|
|
49
51
|
defaultMessage: 'Date from',
|
|
@@ -222,7 +224,7 @@ var FilterDateRangePickerField = function (_a) {
|
|
|
222
224
|
dateStart: dateStartValidation.validationMessage,
|
|
223
225
|
dateEnd: dateEndValidation.validationMessage
|
|
224
226
|
},
|
|
225
|
-
classNameOverride: FilterDateRangePickerField_module.dateRangeInputField
|
|
227
|
+
classNameOverride: classnames__default.default(FilterDateRangePickerField_module.dateRangeInputField)
|
|
226
228
|
}), React__default.default.createElement(CalendarRange.CalendarRange, {
|
|
227
229
|
disabled: disabledDays,
|
|
228
230
|
locale: locale,
|
|
@@ -232,6 +234,7 @@ var FilterDateRangePickerField = function (_a) {
|
|
|
232
234
|
},
|
|
233
235
|
onSelect: handleCalendarSelectRange,
|
|
234
236
|
month: state.startMonth,
|
|
237
|
+
numberOfMonths: queries.isSmall ? 1 : 2,
|
|
235
238
|
onMonthChange: function (value) {
|
|
236
239
|
return dispatch({
|
|
237
240
|
type: 'navigate_months',
|
|
@@ -4,8 +4,8 @@ var tslib = require('tslib');
|
|
|
4
4
|
var React = require('react');
|
|
5
5
|
var listbox = require('@react-aria/listbox');
|
|
6
6
|
var classnames = require('classnames');
|
|
7
|
+
var useIsClientReady = require('../../../../__utilities__/useIsClientReady/useIsClientReady.cjs');
|
|
7
8
|
var SelectContext = require('../../context/SelectContext.cjs');
|
|
8
|
-
var useHasStableYPosition = require('../../hooks/useHasStableYPosition.cjs');
|
|
9
9
|
var ListBox_module = require('./ListBox.module.scss.cjs');
|
|
10
10
|
function _interopDefault(e) {
|
|
11
11
|
return e && e.__esModule ? e : {
|
|
@@ -43,31 +43,32 @@ var ListBox = function (_a) {
|
|
|
43
43
|
menuProps = _a.menuProps,
|
|
44
44
|
classNameOverride = _a.classNameOverride,
|
|
45
45
|
restProps = tslib.__rest(_a, ["children", "menuProps", "classNameOverride"]);
|
|
46
|
+
var isClientReady = useIsClientReady.useIsClientReady();
|
|
46
47
|
var state = SelectContext.useSelectContext().state;
|
|
47
48
|
var ref = React.useRef(null);
|
|
48
|
-
var hasStableYPosition = useHasStableYPosition.useHasStableYPosition(ref);
|
|
49
49
|
var listBoxProps = listbox.useListBox(tslib.__assign(tslib.__assign({}, menuProps), {
|
|
50
50
|
disallowEmptySelection: true,
|
|
51
51
|
// This is to ensure that the listbox doesn't use React Aria's auto focus feature for Listbox, which creates a visual bug
|
|
52
52
|
autoFocus: false
|
|
53
53
|
}), state, ref).listBoxProps;
|
|
54
54
|
/**
|
|
55
|
-
* This uses the
|
|
55
|
+
* This uses the new useIsClientReady to ensure document exists before trying to querySelector and give the time to focus to the correct element
|
|
56
56
|
*/
|
|
57
57
|
React.useEffect(function () {
|
|
58
58
|
var _a;
|
|
59
|
-
if (
|
|
59
|
+
if (isClientReady) {
|
|
60
60
|
var optionKey = getOptionKeyFromCollection(state);
|
|
61
61
|
var focusToElement = safeQuerySelector("[data-key='".concat(optionKey, "']"));
|
|
62
62
|
if (focusToElement) {
|
|
63
63
|
focusToElement.focus();
|
|
64
64
|
} else {
|
|
65
|
+
// If an element is not found, focus on the listbox. This ensures the list can still be navigated to via keyboard if the keys do not align to the data attributes of the list items.
|
|
65
66
|
(_a = ref.current) === null || _a === undefined ? undefined : _a.focus();
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
// Only run this effect for checking the first successful render
|
|
69
70
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
|
-
}, [
|
|
71
|
+
}, [isClientReady]);
|
|
71
72
|
return React__default.default.createElement("ul", tslib.__assign({
|
|
72
73
|
ref: ref,
|
|
73
74
|
className: classnames__default.default(ListBox_module.listBox, classNameOverride)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A hook that returns a truthy value indicating if the code can be run on client side.
|
|
7
|
+
* This is a useful hook for determining if the `document` or `window` objects are available.
|
|
8
|
+
*/
|
|
9
|
+
var useIsClientReady = function () {
|
|
10
|
+
var _a = React.useState(false),
|
|
11
|
+
isClientReady = _a[0],
|
|
12
|
+
setIsClientReady = _a[1];
|
|
13
|
+
React.useEffect(function () {
|
|
14
|
+
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
15
|
+
setIsClientReady(true);
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
return isClientReady;
|
|
19
|
+
};
|
|
20
|
+
exports.useIsClientReady = useIsClientReady;
|
|
@@ -17,9 +17,11 @@ const CalendarRange = /*#__PURE__*/function () {
|
|
|
17
17
|
classNameOverride = _a.classNameOverride,
|
|
18
18
|
selected = _a.selected,
|
|
19
19
|
defaultMonth = _a.defaultMonth,
|
|
20
|
-
_d = _a.
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
_d = _a.numberOfMonths,
|
|
21
|
+
numberOfMonths = _d === undefined ? 2 : _d,
|
|
22
|
+
_e = _a.locale,
|
|
23
|
+
locale = _e === undefined ? enAU : _e,
|
|
24
|
+
restProps = __rest(_a, ["id", "onMount", "hasDivider", "classNameOverride", "selected", "defaultMonth", "numberOfMonths", "locale"]);
|
|
23
25
|
var calendarRef = useRef(null);
|
|
24
26
|
useEffect(function () {
|
|
25
27
|
if (calendarRef.current) onMount === null || onMount === undefined ? undefined : onMount(calendarRef.current);
|
|
@@ -30,6 +32,7 @@ const CalendarRange = /*#__PURE__*/function () {
|
|
|
30
32
|
var classNames = __assign(__assign({}, baseCalendarClassNames), {
|
|
31
33
|
month: hasDivider ? styles.monthWithDivider : styles.month,
|
|
32
34
|
caption_end: styles.captionEnd,
|
|
35
|
+
caption_start: styles.captionStart,
|
|
33
36
|
nav: styles.nav,
|
|
34
37
|
day_range_start: styles.dayRangeStart,
|
|
35
38
|
day_range_end: styles.dayRangeEnd,
|
|
@@ -61,7 +64,7 @@ const CalendarRange = /*#__PURE__*/function () {
|
|
|
61
64
|
});
|
|
62
65
|
}
|
|
63
66
|
},
|
|
64
|
-
numberOfMonths:
|
|
67
|
+
numberOfMonths: numberOfMonths,
|
|
65
68
|
locale: locale
|
|
66
69
|
}, restProps)));
|
|
67
70
|
};
|
|
@@ -3,6 +3,7 @@ var styles = {
|
|
|
3
3
|
"monthWithDivider": "CalendarRange-module_monthWithDivider__JY-56",
|
|
4
4
|
"nav": "CalendarRange-module_nav__OtaVb",
|
|
5
5
|
"captionEnd": "CalendarRange-module_captionEnd__GSLQO",
|
|
6
|
+
"captionStart": "CalendarRange-module_captionStart__K5hlF",
|
|
6
7
|
"dayRangeStart": "CalendarRange-module_dayRangeStart__TwdDT",
|
|
7
8
|
"dayRangeEnd": "CalendarRange-module_dayRangeEnd__y6dEB",
|
|
8
9
|
"dayRangeMiddle": "CalendarRange-module_dayRangeMiddle__SybKY"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __rest, __assign } from 'tslib';
|
|
2
2
|
import React, { useId } from 'react';
|
|
3
|
+
import classnames from 'classnames';
|
|
3
4
|
import { getLocale } from '../../DatePicker/utils/getLocale.mjs';
|
|
4
5
|
import { Filter } from '../Filter/Filter.mjs';
|
|
5
6
|
import { FilterContents } from '../Filter/subcomponents/FilterContents/FilterContents.mjs';
|
|
@@ -7,6 +8,7 @@ import { DateRangeDisplayLabel } from './subcomponents/DateRangeDisplayLabel/Dat
|
|
|
7
8
|
import { FilterDateRangePickerField } from './subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.mjs';
|
|
8
9
|
import { isValidRange } from './subcomponents/FilterDateRangePickerField/utils/isValidRange.mjs';
|
|
9
10
|
import { isCompleteDateRange } from './utils/isCompleteDateRange.mjs';
|
|
11
|
+
import styles from './FilterDateRangePicker.module.css.mjs';
|
|
10
12
|
const FilterDateRangePicker = /*#__PURE__*/function () {
|
|
11
13
|
const FilterDateRangePicker = function (_a) {
|
|
12
14
|
var propsId = _a.id,
|
|
@@ -31,7 +33,9 @@ const FilterDateRangePicker = /*#__PURE__*/function () {
|
|
|
31
33
|
label: label
|
|
32
34
|
}, triggerProps));
|
|
33
35
|
}
|
|
34
|
-
}, /*#__PURE__*/React.createElement(FilterContents,
|
|
36
|
+
}, /*#__PURE__*/React.createElement(FilterContents, {
|
|
37
|
+
classNameOverride: classnames(styles.filterDateRangePickerContents)
|
|
38
|
+
}, /*#__PURE__*/React.createElement(FilterDateRangePickerField, __assign({
|
|
35
39
|
id: "".concat(id, "--input"),
|
|
36
40
|
label: label,
|
|
37
41
|
locale: locale,
|
|
@@ -11,6 +11,7 @@ import 'react-day-picker';
|
|
|
11
11
|
import { parseDateFromTextFormatValue } from '../../../../Calendar/utils/parseDateFromTextFormatValue.mjs';
|
|
12
12
|
import { getLocale } from '../../../../DatePicker/utils/getLocale.mjs';
|
|
13
13
|
import { useDateInputHandlers } from '../../../FilterDatePicker/hooks/useDateInputHandlers.mjs';
|
|
14
|
+
import { useMediaQueries } from '../../../../utils/useMediaQueries.mjs';
|
|
14
15
|
import { DateRangeInputField } from '../DateRangeInputField/DateRangeInputField.mjs';
|
|
15
16
|
import { filterDatePickerFieldReducer } from './filterDateRangePickerFieldReducer.mjs';
|
|
16
17
|
import { useEndDateValidation } from './hooks/useEndDateValidation.mjs';
|
|
@@ -36,6 +37,7 @@ const FilterDateRangePickerField = /*#__PURE__*/function () {
|
|
|
36
37
|
restProps = __rest(_a, ["id", "label", "locale", "defaultMonth", "selectedRange", "onRangeChange", "disabledDays", "inputStartDateProps", "inputEndDateProps", "description", "validationMessage", "onValidate", "classNameOverride"]);
|
|
37
38
|
var formatMessage = useIntl().formatMessage;
|
|
38
39
|
var locale = getLocale(propsLocale);
|
|
40
|
+
var queries = useMediaQueries().queries;
|
|
39
41
|
var translatedDateFrom = formatMessage({
|
|
40
42
|
id: 'filterDateRangePicker.dateFrom',
|
|
41
43
|
defaultMessage: 'Date from',
|
|
@@ -214,7 +216,7 @@ const FilterDateRangePickerField = /*#__PURE__*/function () {
|
|
|
214
216
|
dateStart: dateStartValidation.validationMessage,
|
|
215
217
|
dateEnd: dateEndValidation.validationMessage
|
|
216
218
|
},
|
|
217
|
-
classNameOverride: styles.dateRangeInputField
|
|
219
|
+
classNameOverride: classnames(styles.dateRangeInputField)
|
|
218
220
|
}), /*#__PURE__*/React.createElement(CalendarRange, {
|
|
219
221
|
disabled: disabledDays,
|
|
220
222
|
locale: locale,
|
|
@@ -224,6 +226,7 @@ const FilterDateRangePickerField = /*#__PURE__*/function () {
|
|
|
224
226
|
},
|
|
225
227
|
onSelect: handleCalendarSelectRange,
|
|
226
228
|
month: state.startMonth,
|
|
229
|
+
numberOfMonths: queries.isSmall ? 1 : 2,
|
|
227
230
|
onMonthChange: function (value) {
|
|
228
231
|
return dispatch({
|
|
229
232
|
type: 'navigate_months',
|
|
@@ -2,8 +2,8 @@ import { __rest, __assign } from 'tslib';
|
|
|
2
2
|
import React, { useRef, useEffect } from 'react';
|
|
3
3
|
import { useListBox } from '@react-aria/listbox';
|
|
4
4
|
import classnames from 'classnames';
|
|
5
|
+
import { useIsClientReady } from '../../../../__utilities__/useIsClientReady/useIsClientReady.mjs';
|
|
5
6
|
import { useSelectContext } from '../../context/SelectContext.mjs';
|
|
6
|
-
import { useHasStableYPosition } from '../../hooks/useHasStableYPosition.mjs';
|
|
7
7
|
import styles from './ListBox.module.scss.mjs';
|
|
8
8
|
|
|
9
9
|
/** A util to retrieve the key of the correct focusable items based of the focus strategy
|
|
@@ -35,31 +35,32 @@ const ListBox = /*#__PURE__*/function () {
|
|
|
35
35
|
menuProps = _a.menuProps,
|
|
36
36
|
classNameOverride = _a.classNameOverride,
|
|
37
37
|
restProps = __rest(_a, ["children", "menuProps", "classNameOverride"]);
|
|
38
|
+
var isClientReady = useIsClientReady();
|
|
38
39
|
var state = useSelectContext().state;
|
|
39
40
|
var ref = useRef(null);
|
|
40
|
-
var hasStableYPosition = useHasStableYPosition(ref);
|
|
41
41
|
var listBoxProps = useListBox(__assign(__assign({}, menuProps), {
|
|
42
42
|
disallowEmptySelection: true,
|
|
43
43
|
// This is to ensure that the listbox doesn't use React Aria's auto focus feature for Listbox, which creates a visual bug
|
|
44
44
|
autoFocus: false
|
|
45
45
|
}), state, ref).listBoxProps;
|
|
46
46
|
/**
|
|
47
|
-
* This uses the
|
|
47
|
+
* This uses the new useIsClientReady to ensure document exists before trying to querySelector and give the time to focus to the correct element
|
|
48
48
|
*/
|
|
49
49
|
useEffect(function () {
|
|
50
50
|
var _a;
|
|
51
|
-
if (
|
|
51
|
+
if (isClientReady) {
|
|
52
52
|
var optionKey = getOptionKeyFromCollection(state);
|
|
53
53
|
var focusToElement = safeQuerySelector("[data-key='".concat(optionKey, "']"));
|
|
54
54
|
if (focusToElement) {
|
|
55
55
|
focusToElement.focus();
|
|
56
56
|
} else {
|
|
57
|
+
// If an element is not found, focus on the listbox. This ensures the list can still be navigated to via keyboard if the keys do not align to the data attributes of the list items.
|
|
57
58
|
(_a = ref.current) === null || _a === undefined ? undefined : _a.focus();
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
// Only run this effect for checking the first successful render
|
|
61
62
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
62
|
-
}, [
|
|
63
|
+
}, [isClientReady]);
|
|
63
64
|
return /*#__PURE__*/React.createElement("ul", __assign({
|
|
64
65
|
ref: ref,
|
|
65
66
|
className: classnames(styles.listBox, classNameOverride)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A hook that returns a truthy value indicating if the code can be run on client side.
|
|
5
|
+
* This is a useful hook for determining if the `document` or `window` objects are available.
|
|
6
|
+
*/
|
|
7
|
+
var useIsClientReady = function () {
|
|
8
|
+
var _a = useState(false),
|
|
9
|
+
isClientReady = _a[0],
|
|
10
|
+
setIsClientReady = _a[1];
|
|
11
|
+
useEffect(function () {
|
|
12
|
+
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
13
|
+
setIsClientReady(true);
|
|
14
|
+
}
|
|
15
|
+
}, []);
|
|
16
|
+
return isClientReady;
|
|
17
|
+
};
|
|
18
|
+
export { useIsClientReady };
|
package/dist/styles.css
CHANGED
|
@@ -1863,6 +1863,10 @@
|
|
|
1863
1863
|
.CalendarRange-module_captionEnd__GSLQO .CalendarRange-module_nav__OtaVb {
|
|
1864
1864
|
flex-direction: row-reverse;
|
|
1865
1865
|
}
|
|
1866
|
+
.CalendarRange-module_captionStart__K5hlF.CalendarRange-module_captionEnd__GSLQO .CalendarRange-module_nav__OtaVb {
|
|
1867
|
+
justify-content: space-between;
|
|
1868
|
+
flex-direction: row;
|
|
1869
|
+
}
|
|
1866
1870
|
|
|
1867
1871
|
.CalendarRange-module_dayRangeStart__TwdDT,
|
|
1868
1872
|
.CalendarRange-module_dayRangeEnd__y6dEB {
|
|
@@ -2390,12 +2394,13 @@
|
|
|
2390
2394
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
2391
2395
|
.Content-module_content__ZeTRs {
|
|
2392
2396
|
max-width: 1392px;
|
|
2393
|
-
|
|
2397
|
+
margin: 0 72px;
|
|
2394
2398
|
width: 100%;
|
|
2395
2399
|
}
|
|
2396
2400
|
@media (max-width: calc(1080px - 1px)) {
|
|
2397
2401
|
.Content-module_content__ZeTRs {
|
|
2398
|
-
|
|
2402
|
+
margin: 0 12px;
|
|
2403
|
+
width: calc(100% - 2 * 12px);
|
|
2399
2404
|
}
|
|
2400
2405
|
}
|
|
2401
2406
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
@@ -3710,6 +3715,14 @@ input[type=range].InputRange-module_ratingScaleRange__gI-rs::-ms-thumb:not(:disa
|
|
|
3710
3715
|
.FilterDateRangePickerField-module_dateRangeInputField__EEU-X {
|
|
3711
3716
|
margin-bottom: var(--spacing-24, 1.5rem);
|
|
3712
3717
|
}
|
|
3718
|
+
@media (width <= 320px) {
|
|
3719
|
+
.FilterDateRangePicker-module_filterDateRangePickerContents__P7eNa {
|
|
3720
|
+
padding: var(--spacing-16);
|
|
3721
|
+
max-width: 320px;
|
|
3722
|
+
box-sizing: border-box;
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
|
|
3713
3726
|
/** THIS IS AN AUTOGENERATED FILE **/
|
|
3714
3727
|
.ListBox-module_listBox__q95MO {
|
|
3715
3728
|
list-style: none;
|
|
@@ -7,6 +7,6 @@ export type CalendarRangeProps = {
|
|
|
7
7
|
hasDivider?: boolean;
|
|
8
8
|
} & OverrideClassName<Omit<DayPickerRangeProps, 'mode'>>;
|
|
9
9
|
export declare const CalendarRange: {
|
|
10
|
-
({ id, onMount, hasDivider, classNameOverride, selected, defaultMonth, locale, ...restProps }: CalendarRangeProps): JSX.Element;
|
|
10
|
+
({ id, onMount, hasDivider, classNameOverride, selected, defaultMonth, numberOfMonths, locale, ...restProps }: CalendarRangeProps): JSX.Element;
|
|
11
11
|
displayName: string;
|
|
12
12
|
};
|
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-test-1-20250201010717",
|
|
4
4
|
"description": "Kaizen component library",
|
|
5
5
|
"author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
|
|
6
6
|
"homepage": "https://cultureamp.design",
|
|
@@ -30,6 +30,13 @@
|
|
|
30
30
|
"sideEffects": [
|
|
31
31
|
"styles.css"
|
|
32
32
|
],
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"import": "./dist/esm/index.mjs",
|
|
36
|
+
"require": "./dist/cjs/index.cjs",
|
|
37
|
+
"types": "./dist/types/index.d.ts"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
33
40
|
"bin": {
|
|
34
41
|
"kaizen-codemod": "./bin/codemod.sh"
|
|
35
42
|
},
|
|
@@ -22,6 +22,7 @@ export const CalendarRange = ({
|
|
|
22
22
|
classNameOverride,
|
|
23
23
|
selected,
|
|
24
24
|
defaultMonth,
|
|
25
|
+
numberOfMonths = 2,
|
|
25
26
|
locale = enAU,
|
|
26
27
|
...restProps
|
|
27
28
|
}: CalendarRangeProps): JSX.Element => {
|
|
@@ -39,6 +40,7 @@ export const CalendarRange = ({
|
|
|
39
40
|
...baseCalendarClassNames,
|
|
40
41
|
month: hasDivider ? styles.monthWithDivider : styles.month,
|
|
41
42
|
caption_end: styles.captionEnd,
|
|
43
|
+
caption_start: styles.captionStart,
|
|
42
44
|
nav: styles.nav,
|
|
43
45
|
day_range_start: styles.dayRangeStart,
|
|
44
46
|
day_range_end: styles.dayRangeEnd,
|
|
@@ -57,7 +59,7 @@ export const CalendarRange = ({
|
|
|
57
59
|
IconRight: () => <Icon name="arrow_forward" isPresentational shouldMirrorInRTL />,
|
|
58
60
|
IconLeft: () => <Icon name="arrow_back" isPresentational shouldMirrorInRTL />,
|
|
59
61
|
}}
|
|
60
|
-
numberOfMonths={
|
|
62
|
+
numberOfMonths={numberOfMonths}
|
|
61
63
|
locale={locale}
|
|
62
64
|
{...restProps}
|
|
63
65
|
/>
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
.content {
|
|
5
5
|
max-width: $layout-content-max-width;
|
|
6
|
-
|
|
6
|
+
margin: 0 $layout-content-side-margin;
|
|
7
7
|
width: 100%;
|
|
8
8
|
|
|
9
9
|
@media (max-width: calc(#{$layout-breakpoints-large} - 1px)) {
|
|
10
|
-
|
|
10
|
+
margin: 0 $content-margin-width-on-medium-and-small;
|
|
11
|
+
width: calc(100% - 2 * #{$content-margin-width-on-medium-and-small});
|
|
11
12
|
}
|
|
12
13
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useId } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
2
3
|
import { getLocale } from '~components/DatePicker/utils/getLocale'
|
|
3
4
|
import { Filter, FilterContents, type FilterProps } from '~components/Filter/Filter'
|
|
4
5
|
import { type FilterButtonProps } from '../FilterButton'
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
} from './subcomponents/FilterDateRangePickerField'
|
|
10
11
|
import { isValidRange } from './subcomponents/FilterDateRangePickerField/utils/isValidRange'
|
|
11
12
|
import { isCompleteDateRange } from './utils/isCompleteDateRange'
|
|
13
|
+
import styles from './FilterDateRangePicker.module.css'
|
|
12
14
|
|
|
13
15
|
export type FilterDateRangePickerProps = {
|
|
14
16
|
id?: string
|
|
@@ -46,7 +48,7 @@ export const FilterDateRangePicker = ({
|
|
|
46
48
|
})
|
|
47
49
|
}
|
|
48
50
|
>
|
|
49
|
-
<FilterContents>
|
|
51
|
+
<FilterContents classNameOverride={classNames(styles.filterDateRangePickerContents)}>
|
|
50
52
|
<FilterDateRangePickerField
|
|
51
53
|
id={`${id}--input`}
|
|
52
54
|
label={label}
|
|
@@ -4,7 +4,7 @@ import * as FilterDRPStories from './FilterDateRangePicker.stories'
|
|
|
4
4
|
|
|
5
5
|
<Meta of={FilterDRPStories} />
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# FilterDateRangePicker
|
|
8
8
|
|
|
9
9
|
<ResourceLinks
|
|
10
10
|
sourceCode="https://github.com/cultureamp/kaizen-design-system/tree/main/packages/components/src/FilterDateRangePicker"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react'
|
|
2
2
|
import { type Meta, type StoryObj } from '@storybook/react'
|
|
3
|
-
import { fn } from '@storybook/test'
|
|
3
|
+
import { expect, fn, waitFor, within } from '@storybook/test'
|
|
4
4
|
import Highlight from 'react-highlight'
|
|
5
5
|
import { type DateRange } from '~components/Calendar'
|
|
6
6
|
import { defaultMonthControls } from '~components/Calendar/_docs/controls/defaultMonthControls'
|
|
@@ -428,3 +428,38 @@ export const Validation: Story = {
|
|
|
428
428
|
controls: { disable: true },
|
|
429
429
|
},
|
|
430
430
|
}
|
|
431
|
+
|
|
432
|
+
export const OnSmallViewport: Story = {
|
|
433
|
+
parameters: { viewport: { defaultViewport: 'mobile1' } },
|
|
434
|
+
...FilterDateRangePickerTemplate,
|
|
435
|
+
play: async ({ canvasElement, step }) => {
|
|
436
|
+
const canvas = within(canvasElement)
|
|
437
|
+
|
|
438
|
+
await step('initial render complete', async () => {
|
|
439
|
+
await waitFor(() => {
|
|
440
|
+
canvas.getByRole('button', {
|
|
441
|
+
name: 'Dates',
|
|
442
|
+
})
|
|
443
|
+
})
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
await step('Can open the date picker', async () => {
|
|
447
|
+
await waitFor(() => {
|
|
448
|
+
const button = canvas.getByRole('button', {
|
|
449
|
+
name: 'Dates',
|
|
450
|
+
})
|
|
451
|
+
button.click()
|
|
452
|
+
})
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
await step('Back and Forward arrow and both visible', async () => {
|
|
456
|
+
await waitFor(() => {
|
|
457
|
+
const prevMonth = canvas.getByLabelText('Go to previous month')
|
|
458
|
+
const nextMonth = canvas.getByLabelText('Go to next month')
|
|
459
|
+
|
|
460
|
+
expect(prevMonth).toBeVisible()
|
|
461
|
+
expect(nextMonth).toBeVisible()
|
|
462
|
+
})
|
|
463
|
+
})
|
|
464
|
+
},
|
|
465
|
+
}
|
|
@@ -15,6 +15,7 @@ import { type DateValidationResponse } from '~components/Filter/FilterDatePicker
|
|
|
15
15
|
import { useDateInputHandlers } from '~components/Filter/FilterDatePicker/hooks/useDateInputHandlers'
|
|
16
16
|
import { type DataAttributes } from '~components/types/DataAttributes'
|
|
17
17
|
import { type OverrideClassName } from '~components/types/OverrideClassName'
|
|
18
|
+
import { useMediaQueries } from '~components/utils/useMediaQueries'
|
|
18
19
|
import { DateRangeInputField, type DateRangeInputFieldProps } from '../DateRangeInputField'
|
|
19
20
|
import { filterDatePickerFieldReducer } from './filterDateRangePickerFieldReducer'
|
|
20
21
|
import { useEndDateValidation } from './hooks/useEndDateValidation'
|
|
@@ -84,6 +85,8 @@ export const FilterDateRangePickerField = ({
|
|
|
84
85
|
const { formatMessage } = useIntl()
|
|
85
86
|
const locale = getLocale(propsLocale)
|
|
86
87
|
|
|
88
|
+
const { queries } = useMediaQueries()
|
|
89
|
+
|
|
87
90
|
const translatedDateFrom = formatMessage({
|
|
88
91
|
id: 'filterDateRangePicker.dateFrom',
|
|
89
92
|
defaultMessage: 'Date from',
|
|
@@ -292,7 +295,7 @@ export const FilterDateRangePickerField = ({
|
|
|
292
295
|
dateStart: dateStartValidation.validationMessage,
|
|
293
296
|
dateEnd: dateEndValidation.validationMessage,
|
|
294
297
|
}}
|
|
295
|
-
classNameOverride={styles.dateRangeInputField}
|
|
298
|
+
classNameOverride={classnames(styles.dateRangeInputField)}
|
|
296
299
|
/>
|
|
297
300
|
<CalendarRange
|
|
298
301
|
disabled={disabledDays}
|
|
@@ -303,6 +306,7 @@ export const FilterDateRangePickerField = ({
|
|
|
303
306
|
}}
|
|
304
307
|
onSelect={handleCalendarSelectRange}
|
|
305
308
|
month={state.startMonth}
|
|
309
|
+
numberOfMonths={queries.isSmall ? 1 : 2}
|
|
306
310
|
onMonthChange={(value: Date) => dispatch({ type: 'navigate_months', date: value })}
|
|
307
311
|
/>
|
|
308
312
|
</div>
|
|
@@ -4,7 +4,7 @@ import * as FilterMultiSelectStories from './FilterMultiSelect.stories'
|
|
|
4
4
|
|
|
5
5
|
<Meta of={FilterMultiSelectStories} />
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# FilterMultiSelect
|
|
8
8
|
|
|
9
9
|
<ResourceLinks
|
|
10
10
|
sourceCode="https://github.com/cultureamp/kaizen-design-system/tree/main/packages/components/src/FilterMultiSelect"
|
|
@@ -100,48 +100,3 @@ export const AdditionalProperties: Story = {
|
|
|
100
100
|
},
|
|
101
101
|
name: 'Additional option properties',
|
|
102
102
|
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Extend the option type to have additional properties to use for rendering.
|
|
106
|
-
*/
|
|
107
|
-
export const TestPageWithFilterSelect: Story = {
|
|
108
|
-
render: (args) => {
|
|
109
|
-
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<div>
|
|
113
|
-
<div style={{ color: 'coral', display: 'block', height: '1500px' }}>Content</div>
|
|
114
|
-
<FilterSelect<SelectOption & { isFruit: boolean }>
|
|
115
|
-
{...args}
|
|
116
|
-
label="Custom"
|
|
117
|
-
isOpen={isOpen}
|
|
118
|
-
setIsOpen={setIsOpen}
|
|
119
|
-
items={[
|
|
120
|
-
{ label: 'Bubblegum', value: 'bubblegum', isFruit: false },
|
|
121
|
-
{ label: 'Strawberry', value: 'strawberry', isFruit: true },
|
|
122
|
-
{ label: 'Chocolate', value: 'chocolate', isFruit: false },
|
|
123
|
-
{ label: 'Apple', value: 'apple', isFruit: true },
|
|
124
|
-
{ label: 'Lemon', value: 'lemon', isFruit: true },
|
|
125
|
-
]}
|
|
126
|
-
>
|
|
127
|
-
{({ items }): JSX.Element[] =>
|
|
128
|
-
items.map((item) =>
|
|
129
|
-
item.type === 'item' ? (
|
|
130
|
-
<FilterSelect.Option
|
|
131
|
-
key={item.key}
|
|
132
|
-
item={{
|
|
133
|
-
...item,
|
|
134
|
-
rendered: item.value?.isFruit ? `${item.rendered} (Fruit)` : item.rendered,
|
|
135
|
-
}}
|
|
136
|
-
/>
|
|
137
|
-
) : (
|
|
138
|
-
<FilterSelect.ItemDefaultRender key={item.key} item={item} />
|
|
139
|
-
),
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
</FilterSelect>
|
|
143
|
-
</div>
|
|
144
|
-
)
|
|
145
|
-
},
|
|
146
|
-
name: 'Additional option properties',
|
|
147
|
-
}
|
|
@@ -2,9 +2,9 @@ import React, { useEffect, useRef, type HTMLAttributes, type Key, type ReactNode
|
|
|
2
2
|
import { useListBox, type AriaListBoxOptions } from '@react-aria/listbox'
|
|
3
3
|
import { type SelectState } from '@react-stately/select'
|
|
4
4
|
import classnames from 'classnames'
|
|
5
|
+
import { useIsClientReady } from '~components/__utilities__/useIsClientReady'
|
|
5
6
|
import { type OverrideClassName } from '~components/types/OverrideClassName'
|
|
6
7
|
import { useSelectContext } from '../../context'
|
|
7
|
-
import { useHasStableYPosition } from '../../hooks/useHasStableYPosition'
|
|
8
8
|
import { type SelectItem, type SelectOption } from '../../types'
|
|
9
9
|
import styles from './ListBox.module.scss'
|
|
10
10
|
|
|
@@ -47,9 +47,9 @@ export const ListBox = <Option extends SelectOption>({
|
|
|
47
47
|
classNameOverride,
|
|
48
48
|
...restProps
|
|
49
49
|
}: SingleListBoxProps<Option>): JSX.Element => {
|
|
50
|
+
const isClientReady = useIsClientReady()
|
|
50
51
|
const { state } = useSelectContext<Option>()
|
|
51
52
|
const ref = useRef<HTMLUListElement>(null)
|
|
52
|
-
const hasStableYPosition = useHasStableYPosition(ref)
|
|
53
53
|
const { listBoxProps } = useListBox(
|
|
54
54
|
{
|
|
55
55
|
...menuProps,
|
|
@@ -62,22 +62,23 @@ export const ListBox = <Option extends SelectOption>({
|
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* This uses the
|
|
65
|
+
* This uses the new useIsClientReady to ensure document exists before trying to querySelector and give the time to focus to the correct element
|
|
66
66
|
*/
|
|
67
67
|
useEffect(() => {
|
|
68
|
-
if (
|
|
68
|
+
if (isClientReady) {
|
|
69
69
|
const optionKey = getOptionKeyFromCollection(state)
|
|
70
70
|
const focusToElement = safeQuerySelector(`[data-key='${optionKey}']`)
|
|
71
71
|
|
|
72
72
|
if (focusToElement) {
|
|
73
73
|
focusToElement.focus()
|
|
74
74
|
} else {
|
|
75
|
+
// If an element is not found, focus on the listbox. This ensures the list can still be navigated to via keyboard if the keys do not align to the data attributes of the list items.
|
|
75
76
|
ref.current?.focus()
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
// Only run this effect for checking the first successful render
|
|
79
80
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
80
|
-
}, [
|
|
81
|
+
}, [isClientReady])
|
|
81
82
|
|
|
82
83
|
return (
|
|
83
84
|
<ul
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var React = require('react');
|
|
4
|
-
|
|
5
|
-
/** This is a helper util to resolve the focus jumping issue with future Select and FilterSelect.
|
|
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
|
-
* This now polls to check if the element's position is stable by comparing the first and last position.
|
|
8
|
-
*/
|
|
9
|
-
var useHasStableYPosition = function (ref) {
|
|
10
|
-
var _a = React.useState(false),
|
|
11
|
-
isStable = _a[0],
|
|
12
|
-
setIsStable = _a[1];
|
|
13
|
-
var _b = React.useState(null),
|
|
14
|
-
lastYPosition = _b[0],
|
|
15
|
-
setLastYPosition = _b[1];
|
|
16
|
-
React.useEffect(function () {
|
|
17
|
-
var checkPosition = function () {
|
|
18
|
-
if (ref.current) {
|
|
19
|
-
var y = ref.current.getBoundingClientRect().y;
|
|
20
|
-
if (lastYPosition === null) {
|
|
21
|
-
setLastYPosition(y);
|
|
22
|
-
} else if (y === lastYPosition) {
|
|
23
|
-
setIsStable(true);
|
|
24
|
-
} else {
|
|
25
|
-
setLastYPosition(y);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var intervalId = setInterval(checkPosition, 1);
|
|
30
|
-
return function () {
|
|
31
|
-
return clearInterval(intervalId);
|
|
32
|
-
};
|
|
33
|
-
}, [ref, lastYPosition]);
|
|
34
|
-
return isStable;
|
|
35
|
-
};
|
|
36
|
-
exports.useHasStableYPosition = useHasStableYPosition;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
|
|
3
|
-
/** This is a helper util to resolve the focus jumping issue with future Select and FilterSelect.
|
|
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
|
-
* This now polls to check if the element's position is stable by comparing the first and last position.
|
|
6
|
-
*/
|
|
7
|
-
var useHasStableYPosition = function (ref) {
|
|
8
|
-
var _a = useState(false),
|
|
9
|
-
isStable = _a[0],
|
|
10
|
-
setIsStable = _a[1];
|
|
11
|
-
var _b = useState(null),
|
|
12
|
-
lastYPosition = _b[0],
|
|
13
|
-
setLastYPosition = _b[1];
|
|
14
|
-
useEffect(function () {
|
|
15
|
-
var checkPosition = function () {
|
|
16
|
-
if (ref.current) {
|
|
17
|
-
var y = ref.current.getBoundingClientRect().y;
|
|
18
|
-
if (lastYPosition === null) {
|
|
19
|
-
setLastYPosition(y);
|
|
20
|
-
} else if (y === lastYPosition) {
|
|
21
|
-
setIsStable(true);
|
|
22
|
-
} else {
|
|
23
|
-
setLastYPosition(y);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var intervalId = setInterval(checkPosition, 1);
|
|
28
|
-
return function () {
|
|
29
|
-
return clearInterval(intervalId);
|
|
30
|
-
};
|
|
31
|
-
}, [ref, lastYPosition]);
|
|
32
|
-
return isStable;
|
|
33
|
-
};
|
|
34
|
-
export { useHasStableYPosition };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/** This is a helper util to resolve the focus jumping issue with future Select and FilterSelect.
|
|
2
|
-
* 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.
|
|
3
|
-
* This now polls to check if the element's position is stable by comparing the first and last position.
|
|
4
|
-
*/
|
|
5
|
-
export declare const useHasStableYPosition: (ref: React.RefObject<HTMLElement>) => boolean;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
|
|
3
|
-
/** This is a helper util to resolve the focus jumping issue with future Select and FilterSelect.
|
|
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
|
-
* This now polls to check if the element's position is stable by comparing the first and last position.
|
|
6
|
-
*/
|
|
7
|
-
export const useHasStableYPosition = (ref: React.RefObject<HTMLElement>): boolean => {
|
|
8
|
-
const [isStable, setIsStable] = useState(false)
|
|
9
|
-
const [lastYPosition, setLastYPosition] = useState<number | null>(null)
|
|
10
|
-
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
const checkPosition = (): void => {
|
|
13
|
-
if (ref.current) {
|
|
14
|
-
const { y } = ref.current.getBoundingClientRect()
|
|
15
|
-
if (lastYPosition === null) {
|
|
16
|
-
setLastYPosition(y)
|
|
17
|
-
} else if (y === lastYPosition) {
|
|
18
|
-
setIsStable(true)
|
|
19
|
-
} else {
|
|
20
|
-
setLastYPosition(y)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const intervalId = setInterval(checkPosition, 1)
|
|
26
|
-
|
|
27
|
-
return () => clearInterval(intervalId)
|
|
28
|
-
}, [ref, lastYPosition])
|
|
29
|
-
|
|
30
|
-
return isStable
|
|
31
|
-
}
|