@noya-app/noya-designsystem 0.1.71 → 0.1.73
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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +17 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +58 -5
- package/dist/index.d.ts +58 -5
- package/dist/index.js +990 -780
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +970 -759
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -7
- package/src/components/BaseToolbar.tsx +1 -1
- package/src/components/Breadcrumbs.tsx +1 -0
- package/src/components/Collection.tsx +1 -2
- package/src/components/ComboboxMenu.tsx +1 -1
- package/src/components/Message.tsx +3 -2
- package/src/components/ScrollArea2.tsx +22 -2
- package/src/components/Virtualized.tsx +439 -0
- package/src/components/__tests__/Virtualized.math.test.ts +153 -0
- package/src/components/__tests__/Virtualized.test.tsx +85 -0
- package/src/components/listView/ListViewContexts.tsx +1 -6
- package/src/components/listView/ListViewRoot.tsx +18 -152
- package/src/index.tsx +5 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
buildMeasurements,
|
|
4
|
+
calculateScrollOffsetForIndex,
|
|
5
|
+
calculateVisibleRange,
|
|
6
|
+
clampGapValue,
|
|
7
|
+
findFirstVisibleIndex,
|
|
8
|
+
ItemMeasurement,
|
|
9
|
+
resolvePaddingValues,
|
|
10
|
+
} from "../Virtualized";
|
|
11
|
+
|
|
12
|
+
test("resolvePaddingValues handles numbers and objects", () => {
|
|
13
|
+
expect(resolvePaddingValues(8)).toEqual({ top: 8, bottom: 8 });
|
|
14
|
+
expect(resolvePaddingValues({ top: 4 })).toEqual({ top: 4, bottom: 0 });
|
|
15
|
+
expect(resolvePaddingValues(undefined)).toEqual({ top: 0, bottom: 0 });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("clampGapValue avoids negatives", () => {
|
|
19
|
+
expect(clampGapValue(undefined)).toBe(0);
|
|
20
|
+
expect(clampGapValue(-10)).toBe(0);
|
|
21
|
+
expect(clampGapValue(6)).toBe(6);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("buildMeasurements returns cumulative offsets and total height", () => {
|
|
25
|
+
const { measurements, totalHeight } = buildMeasurements({
|
|
26
|
+
itemCount: 3,
|
|
27
|
+
getItemHeight: (index) => 10 + index,
|
|
28
|
+
paddingTop: 5,
|
|
29
|
+
paddingBottom: 15,
|
|
30
|
+
gap: 4,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(measurements).toEqual([
|
|
34
|
+
{ index: 0, size: 10, start: 5, end: 15 },
|
|
35
|
+
{ index: 1, size: 11, start: 19, end: 30 },
|
|
36
|
+
{ index: 2, size: 12, start: 34, end: 46 },
|
|
37
|
+
]);
|
|
38
|
+
expect(totalHeight).toBe(61);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("findFirstVisibleIndex binary searches measurement offsets", () => {
|
|
42
|
+
const measurements = [
|
|
43
|
+
{ index: 0, size: 10, start: 0, end: 10 },
|
|
44
|
+
{ index: 1, size: 10, start: 10, end: 20 },
|
|
45
|
+
{ index: 2, size: 10, start: 20, end: 30 },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
expect(findFirstVisibleIndex(measurements, 0)).toBe(0);
|
|
49
|
+
expect(findFirstVisibleIndex(measurements, 5)).toBe(0);
|
|
50
|
+
expect(findFirstVisibleIndex(measurements, 10)).toBe(1);
|
|
51
|
+
expect(findFirstVisibleIndex(measurements, 25)).toBe(2);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("calculateVisibleRange respects overscan and height", () => {
|
|
55
|
+
const measurements = [
|
|
56
|
+
{ index: 0, size: 10, start: 0, end: 10 },
|
|
57
|
+
{ index: 1, size: 10, start: 10, end: 20 },
|
|
58
|
+
{ index: 2, size: 10, start: 20, end: 30 },
|
|
59
|
+
{ index: 3, size: 10, start: 30, end: 40 },
|
|
60
|
+
{ index: 4, size: 10, start: 40, end: 50 },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
const visible = calculateVisibleRange({
|
|
64
|
+
measurements,
|
|
65
|
+
scrollTop: 12,
|
|
66
|
+
height: 20,
|
|
67
|
+
overscan: 1,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(visible).toEqual({ start: 0, end: 4 });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const sampleMeasurements: ItemMeasurement[] = [
|
|
74
|
+
{ index: 0, size: 30, start: 0, end: 30 },
|
|
75
|
+
{ index: 1, size: 30, start: 30, end: 60 },
|
|
76
|
+
{ index: 2, size: 30, start: 60, end: 90 },
|
|
77
|
+
{ index: 3, size: 30, start: 90, end: 120 },
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const extendedMeasurements: ItemMeasurement[] = [
|
|
81
|
+
{ index: 0, size: 30, start: 0, end: 30 },
|
|
82
|
+
{ index: 1, size: 30, start: 30, end: 60 },
|
|
83
|
+
{ index: 2, size: 30, start: 60, end: 90 },
|
|
84
|
+
{ index: 3, size: 30, start: 90, end: 120 },
|
|
85
|
+
{ index: 4, size: 30, start: 120, end: 150 },
|
|
86
|
+
{ index: 5, size: 30, start: 150, end: 180 },
|
|
87
|
+
{ index: 6, size: 30, start: 180, end: 210 },
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
test("calculateScrollOffsetForIndex returns undefined when already visible", () => {
|
|
91
|
+
const offset = calculateScrollOffsetForIndex({
|
|
92
|
+
measurements: sampleMeasurements,
|
|
93
|
+
height: 60,
|
|
94
|
+
totalHeight: 120,
|
|
95
|
+
targetIndex: 1,
|
|
96
|
+
currentScrollTop: 30,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(offset).toBeUndefined();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("calculateScrollOffsetForIndex scrolls up when item above viewport", () => {
|
|
103
|
+
const offset = calculateScrollOffsetForIndex({
|
|
104
|
+
measurements: sampleMeasurements,
|
|
105
|
+
height: 60,
|
|
106
|
+
totalHeight: 120,
|
|
107
|
+
targetIndex: 0,
|
|
108
|
+
currentScrollTop: 50,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(offset).toBe(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("calculateScrollOffsetForIndex scrolls down when item below viewport", () => {
|
|
115
|
+
const offset = calculateScrollOffsetForIndex({
|
|
116
|
+
measurements: extendedMeasurements,
|
|
117
|
+
height: 60,
|
|
118
|
+
totalHeight: 210,
|
|
119
|
+
targetIndex: 4,
|
|
120
|
+
currentScrollTop: 0,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(offset).toBe(120);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("calculateScrollOffsetForIndex clamps to end of content", () => {
|
|
127
|
+
const offset = calculateScrollOffsetForIndex({
|
|
128
|
+
measurements: sampleMeasurements,
|
|
129
|
+
height: 80,
|
|
130
|
+
totalHeight: 120,
|
|
131
|
+
targetIndex: 3,
|
|
132
|
+
currentScrollTop: 10,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(offset).toBe(40);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("calculateScrollOffsetForIndex aligns bottom when item taller than viewport", () => {
|
|
139
|
+
const tallMeasurements: ItemMeasurement[] = [
|
|
140
|
+
{ index: 0, size: 120, start: 0, end: 120 },
|
|
141
|
+
{ index: 1, size: 120, start: 120, end: 240 },
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
const offset = calculateScrollOffsetForIndex({
|
|
145
|
+
measurements: tallMeasurements,
|
|
146
|
+
height: 60,
|
|
147
|
+
totalHeight: 240,
|
|
148
|
+
targetIndex: 1,
|
|
149
|
+
currentScrollTop: 0,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(offset).toBe(180);
|
|
153
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { act, render } from "@testing-library/react";
|
|
2
|
+
import { expect, test } from "bun:test";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Virtualized } from "../Virtualized";
|
|
5
|
+
|
|
6
|
+
test("virtualized window updates visible rows when scrolling", () => {
|
|
7
|
+
const items = Array.from({ length: 100 }, (_, index) => `Row ${index + 1}`);
|
|
8
|
+
|
|
9
|
+
const { container, getByTestId, queryByTestId } = render(
|
|
10
|
+
<Virtualized
|
|
11
|
+
height={100}
|
|
12
|
+
itemCount={items.length}
|
|
13
|
+
getItemHeight={() => 20}
|
|
14
|
+
renderItem={(index) => (
|
|
15
|
+
<div data-testid={`row-${index}`}>{items[index]}</div>
|
|
16
|
+
)}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const scroller = container.firstChild as HTMLDivElement;
|
|
21
|
+
|
|
22
|
+
expect(getByTestId("row-0")).toBeTruthy();
|
|
23
|
+
|
|
24
|
+
act(() => {
|
|
25
|
+
scroller.scrollTop = 200;
|
|
26
|
+
scroller.dispatchEvent(new Event("scroll"));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(queryByTestId("row-0")).toBeNull();
|
|
30
|
+
expect(getByTestId("row-10")).toBeTruthy();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("accounts for padding and gap", () => {
|
|
34
|
+
const { container } = render(
|
|
35
|
+
<Virtualized
|
|
36
|
+
height={120}
|
|
37
|
+
itemCount={2}
|
|
38
|
+
getItemHeight={() => 20}
|
|
39
|
+
padding={{ top: 12, bottom: 8 }}
|
|
40
|
+
gap={6}
|
|
41
|
+
renderItem={(index) => <div>Row {index}</div>}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const scroller = container.firstChild as HTMLDivElement;
|
|
46
|
+
const inner = scroller.firstChild as HTMLDivElement;
|
|
47
|
+
const firstRow = inner.firstChild as HTMLDivElement;
|
|
48
|
+
const secondRow = firstRow.nextSibling as HTMLDivElement;
|
|
49
|
+
|
|
50
|
+
expect(inner.style.height).toBe("66px");
|
|
51
|
+
expect(firstRow.style.top).toBe("12px");
|
|
52
|
+
expect(secondRow.style.top).toBe("38px");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("supports ScrollArea as the scroller", () => {
|
|
56
|
+
const items = Array.from({ length: 50 }, (_, index) => `Row ${index + 1}`);
|
|
57
|
+
|
|
58
|
+
const { container, getByTestId, queryByTestId } = render(
|
|
59
|
+
<Virtualized
|
|
60
|
+
height={120}
|
|
61
|
+
itemCount={items.length}
|
|
62
|
+
getItemHeight={() => 20}
|
|
63
|
+
useScrollArea
|
|
64
|
+
scrollAreaViewportClassName="virtualized-scrollarea-viewport"
|
|
65
|
+
renderItem={(index) => (
|
|
66
|
+
<div data-testid={`scroll-row-${index}`}>{items[index]}</div>
|
|
67
|
+
)}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const viewport = container.querySelector(
|
|
72
|
+
".virtualized-scrollarea-viewport"
|
|
73
|
+
) as HTMLDivElement;
|
|
74
|
+
|
|
75
|
+
expect(viewport).toBeTruthy();
|
|
76
|
+
expect(getByTestId("scroll-row-0")).toBeTruthy();
|
|
77
|
+
|
|
78
|
+
act(() => {
|
|
79
|
+
viewport.scrollTop = 200;
|
|
80
|
+
viewport.dispatchEvent(new Event("scroll"));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(queryByTestId("scroll-row-0")).toBeNull();
|
|
84
|
+
expect(getByTestId("scroll-row-10")).toBeTruthy();
|
|
85
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { createContext
|
|
3
|
+
import { createContext } from "react";
|
|
4
4
|
import {
|
|
5
5
|
ListColorScheme,
|
|
6
6
|
ListRowMarginType,
|
|
@@ -61,8 +61,3 @@ export const ListRowContext = createContext<ListRowContextValue>({
|
|
|
61
61
|
isSectionHeader: false,
|
|
62
62
|
});
|
|
63
63
|
(ListRowContext as any).displayName = "ListRowContext";
|
|
64
|
-
|
|
65
|
-
export const RenderItemContext = createContext<(index: number) => ReactNode>(
|
|
66
|
-
() => null
|
|
67
|
-
);
|
|
68
|
-
(RenderItemContext as any).displayName = "RenderItemContext";
|
|
@@ -1,27 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { Size } from "@noya-app/noya-geometry";
|
|
4
3
|
import { range } from "@noya-app/noya-utils";
|
|
5
4
|
import { forwardRefGeneric, memoGeneric } from "@noya-app/react-utils";
|
|
6
5
|
import React, {
|
|
7
6
|
CSSProperties,
|
|
8
7
|
ForwardedRef,
|
|
9
8
|
isValidElement,
|
|
10
|
-
memo,
|
|
11
9
|
ReactElement,
|
|
12
10
|
ReactNode,
|
|
13
11
|
useCallback,
|
|
14
|
-
useContext,
|
|
15
|
-
useImperativeHandle,
|
|
16
|
-
useLayoutEffect,
|
|
17
12
|
useMemo,
|
|
18
|
-
useRef,
|
|
19
13
|
} from "react";
|
|
20
|
-
import { WindowScroller, WindowScrollerChildProps } from "react-virtualized";
|
|
21
|
-
import { ListChildComponentProps, VariableSizeList } from "react-window";
|
|
22
14
|
import { mergeConflictingClassNames } from "../../utils/classNames";
|
|
23
15
|
import { IVirtualizedList } from "../IVirtualizedList";
|
|
24
16
|
import { ScrollArea } from "../ScrollArea";
|
|
17
|
+
import { Virtualized } from "../Virtualized";
|
|
25
18
|
import { SharedDragProps } from "../sorting/DragRegistration";
|
|
26
19
|
import { Sortable } from "../sorting/Sortable";
|
|
27
20
|
import {
|
|
@@ -36,7 +29,6 @@ import {
|
|
|
36
29
|
ListViewContextValue,
|
|
37
30
|
ListViewDraggingContext,
|
|
38
31
|
ListViewDraggingContextValue,
|
|
39
|
-
RenderItemContext,
|
|
40
32
|
} from "./ListViewContexts";
|
|
41
33
|
import {
|
|
42
34
|
ListColorScheme,
|
|
@@ -56,129 +48,6 @@ export const SECTION_HEADER_LABEL_HEIGHT = 24;
|
|
|
56
48
|
// use a taller height.
|
|
57
49
|
export const TALL_ROW_HEIGHT = 50;
|
|
58
50
|
|
|
59
|
-
const VirtualizedListRow = memo(function VirtualizedListRow({
|
|
60
|
-
index,
|
|
61
|
-
style,
|
|
62
|
-
}: ListChildComponentProps) {
|
|
63
|
-
const renderItem = useContext(RenderItemContext);
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<div key={index} style={style}>
|
|
67
|
-
{renderItem(index)}
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
/* ----------------------------------------------------------------------------
|
|
73
|
-
* VirtualizedList
|
|
74
|
-
* ------------------------------------------------------------------------- */
|
|
75
|
-
|
|
76
|
-
interface VirtualizedListProps<T> {
|
|
77
|
-
size: Size;
|
|
78
|
-
scrollElement: HTMLDivElement;
|
|
79
|
-
items: T[];
|
|
80
|
-
getItemHeight: (index: number) => number;
|
|
81
|
-
keyExtractor: (index: number) => string;
|
|
82
|
-
renderItem: (index: number) => ReactNode;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const VirtualizedListInner = forwardRefGeneric(function VirtualizedListInner<T>(
|
|
86
|
-
{
|
|
87
|
-
size,
|
|
88
|
-
scrollElement,
|
|
89
|
-
items,
|
|
90
|
-
getItemHeight,
|
|
91
|
-
keyExtractor,
|
|
92
|
-
renderItem,
|
|
93
|
-
}: VirtualizedListProps<T>,
|
|
94
|
-
ref: ForwardedRef<IVirtualizedList>
|
|
95
|
-
) {
|
|
96
|
-
const listRef = useRef<VariableSizeList<T> | null>(null);
|
|
97
|
-
|
|
98
|
-
useImperativeHandle(ref, () => ({
|
|
99
|
-
scrollToIndex(index) {
|
|
100
|
-
listRef.current?.scrollToItem(index);
|
|
101
|
-
},
|
|
102
|
-
}));
|
|
103
|
-
|
|
104
|
-
useLayoutEffect(() => {
|
|
105
|
-
listRef.current?.resetAfterIndex(0);
|
|
106
|
-
}, [
|
|
107
|
-
// When items or the height resolver change, re-render the virtualized list
|
|
108
|
-
// since VariableSizeList caches sizes per index.
|
|
109
|
-
items,
|
|
110
|
-
getItemHeight,
|
|
111
|
-
]);
|
|
112
|
-
|
|
113
|
-
// Internally, react-virtualized updates these properties. We always want
|
|
114
|
-
// to use our custom scroll element, so we override them. It may update
|
|
115
|
-
// overflowX/Y individually in addition to `overflow`, so we include all 3.
|
|
116
|
-
const listStyle = useMemo(
|
|
117
|
-
(): CSSProperties => ({
|
|
118
|
-
overflowX: "initial",
|
|
119
|
-
overflowY: "initial",
|
|
120
|
-
overflow: "initial",
|
|
121
|
-
}),
|
|
122
|
-
[]
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<RenderItemContext.Provider value={renderItem}>
|
|
127
|
-
<WindowScroller
|
|
128
|
-
scrollElement={scrollElement}
|
|
129
|
-
style={useMemo(() => ({ flex: "1 1 auto" }), [])}
|
|
130
|
-
>
|
|
131
|
-
{useCallback(
|
|
132
|
-
({
|
|
133
|
-
registerChild,
|
|
134
|
-
onChildScroll,
|
|
135
|
-
scrollTop,
|
|
136
|
-
}: WindowScrollerChildProps & {
|
|
137
|
-
// Added when noya-designsystem moved to a separate package.
|
|
138
|
-
// I think this is a hack to get around the fact that react-virtualized
|
|
139
|
-
// doesn't update on scroll unless we force it to by changing ref.
|
|
140
|
-
// Either we're not using this the intended way or the types are wrong.
|
|
141
|
-
registerChild: (element: any) => void;
|
|
142
|
-
}) => (
|
|
143
|
-
<div ref={registerChild}>
|
|
144
|
-
<VariableSizeList<T>
|
|
145
|
-
ref={listRef}
|
|
146
|
-
// The list won't update on scroll unless we force it to by changing key
|
|
147
|
-
key={scrollTop}
|
|
148
|
-
style={listStyle}
|
|
149
|
-
itemKey={keyExtractor}
|
|
150
|
-
onScroll={({ scrollOffset }: { scrollOffset: number }) => {
|
|
151
|
-
onChildScroll({ scrollTop: scrollOffset });
|
|
152
|
-
}}
|
|
153
|
-
initialScrollOffset={scrollTop}
|
|
154
|
-
width={size.width}
|
|
155
|
-
height={size.height}
|
|
156
|
-
itemCount={items.length}
|
|
157
|
-
itemSize={getItemHeight}
|
|
158
|
-
estimatedItemSize={ROW_HEIGHT}
|
|
159
|
-
>
|
|
160
|
-
{VirtualizedListRow as any}
|
|
161
|
-
</VariableSizeList>
|
|
162
|
-
</div>
|
|
163
|
-
),
|
|
164
|
-
[
|
|
165
|
-
listStyle,
|
|
166
|
-
keyExtractor,
|
|
167
|
-
size.width,
|
|
168
|
-
size.height,
|
|
169
|
-
items.length,
|
|
170
|
-
getItemHeight,
|
|
171
|
-
]
|
|
172
|
-
)}
|
|
173
|
-
</WindowScroller>
|
|
174
|
-
</RenderItemContext.Provider>
|
|
175
|
-
);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
const VirtualizedList = memo(
|
|
179
|
-
VirtualizedListInner
|
|
180
|
-
) as typeof VirtualizedListInner;
|
|
181
|
-
|
|
182
51
|
/* ----------------------------------------------------------------------------
|
|
183
52
|
* Root
|
|
184
53
|
* ------------------------------------------------------------------------- */
|
|
@@ -198,7 +67,7 @@ export type ListViewRootProps<T> = {
|
|
|
198
67
|
* Additionally, the key extracted with `keyExtractor` must match the ListItem.Row `id`.
|
|
199
68
|
*/
|
|
200
69
|
sortable?: boolean;
|
|
201
|
-
virtualized?:
|
|
70
|
+
virtualized?: number;
|
|
202
71
|
|
|
203
72
|
id?: string;
|
|
204
73
|
className?: string;
|
|
@@ -432,9 +301,8 @@ export const ListViewRoot = memoGeneric(
|
|
|
432
301
|
children
|
|
433
302
|
);
|
|
434
303
|
|
|
435
|
-
const withScrollable = (
|
|
436
|
-
children
|
|
437
|
-
) => (scrollable ? <ScrollArea>{children}</ScrollArea> : children(null));
|
|
304
|
+
const withScrollable = (children: ReactNode) =>
|
|
305
|
+
scrollable ? <ScrollArea>{children}</ScrollArea> : children;
|
|
438
306
|
|
|
439
307
|
const getItemHeight = useCallback(
|
|
440
308
|
(index: number) => {
|
|
@@ -528,23 +396,21 @@ export const ListViewRoot = memoGeneric(
|
|
|
528
396
|
>
|
|
529
397
|
{data.length === 0 && renderEmptyState
|
|
530
398
|
? renderEmptyState()
|
|
531
|
-
:
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
/>
|
|
543
|
-
) : (
|
|
544
|
-
range(0, data.length).map(renderWrappedChild)
|
|
545
|
-
)
|
|
399
|
+
: virtualized != null
|
|
400
|
+
? withSortable(
|
|
401
|
+
<Virtualized
|
|
402
|
+
ref={forwardedRef}
|
|
403
|
+
height={virtualized}
|
|
404
|
+
itemCount={data.length}
|
|
405
|
+
getItemHeight={getItemHeight}
|
|
406
|
+
renderItem={renderWrappedChild}
|
|
407
|
+
itemKey={getKey}
|
|
408
|
+
useScrollArea={scrollable}
|
|
409
|
+
/>
|
|
546
410
|
)
|
|
547
|
-
|
|
411
|
+
: withScrollable(
|
|
412
|
+
withSortable(range(0, data.length).map(renderWrappedChild))
|
|
413
|
+
)}
|
|
548
414
|
</div>
|
|
549
415
|
</ListViewDraggingContext.Provider>
|
|
550
416
|
</ListViewContext.Provider>
|
package/src/index.tsx
CHANGED
|
@@ -85,6 +85,11 @@ export * from "./components/Tooltip";
|
|
|
85
85
|
export * from "./components/TreeView";
|
|
86
86
|
export * from "./components/UserPicker";
|
|
87
87
|
export * from "./components/UserPointer";
|
|
88
|
+
export {
|
|
89
|
+
Virtualized,
|
|
90
|
+
type VirtualizedProps,
|
|
91
|
+
type VirtualizedRenderItem,
|
|
92
|
+
} from "./components/Virtualized";
|
|
88
93
|
export * from "./components/workspace/types";
|
|
89
94
|
export * from "./components/workspace/WorkspaceLayout";
|
|
90
95
|
export * from "./components/workspace/WorkspaceSideContext";
|