@snack-uikit/list 0.29.7-preview-54496a2c.0 → 0.29.7-preview-c824da44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -33,6 +33,7 @@ const styles_module_scss_1 = __importDefault(require('../styles.module.css'));
|
|
|
33
33
|
const constants_1 = require("./constants");
|
|
34
34
|
const styles_module_scss_2 = __importDefault(require('./styles.module.css'));
|
|
35
35
|
exports.ListPrivate = (0, react_1.forwardRef)((_a, ref) => {
|
|
36
|
+
var _b;
|
|
36
37
|
var {
|
|
37
38
|
items,
|
|
38
39
|
pinTop,
|
|
@@ -78,7 +79,12 @@ exports.ListPrivate = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
78
79
|
const itemsJSX = (0, Items_1.useRenderItems)(items);
|
|
79
80
|
const itemsPinTopJSX = (0, Items_1.useRenderItems)(pinTop);
|
|
80
81
|
const itemsPinBottomJSX = (0, Items_1.useRenderItems)(pinBottom);
|
|
81
|
-
const
|
|
82
|
+
const [scrollState, setScrollState] = (0, react_1.useState)({
|
|
83
|
+
virtualizer: null,
|
|
84
|
+
browser: null,
|
|
85
|
+
measured: false
|
|
86
|
+
});
|
|
87
|
+
console.info('[DEBUG] ScrollState', scrollState);
|
|
82
88
|
const emptyStates = (0, helperComponents_1.useEmptyState)({
|
|
83
89
|
noDataState,
|
|
84
90
|
noResultsState,
|
|
@@ -119,38 +125,64 @@ exports.ListPrivate = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
119
125
|
});
|
|
120
126
|
const virtualItems = virtualizer.getVirtualItems();
|
|
121
127
|
(0, react_1.useEffect)(() => {
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
if (scrollState.measured) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
virtualizer.measure(); // TODO: перезамерять размер
|
|
132
|
+
setScrollState(prevState => Object.assign(Object.assign({}, prevState), {
|
|
133
|
+
measured: true
|
|
134
|
+
}));
|
|
135
|
+
}, [scrollState.measured, virtualizer]);
|
|
124
136
|
const isScrollToItemEnabled = scroll && scrollToSelectedItem && virtualized;
|
|
125
137
|
(0, react_1.useEffect)(() => {
|
|
126
138
|
var _a;
|
|
127
139
|
if (isScrollToItemEnabled) {
|
|
140
|
+
console.info('[DEBUG] selectedItemIndex', selectedItemIndex);
|
|
141
|
+
if (!scrollState.measured) {
|
|
142
|
+
console.info('[DEBUG] Not measured yet');
|
|
143
|
+
return; // Not measured yet
|
|
144
|
+
}
|
|
128
145
|
if (selectedItemIndex < 0 || !selectedItem) {
|
|
146
|
+
console.info('[DEBUG] Cannot scroll to non-existing item');
|
|
129
147
|
return; // Cannot scroll to non-existing item
|
|
130
148
|
}
|
|
131
|
-
if (
|
|
149
|
+
if (scrollState.virtualizer === selectedItemIndex) {
|
|
150
|
+
console.info('[DEBUG] No need to re-scroll to the same item during re-renders');
|
|
132
151
|
return; // No need to re-scroll to the same item during re-renders
|
|
133
152
|
}
|
|
134
153
|
if ((selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) && ((_a = innerScrollRef.current) === null || _a === void 0 ? void 0 : _a.contains(selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef.current))) {
|
|
154
|
+
console.info('[DEBUG] No need to scroll to manually clicked item currently present in DOM');
|
|
135
155
|
return; // No need to scroll to manually clicked item currently present in DOM
|
|
136
156
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
157
|
+
console.info('[DEBUG] SCROLLING BY VIRTUALIZER');
|
|
158
|
+
virtualizer.scrollToIndex(selectedItemIndex, {
|
|
159
|
+
align: 'center'
|
|
160
|
+
});
|
|
161
|
+
setScrollState(prevState => Object.assign(Object.assign({}, prevState), {
|
|
162
|
+
virtualizer: selectedItemIndex
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
}, [isScrollToItemEnabled, scrollState, selectedItem, selectedItemIndex, virtualizer]);
|
|
166
|
+
const isTargetPresentInDom = Boolean((_b = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) === null || _b === void 0 ? void 0 : _b.current);
|
|
167
|
+
(0, react_1.useEffect)(() => {
|
|
168
|
+
var _a, _b, _c;
|
|
169
|
+
if (scrollState.virtualizer === null) {
|
|
170
|
+
return; // Not scrolled by virtualizer yet, no need for additional scroll
|
|
171
|
+
}
|
|
172
|
+
if (!isTargetPresentInDom) {
|
|
173
|
+
return; // Target element is not present in DOM yet, additional scroll does not work without it
|
|
174
|
+
}
|
|
175
|
+
if (scrollState.virtualizer === scrollState.browser) {
|
|
176
|
+
return; // Virtualizer scroll has not been executed => no need for additional scroll
|
|
152
177
|
}
|
|
153
|
-
|
|
178
|
+
console.info('[DEBUG] SCROLLING BY BROWSER', (_a = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) === null || _a === void 0 ? void 0 : _a.current);
|
|
179
|
+
(_c = (_b = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) === null || _b === void 0 ? void 0 : _b.current) === null || _c === void 0 ? void 0 : _c.scrollIntoView({
|
|
180
|
+
block: 'center'
|
|
181
|
+
});
|
|
182
|
+
setScrollState(prevState => Object.assign(Object.assign({}, prevState), {
|
|
183
|
+
browser: selectedItemIndex
|
|
184
|
+
}));
|
|
185
|
+
}, [scrollState, selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef, isTargetPresentInDom, selectedItemIndex]);
|
|
154
186
|
const loadingJSX = (0, react_1.useMemo)(() => loading && (0, jsx_runtime_1.jsx)("div", {
|
|
155
187
|
role: 'spinbutton',
|
|
156
188
|
tabIndex: -1,
|
|
@@ -13,7 +13,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
13
13
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
14
14
|
import cn from 'classnames';
|
|
15
15
|
import mergeRefs from 'merge-refs';
|
|
16
|
-
import { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
16
|
+
import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
17
17
|
import { Spinner } from '@snack-uikit/loaders';
|
|
18
18
|
import { Scroll } from '@snack-uikit/scroll';
|
|
19
19
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
@@ -25,6 +25,7 @@ import commonStyles from '../styles.module.css';
|
|
|
25
25
|
import { ALL_SIZES } from './constants';
|
|
26
26
|
import styles from './styles.module.css';
|
|
27
27
|
export const ListPrivate = forwardRef((_a, ref) => {
|
|
28
|
+
var _b;
|
|
28
29
|
var { items, pinTop, pinBottom, onKeyDown, onBlur, onFocus, tabIndex, active, scroll, nested, search, searchItem, scrollRef, scrollContainerRef, onScroll, footer, loading, limitedScrollHeight, untouchableScrollbars, className, noDataState, noResultsState, errorDataState, dataError, dataFiltered, scrollToSelectedItem = false, virtualized = false, scrollContainerClassName, barHideStrategy = 'never' } = _a, props = __rest(_a, ["items", "pinTop", "pinBottom", "onKeyDown", "onBlur", "onFocus", "tabIndex", "active", "scroll", "nested", "search", "searchItem", "scrollRef", "scrollContainerRef", "onScroll", "footer", "loading", "limitedScrollHeight", "untouchableScrollbars", "className", "noDataState", "noResultsState", "errorDataState", "dataError", "dataFiltered", "scrollToSelectedItem", "virtualized", "scrollContainerClassName", "barHideStrategy"]);
|
|
29
30
|
const { size = 's', flattenItems, focusFlattenItems } = useNewListContext();
|
|
30
31
|
const { value, isSelectionSingle } = useSelectionContext();
|
|
@@ -32,7 +33,8 @@ export const ListPrivate = forwardRef((_a, ref) => {
|
|
|
32
33
|
const itemsJSX = useRenderItems(items);
|
|
33
34
|
const itemsPinTopJSX = useRenderItems(pinTop);
|
|
34
35
|
const itemsPinBottomJSX = useRenderItems(pinBottom);
|
|
35
|
-
const
|
|
36
|
+
const [scrollState, setScrollState] = useState({ virtualizer: null, browser: null, measured: false });
|
|
37
|
+
console.info('[DEBUG] ScrollState', scrollState);
|
|
36
38
|
const emptyStates = useEmptyState({ noDataState, noResultsState, errorDataState });
|
|
37
39
|
const hasNoItems = items.length === 0;
|
|
38
40
|
const { selectedItemIndex, selectedItem } = useMemo(() => {
|
|
@@ -66,34 +68,54 @@ export const ListPrivate = forwardRef((_a, ref) => {
|
|
|
66
68
|
});
|
|
67
69
|
const virtualItems = virtualizer.getVirtualItems();
|
|
68
70
|
useEffect(() => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
if (scrollState.measured) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
virtualizer.measure(); // TODO: перезамерять размер
|
|
75
|
+
setScrollState(prevState => (Object.assign(Object.assign({}, prevState), { measured: true })));
|
|
76
|
+
}, [scrollState.measured, virtualizer]);
|
|
71
77
|
const isScrollToItemEnabled = scroll && scrollToSelectedItem && virtualized;
|
|
72
78
|
useEffect(() => {
|
|
73
79
|
var _a;
|
|
74
80
|
if (isScrollToItemEnabled) {
|
|
81
|
+
console.info('[DEBUG] selectedItemIndex', selectedItemIndex);
|
|
82
|
+
if (!scrollState.measured) {
|
|
83
|
+
console.info('[DEBUG] Not measured yet');
|
|
84
|
+
return; // Not measured yet
|
|
85
|
+
}
|
|
75
86
|
if (selectedItemIndex < 0 || !selectedItem) {
|
|
87
|
+
console.info('[DEBUG] Cannot scroll to non-existing item');
|
|
76
88
|
return; // Cannot scroll to non-existing item
|
|
77
89
|
}
|
|
78
|
-
if (
|
|
90
|
+
if (scrollState.virtualizer === selectedItemIndex) {
|
|
91
|
+
console.info('[DEBUG] No need to re-scroll to the same item during re-renders');
|
|
79
92
|
return; // No need to re-scroll to the same item during re-renders
|
|
80
93
|
}
|
|
81
94
|
if ((selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) && ((_a = innerScrollRef.current) === null || _a === void 0 ? void 0 : _a.contains(selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef.current))) {
|
|
95
|
+
console.info('[DEBUG] No need to scroll to manually clicked item currently present in DOM');
|
|
82
96
|
return; // No need to scroll to manually clicked item currently present in DOM
|
|
83
97
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
console.info('[DEBUG] SCROLLING BY VIRTUALIZER');
|
|
99
|
+
virtualizer.scrollToIndex(selectedItemIndex, { align: 'center' });
|
|
100
|
+
setScrollState(prevState => (Object.assign(Object.assign({}, prevState), { virtualizer: selectedItemIndex })));
|
|
101
|
+
}
|
|
102
|
+
}, [isScrollToItemEnabled, scrollState, selectedItem, selectedItemIndex, virtualizer]);
|
|
103
|
+
const isTargetPresentInDom = Boolean((_b = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) === null || _b === void 0 ? void 0 : _b.current);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
var _a, _b, _c;
|
|
106
|
+
if (scrollState.virtualizer === null) {
|
|
107
|
+
return; // Not scrolled by virtualizer yet, no need for additional scroll
|
|
108
|
+
}
|
|
109
|
+
if (!isTargetPresentInDom) {
|
|
110
|
+
return; // Target element is not present in DOM yet, additional scroll does not work without it
|
|
111
|
+
}
|
|
112
|
+
if (scrollState.virtualizer === scrollState.browser) {
|
|
113
|
+
return; // Virtualizer scroll has not been executed => no need for additional scroll
|
|
95
114
|
}
|
|
96
|
-
|
|
115
|
+
console.info('[DEBUG] SCROLLING BY BROWSER', (_a = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) === null || _a === void 0 ? void 0 : _a.current);
|
|
116
|
+
(_c = (_b = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) === null || _b === void 0 ? void 0 : _b.current) === null || _c === void 0 ? void 0 : _c.scrollIntoView({ block: 'center' });
|
|
117
|
+
setScrollState(prevState => (Object.assign(Object.assign({}, prevState), { browser: selectedItemIndex })));
|
|
118
|
+
}, [scrollState, selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef, isTargetPresentInDom, selectedItemIndex]);
|
|
97
119
|
const loadingJSX = useMemo(() => loading && (_jsx("div", { role: 'spinbutton', tabIndex: -1, className: styles.loader, "data-size": size, "data-no-items": hasNoItems || undefined, "data-test-id": 'list__loader', children: _jsx(Spinner, { size: size === 'l' ? 's' : 'xs' }) })), [hasNoItems, loading, size]);
|
|
98
120
|
const content = useMemo(() => (_jsxs(_Fragment, { children: [virtualized ? (_jsx("div", { className: styles.virtualizedContainer, style: { height: virtualizer.getTotalSize() }, tabIndex: -1, children: virtualItems.map(virtualRow => (_jsx("div", { "data-index": virtualRow.index, ref: virtualizer.measureElement, tabIndex: -1, className: styles.virtualizedPositionBox, style: {
|
|
99
121
|
transform: `translateY(${virtualRow.start}px)`,
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "List",
|
|
7
|
-
"version": "0.29.7-preview-
|
|
7
|
+
"version": "0.29.7-preview-c824da44.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@snack-uikit/locale": "*"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "edea7e461de9f4f112e73ed1de8c1063240d3164"
|
|
58
58
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
2
2
|
import cn from 'classnames';
|
|
3
3
|
import mergeRefs from 'merge-refs';
|
|
4
|
-
import { ForwardedRef, forwardRef, RefObject, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
4
|
+
import { ForwardedRef, forwardRef, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
5
5
|
|
|
6
6
|
import { Spinner } from '@snack-uikit/loaders';
|
|
7
7
|
import { Scroll } from '@snack-uikit/scroll';
|
|
@@ -16,6 +16,12 @@ import { ListPrivateProps } from '../types';
|
|
|
16
16
|
import { ALL_SIZES } from './constants';
|
|
17
17
|
import styles from './styles.module.scss';
|
|
18
18
|
|
|
19
|
+
type ScrollState = {
|
|
20
|
+
virtualizer: number | null;
|
|
21
|
+
browser: number | null;
|
|
22
|
+
measured: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
19
25
|
export const ListPrivate = forwardRef(
|
|
20
26
|
(
|
|
21
27
|
{
|
|
@@ -60,7 +66,8 @@ export const ListPrivate = forwardRef(
|
|
|
60
66
|
const itemsPinTopJSX = useRenderItems(pinTop);
|
|
61
67
|
const itemsPinBottomJSX = useRenderItems(pinBottom);
|
|
62
68
|
|
|
63
|
-
const
|
|
69
|
+
const [scrollState, setScrollState] = useState<ScrollState>({ virtualizer: null, browser: null, measured: false });
|
|
70
|
+
console.info('[DEBUG] ScrollState', scrollState);
|
|
64
71
|
|
|
65
72
|
const emptyStates = useEmptyState({ noDataState, noResultsState, errorDataState });
|
|
66
73
|
const hasNoItems = items.length === 0;
|
|
@@ -102,36 +109,74 @@ export const ListPrivate = forwardRef(
|
|
|
102
109
|
const virtualItems = virtualizer.getVirtualItems();
|
|
103
110
|
|
|
104
111
|
useEffect(() => {
|
|
105
|
-
|
|
106
|
-
|
|
112
|
+
if (scrollState.measured) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
virtualizer.measure(); // TODO: перезамерять размер
|
|
117
|
+
|
|
118
|
+
setScrollState(prevState => ({
|
|
119
|
+
...prevState,
|
|
120
|
+
measured: true,
|
|
121
|
+
}));
|
|
122
|
+
}, [scrollState.measured, virtualizer]);
|
|
107
123
|
|
|
108
124
|
const isScrollToItemEnabled = scroll && scrollToSelectedItem && virtualized;
|
|
109
125
|
|
|
110
126
|
useEffect(() => {
|
|
111
127
|
if (isScrollToItemEnabled) {
|
|
128
|
+
console.info('[DEBUG] selectedItemIndex', selectedItemIndex);
|
|
129
|
+
if (!scrollState.measured) {
|
|
130
|
+
console.info('[DEBUG] Not measured yet');
|
|
131
|
+
return; // Not measured yet
|
|
132
|
+
}
|
|
112
133
|
if (selectedItemIndex < 0 || !selectedItem) {
|
|
134
|
+
console.info('[DEBUG] Cannot scroll to non-existing item');
|
|
113
135
|
return; // Cannot scroll to non-existing item
|
|
114
136
|
}
|
|
115
|
-
if (
|
|
137
|
+
if (scrollState.virtualizer === selectedItemIndex) {
|
|
138
|
+
console.info('[DEBUG] No need to re-scroll to the same item during re-renders');
|
|
116
139
|
return; // No need to re-scroll to the same item during re-renders
|
|
117
140
|
}
|
|
118
141
|
if (selectedItem?.itemRef && innerScrollRef.current?.contains(selectedItem?.itemRef.current)) {
|
|
142
|
+
console.info('[DEBUG] No need to scroll to manually clicked item currently present in DOM');
|
|
119
143
|
return; // No need to scroll to manually clicked item currently present in DOM
|
|
120
144
|
}
|
|
121
145
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
selectedItem.itemRef?.current?.scrollIntoView({ block: 'center' });
|
|
130
|
-
lastScrolledItemIndex.current = selectedItemIndex;
|
|
131
|
-
}, 0);
|
|
132
|
-
}, 0);
|
|
146
|
+
console.info('[DEBUG] SCROLLING BY VIRTUALIZER');
|
|
147
|
+
virtualizer.scrollToIndex(selectedItemIndex, { align: 'center' });
|
|
148
|
+
|
|
149
|
+
setScrollState(prevState => ({
|
|
150
|
+
...prevState,
|
|
151
|
+
virtualizer: selectedItemIndex,
|
|
152
|
+
}));
|
|
133
153
|
}
|
|
134
|
-
}, [isScrollToItemEnabled, selectedItem, selectedItemIndex, virtualizer]);
|
|
154
|
+
}, [isScrollToItemEnabled, scrollState, selectedItem, selectedItemIndex, virtualizer]);
|
|
155
|
+
|
|
156
|
+
const isTargetPresentInDom = Boolean(selectedItem?.itemRef?.current);
|
|
157
|
+
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
if (scrollState.virtualizer === null) {
|
|
160
|
+
return; // Not scrolled by virtualizer yet, no need for additional scroll
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!isTargetPresentInDom) {
|
|
164
|
+
return; // Target element is not present in DOM yet, additional scroll does not work without it
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (scrollState.virtualizer === scrollState.browser) {
|
|
168
|
+
return; // Virtualizer scroll has not been executed => no need for additional scroll
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.info('[DEBUG] SCROLLING BY BROWSER', selectedItem?.itemRef?.current);
|
|
172
|
+
|
|
173
|
+
selectedItem?.itemRef?.current?.scrollIntoView({ block: 'center' });
|
|
174
|
+
|
|
175
|
+
setScrollState(prevState => ({
|
|
176
|
+
...prevState,
|
|
177
|
+
browser: selectedItemIndex,
|
|
178
|
+
}));
|
|
179
|
+
}, [scrollState, selectedItem?.itemRef, isTargetPresentInDom, selectedItemIndex]);
|
|
135
180
|
|
|
136
181
|
const loadingJSX = useMemo(
|
|
137
182
|
() =>
|