@react-fabric/data 1.0.0-beta.9 → 1.0.1
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/{src/histogram/Histogram.module.css → css/_histogram.css} +16 -13
- package/css/styles.css +24 -0
- package/dist/cjs/checklist/CheckList.js +59 -33
- package/dist/cjs/histogram/Histogram.js +41 -26
- package/dist/cjs/hooks/useFilteredList.js +100 -17
- package/dist/cjs/hooks/usePagination.js +29 -8
- package/dist/cjs/hooks/useSelectableList.js +30 -5
- package/dist/cjs/i18n/{ar.json.js → ar/data.json.js} +8 -1
- package/dist/cjs/i18n/{en.json.js → en/data.json.js} +8 -1
- package/dist/cjs/i18n/index.js +4 -4
- package/dist/cjs/index.js +30 -0
- package/dist/cjs/json/JsonViewer.js +80 -43
- package/dist/cjs/pagination/Pagination.js +24 -15
- package/dist/cjs/table/AddColumn.js +5 -5
- package/dist/cjs/table/BodyCell.js +20 -13
- package/dist/cjs/table/BodyRow.js +41 -28
- package/dist/cjs/table/CheckboxCell.js +10 -9
- package/dist/cjs/table/ColumnFilters.js +100 -0
- package/dist/cjs/table/EmptyCell.js +4 -4
- package/dist/cjs/table/HeaderCell.js +79 -53
- package/dist/cjs/table/HtmlTable.js +84 -0
- package/dist/cjs/table/{Context.js → Provider.js} +8 -10
- package/dist/cjs/table/Table.js +99 -33
- package/dist/cjs/{tree/types.js → table/context.js} +9 -5
- package/dist/cjs/table/types.js +29 -0
- package/dist/cjs/table/useResizer.js +10 -10
- package/dist/cjs/table/useTableColumns.js +4 -4
- package/dist/cjs/table/useVirtualTable.js +129 -22
- package/dist/cjs/tree/TreeNode.js +66 -46
- package/dist/cjs/tree/TreePanel.js +60 -24
- package/dist/cjs/tree/useTree.js +212 -47
- package/dist/cjs/tree/utils.js +63 -34
- package/dist/cjs/utils/getColor.js +58 -0
- package/dist/cjs/virtual/Gallery.js +119 -61
- package/dist/cjs/virtual/List.js +116 -55
- package/dist/cjs/virtual/Scroller.js +16 -8
- package/dist/esm/checklist/CheckList.js +61 -35
- package/dist/esm/histogram/Histogram.js +43 -28
- package/dist/esm/hooks/useFilteredList.js +101 -18
- package/dist/esm/hooks/usePagination.js +29 -8
- package/dist/esm/hooks/useSelectableList.js +30 -5
- package/dist/esm/i18n/{ar.json.js → ar/data.json.js} +8 -2
- package/dist/esm/i18n/{en.json.js → en/data.json.js} +8 -2
- package/dist/esm/i18n/index.js +2 -2
- package/dist/esm/index.js +31 -0
- package/dist/esm/json/JsonViewer.js +82 -45
- package/dist/esm/pagination/Pagination.js +25 -16
- package/dist/esm/table/AddColumn.js +6 -6
- package/dist/esm/table/BodyCell.js +21 -14
- package/dist/esm/table/BodyRow.js +41 -28
- package/dist/esm/table/CheckboxCell.js +11 -10
- package/dist/esm/table/ColumnFilters.js +100 -0
- package/dist/esm/table/EmptyCell.js +4 -4
- package/dist/esm/table/HeaderCell.js +80 -54
- package/dist/esm/table/HtmlTable.js +84 -0
- package/dist/esm/table/{Context.js → Provider.js} +11 -12
- package/dist/esm/table/Table.js +100 -34
- package/dist/esm/{tree/types.js → table/context.js} +8 -4
- package/dist/esm/table/types.js +29 -0
- package/dist/esm/table/useResizer.js +10 -10
- package/dist/esm/table/useTableColumns.js +4 -4
- package/dist/esm/table/useVirtualTable.js +131 -24
- package/dist/esm/tree/TreeNode.js +69 -49
- package/dist/esm/tree/TreePanel.js +62 -26
- package/dist/esm/tree/useTree.js +215 -50
- package/dist/esm/tree/utils.js +64 -35
- package/dist/esm/utils/getColor.js +58 -0
- package/dist/esm/virtual/Gallery.js +121 -63
- package/dist/esm/virtual/List.js +118 -57
- package/dist/esm/virtual/Scroller.js +17 -9
- package/dist/types/checklist/CheckList.d.ts +25 -6
- package/dist/types/histogram/Histogram.d.ts +28 -6
- package/dist/types/hooks/useFilteredList.d.ts +62 -5
- package/dist/types/hooks/usePagination.d.ts +18 -2
- package/dist/types/hooks/useSelectableList.d.ts +24 -1
- package/dist/types/index.d.ts +27 -0
- package/dist/types/json/JsonViewer.d.ts +23 -3
- package/dist/types/pagination/Pagination.d.ts +8 -2
- package/dist/types/table/AddColumn.d.ts +2 -2
- package/dist/types/table/BodyCell.d.ts +2 -2
- package/dist/types/table/BodyRow.d.ts +9 -9
- package/dist/types/table/CheckboxCell.d.ts +3 -3
- package/dist/types/table/ColumnFilters.d.ts +12 -0
- package/dist/types/table/EmptyCell.d.ts +1 -1
- package/dist/types/table/HeaderCell.d.ts +1 -1
- package/dist/types/table/HtmlTable.d.ts +21 -0
- package/dist/types/table/Provider.d.ts +2 -0
- package/dist/types/table/Table.d.ts +10 -1
- package/dist/types/table/context.d.ts +7 -0
- package/dist/types/table/types.d.ts +52 -10
- package/dist/types/table/useResizer.d.ts +1 -1
- package/dist/types/table/useTableColumns.d.ts +1 -1
- package/dist/types/table/useVirtualTable.d.ts +31 -12
- package/dist/types/tree/TreeNode.d.ts +1 -1
- package/dist/types/tree/TreePanel.d.ts +36 -1
- package/dist/types/tree/types.d.ts +75 -28
- package/dist/types/tree/useTree.d.ts +8 -12
- package/dist/types/tree/utils.d.ts +15 -8
- package/dist/types/utils/getColor.d.ts +43 -0
- package/dist/types/virtual/Gallery.d.ts +37 -6
- package/dist/types/virtual/List.d.ts +38 -6
- package/dist/types/virtual/Scroller.d.ts +1 -1
- package/package.json +17 -19
- package/src/checklist/CheckList.tsx +68 -71
- package/src/histogram/Histogram.tsx +47 -48
- package/src/hooks/useFilteredList.tsx +111 -28
- package/src/hooks/usePagination.tsx +39 -39
- package/src/hooks/useSelectableList.ts +45 -33
- package/src/i18n/{ar.json → ar/data.json} +5 -0
- package/src/i18n/{en.json → en/data.json} +5 -0
- package/src/i18n/index.ts +2 -2
- package/src/index.ts +23 -17
- package/src/json/JsonViewer.tsx +89 -120
- package/src/pagination/Pagination.tsx +104 -105
- package/src/table/AddColumn.tsx +6 -15
- package/src/table/BodyCell.tsx +27 -36
- package/src/table/BodyRow.tsx +36 -59
- package/src/table/CheckboxCell.tsx +12 -15
- package/src/table/ColumnFilters.tsx +93 -0
- package/src/table/EmptyCell.tsx +5 -18
- package/src/table/HeaderCell.tsx +72 -53
- package/src/table/HtmlTable.tsx +106 -0
- package/src/table/{Context.tsx → Provider.tsx} +11 -28
- package/src/table/Table.tsx +98 -83
- package/src/table/context.ts +33 -0
- package/src/table/types.ts +53 -27
- package/src/table/useResizer.ts +5 -9
- package/src/table/useTableColumns.ts +4 -6
- package/src/table/useVirtualTable.ts +136 -37
- package/src/tree/TreeNode.tsx +91 -86
- package/src/tree/TreePanel.tsx +87 -51
- package/src/tree/types.ts +85 -46
- package/src/tree/useTree.ts +210 -65
- package/src/tree/utils.ts +81 -62
- package/src/utils/getColor.ts +55 -0
- package/src/virtual/Gallery.tsx +129 -120
- package/src/virtual/List.tsx +124 -91
- package/src/virtual/Scroller.tsx +25 -9
- package/dist/cjs/histogram/Histogram.module.css +0 -1
- package/dist/esm/histogram/Histogram.module.css +0 -1
- package/dist/types/table/Context.d.ts +0 -8
package/src/virtual/List.tsx
CHANGED
|
@@ -30,10 +30,9 @@
|
|
|
30
30
|
|
|
31
31
|
import { Skeleton, useDebounce } from "@react-fabric/core";
|
|
32
32
|
import { type TestProps } from "@react-fabric/core/dist/types/types";
|
|
33
|
-
import { debounce } from "@react-fabric/utilities";
|
|
33
|
+
import { cn, debounce } from "@react-fabric/utilities";
|
|
34
34
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
35
|
-
import
|
|
36
|
-
import memoizeOne from "memoize-one";
|
|
35
|
+
import memoize from "memoize-one";
|
|
37
36
|
import {
|
|
38
37
|
memo,
|
|
39
38
|
useCallback,
|
|
@@ -56,11 +55,7 @@ export interface VirtualListRef {
|
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
export interface VirtualListProps<T> extends TestProps {
|
|
59
|
-
children: (props: {
|
|
60
|
-
data: T;
|
|
61
|
-
index: number;
|
|
62
|
-
isLast: boolean;
|
|
63
|
-
}) => ReactElement;
|
|
58
|
+
children: (props: { item: T; index: number; isLast: boolean }) => ReactElement;
|
|
64
59
|
listRef?: Ref<VirtualListRef | undefined>;
|
|
65
60
|
/**
|
|
66
61
|
* default item height
|
|
@@ -74,6 +69,8 @@ export interface VirtualListProps<T> extends TestProps {
|
|
|
74
69
|
* full width list
|
|
75
70
|
*/
|
|
76
71
|
fullWidth?: boolean;
|
|
72
|
+
maxWidth?: string | number;
|
|
73
|
+
minWidth?: string | number;
|
|
77
74
|
/**
|
|
78
75
|
* padding
|
|
79
76
|
*/
|
|
@@ -86,6 +83,7 @@ export interface VirtualListProps<T> extends TestProps {
|
|
|
86
83
|
* data list
|
|
87
84
|
*/
|
|
88
85
|
items: T[];
|
|
86
|
+
total?: number;
|
|
89
87
|
initialScroll?: number;
|
|
90
88
|
/**
|
|
91
89
|
* loading state
|
|
@@ -98,19 +96,22 @@ export interface VirtualListProps<T> extends TestProps {
|
|
|
98
96
|
/**
|
|
99
97
|
* load more callback
|
|
100
98
|
*/
|
|
101
|
-
onLoadMore?: (
|
|
99
|
+
onLoadMore?: (lastIndex?: number) => void;
|
|
102
100
|
/**
|
|
103
101
|
* scroll handler
|
|
104
102
|
*/
|
|
105
103
|
onScroll?: (top: number) => void;
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
const createItemList =
|
|
106
|
+
const createItemList = memoize((items) => items as never);
|
|
109
107
|
|
|
110
|
-
const
|
|
108
|
+
const VirtualListComponent = <T extends AnyObject>({
|
|
111
109
|
items,
|
|
110
|
+
total = 0,
|
|
112
111
|
children,
|
|
113
112
|
fullWidth,
|
|
113
|
+
maxWidth,
|
|
114
|
+
minWidth,
|
|
114
115
|
padding = "md",
|
|
115
116
|
orientation = "vertical",
|
|
116
117
|
defaultHeight: height = 48,
|
|
@@ -124,18 +125,18 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
124
125
|
...aria
|
|
125
126
|
}: VirtualListProps<T>) => {
|
|
126
127
|
const count = useDeferredValue(items.length);
|
|
127
|
-
const extraSize = useMemo(() => (onLoadMore ?
|
|
128
|
+
const extraSize = useMemo(() => (onLoadMore ? 8 : 0), [onLoadMore]);
|
|
128
129
|
const itemList: Array<{
|
|
129
130
|
index: number;
|
|
130
|
-
|
|
131
|
+
item: T;
|
|
131
132
|
isLast: boolean;
|
|
132
133
|
isSticky: boolean;
|
|
133
134
|
}> = createItemList(
|
|
134
|
-
items.map((item:
|
|
135
|
+
items.map((item: T, index) => {
|
|
135
136
|
return {
|
|
136
|
-
index
|
|
137
|
-
|
|
138
|
-
isLast:
|
|
137
|
+
index,
|
|
138
|
+
item,
|
|
139
|
+
isLast: index + 1 === items.length,
|
|
139
140
|
};
|
|
140
141
|
}),
|
|
141
142
|
);
|
|
@@ -143,6 +144,7 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
143
144
|
const scrollerRef = useRef<HTMLDivElement>(null);
|
|
144
145
|
const virtualizer = useVirtualizer({
|
|
145
146
|
count,
|
|
147
|
+
overscan: 0,
|
|
146
148
|
horizontal: orientation === "horizontal",
|
|
147
149
|
getScrollElement: () => scrollerRef.current,
|
|
148
150
|
estimateSize: () => (orientation === "horizontal" ? width : height),
|
|
@@ -150,15 +152,11 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
150
152
|
|
|
151
153
|
const virtualItems = virtualizer.getVirtualItems();
|
|
152
154
|
|
|
153
|
-
const
|
|
155
|
+
const currentIndexRef = useRef(0);
|
|
154
156
|
useEffect(() => {
|
|
155
|
-
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
virtualItems[0] &&
|
|
159
|
-
scrollerRef.current.scrollTop < virtualItems[0].size
|
|
160
|
-
)
|
|
161
|
-
currentIndex.current = 0;
|
|
157
|
+
currentIndexRef.current = virtualItems[0]?.index ?? 0;
|
|
158
|
+
if (scrollerRef.current && virtualItems[0] && scrollerRef.current.scrollTop < virtualItems[0].size)
|
|
159
|
+
currentIndexRef.current = 0;
|
|
162
160
|
}, [virtualItems]);
|
|
163
161
|
|
|
164
162
|
const calculateActiveScroll = useCallback(() => {
|
|
@@ -180,96 +178,96 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
180
178
|
if (scrollWidth === offsetWidth) return 0;
|
|
181
179
|
|
|
182
180
|
if (Math.abs(scrollLeft) === 0) return 1;
|
|
183
|
-
if (Math.abs(scrollLeft) >= scrollWidth - offsetWidth - extraSize * 2)
|
|
184
|
-
return 2;
|
|
181
|
+
if (Math.abs(scrollLeft) >= scrollWidth - offsetWidth - extraSize * 2) return 2;
|
|
185
182
|
}
|
|
186
183
|
return 3;
|
|
184
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
187
185
|
}, [orientation]);
|
|
188
186
|
|
|
189
187
|
const [scrollActive, setScrollActive] = useState(0);
|
|
190
|
-
const fireScrollEvent = useDebounce(
|
|
191
|
-
() => onScroll?.(currentIndex.current),
|
|
192
|
-
[onScroll],
|
|
193
|
-
);
|
|
188
|
+
const fireScrollEvent = useDebounce(() => onScroll?.(currentIndexRef.current), [onScroll]);
|
|
194
189
|
const handleScroll = useCallback(() => {
|
|
195
190
|
setScrollActive(calculateActiveScroll());
|
|
196
191
|
fireScrollEvent();
|
|
192
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
197
193
|
}, [orientation, onLoadMore]);
|
|
198
194
|
|
|
199
195
|
useEffect(() => {
|
|
196
|
+
// eslint-disable-next-line @eslint-react/set-state-in-effect
|
|
200
197
|
setScrollActive(calculateActiveScroll());
|
|
201
198
|
}, [itemList, calculateActiveScroll]);
|
|
202
199
|
|
|
203
200
|
useEffect(() => {
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return () => db.cancel();
|
|
210
|
-
}, [onLoadMore, loading, itemList, virtualItems, count]);
|
|
211
|
-
|
|
212
|
-
useEffect(() => {
|
|
213
|
-
const firstItem = virtualItems[0]?.index;
|
|
214
|
-
if (onLoadMore && firstItem !== undefined && items[firstItem] === null) {
|
|
201
|
+
if (onLoadMore) {
|
|
202
|
+
const firstItem = virtualItems[0]?.index;
|
|
203
|
+
const lastItem = virtualItems?.slice(-1).pop()?.index;
|
|
204
|
+
const canLoadPrevPage = firstItem !== undefined && items[firstItem] === null;
|
|
205
|
+
const canLoadNextPage = lastItem !== undefined && lastItem === count - 1 && count < total;
|
|
215
206
|
const db = debounce(onLoadMore);
|
|
216
|
-
|
|
207
|
+
if (canLoadPrevPage) {
|
|
208
|
+
db(firstItem);
|
|
209
|
+
} else if (!loading && canLoadNextPage) {
|
|
210
|
+
db(lastItem + 1);
|
|
211
|
+
}
|
|
217
212
|
return () => db.cancel();
|
|
218
213
|
}
|
|
219
|
-
|
|
214
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
215
|
+
}, [onLoadMore, virtualItems]);
|
|
220
216
|
|
|
217
|
+
const isRenderedRef = useRef(false);
|
|
221
218
|
useLayoutEffect(() => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
219
|
+
if (!isRenderedRef.current && itemList.length > 0) {
|
|
220
|
+
isRenderedRef.current = true;
|
|
221
|
+
if (initialScroll) {
|
|
222
|
+
const tmr = setTimeout(() => {
|
|
223
|
+
virtualizer.scrollToIndex(Math.floor(initialScroll), {
|
|
224
|
+
align: "start",
|
|
225
|
+
});
|
|
226
|
+
}, 200);
|
|
227
|
+
|
|
228
|
+
return () => {
|
|
229
|
+
clearTimeout(tmr);
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
234
|
+
}, [itemList, initialScroll]);
|
|
227
235
|
|
|
228
236
|
useImperativeHandle(
|
|
229
237
|
listRef,
|
|
230
238
|
() => ({
|
|
231
239
|
scrollToItem(index) {
|
|
232
|
-
virtualizer.scrollToIndex(index, { align: "
|
|
240
|
+
virtualizer.scrollToIndex(index, { align: "auto" });
|
|
233
241
|
},
|
|
234
242
|
hilight(index) {
|
|
235
|
-
scrollerRef.current
|
|
236
|
-
|
|
237
|
-
?.classList.remove("hilight", "ring-1");
|
|
243
|
+
const el = scrollerRef.current?.querySelector("[data-selected='true']") as HTMLElement;
|
|
244
|
+
if (el) el.dataset.selected = "false";
|
|
238
245
|
virtualizer.scrollToIndex(Math.floor(index), {
|
|
239
|
-
align: "
|
|
246
|
+
align: "auto",
|
|
240
247
|
});
|
|
241
248
|
setTimeout(() => {
|
|
242
|
-
scrollerRef.current
|
|
243
|
-
|
|
244
|
-
?.classList.add("hilight", "ring-1");
|
|
249
|
+
const el = scrollerRef.current?.querySelector(`[data-index="${index}"]`) as HTMLElement;
|
|
250
|
+
if (el) el.dataset.selected = "true";
|
|
245
251
|
}, 100);
|
|
246
252
|
},
|
|
247
253
|
unhilight() {
|
|
248
|
-
scrollerRef.current
|
|
249
|
-
|
|
250
|
-
?.classList.remove("hilight", "ring-1");
|
|
254
|
+
const el = scrollerRef.current?.querySelector("[data-selected='true']") as HTMLElement;
|
|
255
|
+
if (el) el.dataset.selected = "false";
|
|
251
256
|
},
|
|
252
257
|
}),
|
|
253
258
|
[virtualizer],
|
|
254
259
|
);
|
|
255
260
|
|
|
256
261
|
return (
|
|
257
|
-
<div
|
|
258
|
-
ref={scrollerRef}
|
|
259
|
-
onScroll={handleScroll}
|
|
260
|
-
className={classNames(
|
|
261
|
-
"area-content bg-base overflow-auto contain-strict",
|
|
262
|
-
)}
|
|
263
|
-
{...aria}
|
|
264
|
-
>
|
|
262
|
+
<div ref={scrollerRef} onScroll={handleScroll} className={cn("area-content bg-default overflow-auto")} {...aria}>
|
|
265
263
|
<div
|
|
266
|
-
className={
|
|
267
|
-
"
|
|
264
|
+
className={cn(
|
|
265
|
+
"flex flex-nowrap gap-2 justify-center min-h-full min-w-full",
|
|
268
266
|
orientation === "horizontal" && "flex-col",
|
|
269
267
|
)}
|
|
270
268
|
>
|
|
271
269
|
<div
|
|
272
|
-
className={
|
|
270
|
+
className={cn(
|
|
273
271
|
"box-content inline-flex flex-nowrap",
|
|
274
272
|
orientation === "vertical" && "flex-col",
|
|
275
273
|
orientation === "horizontal" && "flex-row",
|
|
@@ -278,12 +276,16 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
278
276
|
padding === "md" && "p-2",
|
|
279
277
|
padding === "lg" && "p-4",
|
|
280
278
|
)}
|
|
279
|
+
style={{
|
|
280
|
+
minWidth,
|
|
281
|
+
maxWidth,
|
|
282
|
+
}}
|
|
281
283
|
>
|
|
282
284
|
<div
|
|
283
285
|
style={
|
|
284
286
|
orientation === "vertical"
|
|
285
|
-
? { height: virtualizer.getTotalSize() }
|
|
286
|
-
: { width: virtualizer.getTotalSize() }
|
|
287
|
+
? { height: virtualizer.getTotalSize() + extraSize }
|
|
288
|
+
: { width: virtualizer.getTotalSize() + extraSize }
|
|
287
289
|
}
|
|
288
290
|
>
|
|
289
291
|
<div
|
|
@@ -298,26 +300,29 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
298
300
|
key={key}
|
|
299
301
|
data-index={index}
|
|
300
302
|
ref={virtualizer.measureElement}
|
|
301
|
-
className={
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
303
|
+
className={cn("rounded-capped", orientation === "horizontal" ? "inline-grid" : "grid")}
|
|
304
|
+
style={{
|
|
305
|
+
minWidth: width,
|
|
306
|
+
minHeight: height,
|
|
307
|
+
}}
|
|
305
308
|
>
|
|
306
|
-
{
|
|
309
|
+
{itemList[index]?.item
|
|
310
|
+
? children(itemList[index])
|
|
311
|
+
: itemList[index]?.item === null && <Skeleton className="p-2" />}
|
|
307
312
|
</div>
|
|
308
313
|
))}
|
|
309
314
|
</div>
|
|
310
|
-
{
|
|
311
|
-
<div className={orientation === "horizontal" ? "min-w-16" : "
|
|
312
|
-
|
|
315
|
+
{loading && (
|
|
316
|
+
<div className={orientation === "horizontal" ? "min-w-16" : ""}>
|
|
317
|
+
<Skeleton />
|
|
313
318
|
</div>
|
|
314
319
|
)}
|
|
315
320
|
</div>
|
|
316
321
|
{!hideScroller && (
|
|
317
322
|
<div
|
|
318
|
-
className={
|
|
323
|
+
className={cn(
|
|
319
324
|
orientation === "vertical" && "self-end sticky bottom-2",
|
|
320
|
-
orientation === "horizontal" && "self-end sticky
|
|
325
|
+
orientation === "horizontal" && "self-end sticky inset-e-2",
|
|
321
326
|
)}
|
|
322
327
|
>
|
|
323
328
|
<Scroller
|
|
@@ -327,17 +332,13 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
327
332
|
onPrevious={() =>
|
|
328
333
|
scrollerRef.current &&
|
|
329
334
|
virtualizer.scrollBy(
|
|
330
|
-
-(orientation === "vertical"
|
|
331
|
-
? scrollerRef.current.offsetHeight
|
|
332
|
-
: scrollerRef.current.offsetWidth),
|
|
335
|
+
-(orientation === "vertical" ? scrollerRef.current.offsetHeight : scrollerRef.current.offsetWidth),
|
|
333
336
|
)
|
|
334
337
|
}
|
|
335
338
|
onNext={() =>
|
|
336
339
|
scrollerRef.current &&
|
|
337
340
|
virtualizer.scrollBy(
|
|
338
|
-
orientation === "vertical"
|
|
339
|
-
? scrollerRef.current.offsetHeight
|
|
340
|
-
: scrollerRef.current.offsetWidth,
|
|
341
|
+
orientation === "vertical" ? scrollerRef.current.offsetHeight : scrollerRef.current.offsetWidth,
|
|
341
342
|
)
|
|
342
343
|
}
|
|
343
344
|
onEnd={() => virtualizer.scrollToIndex(count - 1)}
|
|
@@ -348,7 +349,39 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
348
349
|
</div>
|
|
349
350
|
);
|
|
350
351
|
};
|
|
351
|
-
_VirtualList.displayName = "VirtualList";
|
|
352
352
|
|
|
353
353
|
const GenericMemo: <T>(c: T) => T = memo;
|
|
354
|
-
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* VirtualList component for rendering large lists efficiently using virtualization.
|
|
357
|
+
* It supports horizontal and vertical orientations, custom item heights and widths,
|
|
358
|
+
* and provides a scroller for navigating through the list.
|
|
359
|
+
* It also supports loading more items on scroll and provides a way to hilight items.
|
|
360
|
+
* It can be used with a ref to control scrolling and hilighting of items.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```jsx
|
|
364
|
+
* <VirtualList
|
|
365
|
+
* items={items}
|
|
366
|
+
* children={({ item, index, isLast }) => (
|
|
367
|
+
* <div key={index} className="item">
|
|
368
|
+
* {item.label}
|
|
369
|
+
* </div>
|
|
370
|
+
* )}
|
|
371
|
+
* fullWidth={true}
|
|
372
|
+
* orientation="vertical"
|
|
373
|
+
* defaultHeight={50}
|
|
374
|
+
* onLoadMore={(lastIndex) => console.log("Load more items from index:", lastIndex)}
|
|
375
|
+
* onScroll={(top) => console.log("Scrolled to top:", top)}
|
|
376
|
+
* listRef={virtualListRef}
|
|
377
|
+
* >
|
|
378
|
+
* {({ item, index, isLast }) => (
|
|
379
|
+
* <div className="gallery-item" key={item.id}>
|
|
380
|
+
* <img src={item.image} alt={item.label} />
|
|
381
|
+
* <p>{item.label}</p>
|
|
382
|
+
* </div>
|
|
383
|
+
* )}
|
|
384
|
+
* </VirtualList>
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
export const VirtualList = GenericMemo(VirtualListComponent);
|
package/src/virtual/Scroller.tsx
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import { Button, ButtonGroup
|
|
24
|
+
import { Button, ButtonGroup } from "@react-fabric/core";
|
|
25
25
|
|
|
26
26
|
export const Scroller = ({
|
|
27
27
|
vertical = true,
|
|
@@ -41,38 +41,54 @@ export const Scroller = ({
|
|
|
41
41
|
return (
|
|
42
42
|
<ButtonGroup vertical={vertical} variant="link" className="outline">
|
|
43
43
|
<Button
|
|
44
|
-
rtlFlip
|
|
45
44
|
size="sm"
|
|
46
45
|
variant="link"
|
|
47
46
|
aria-label="scroll to top"
|
|
48
|
-
icon={
|
|
47
|
+
icon={{
|
|
48
|
+
icon: vertical
|
|
49
|
+
? "icon-[mdi--chevron-double-up]"
|
|
50
|
+
: "icon-[mdi--chevron-double-left]",
|
|
51
|
+
rtlFlip: true,
|
|
52
|
+
}}
|
|
49
53
|
disabled={(scrollActive & 2) === 0}
|
|
50
54
|
onClick={onStart}
|
|
51
55
|
/>
|
|
52
56
|
<Button
|
|
53
|
-
rtlFlip
|
|
54
57
|
size="sm"
|
|
55
58
|
variant="link"
|
|
56
59
|
aria-label="scroll up"
|
|
57
|
-
icon={
|
|
60
|
+
icon={{
|
|
61
|
+
icon: vertical
|
|
62
|
+
? "icon-[mdi--chevron-up]"
|
|
63
|
+
: "icon-[mdi--chevron-left]",
|
|
64
|
+
rtlFlip: true,
|
|
65
|
+
}}
|
|
58
66
|
disabled={(scrollActive & 2) === 0}
|
|
59
67
|
onClick={onPrevious}
|
|
60
68
|
/>
|
|
61
69
|
<Button
|
|
62
|
-
rtlFlip
|
|
63
70
|
size="sm"
|
|
64
71
|
variant="link"
|
|
65
72
|
aria-label="scroll down"
|
|
66
|
-
icon={
|
|
73
|
+
icon={{
|
|
74
|
+
icon: vertical
|
|
75
|
+
? "icon-[mdi--chevron-down]"
|
|
76
|
+
: "icon-[mdi--chevron-right]",
|
|
77
|
+
rtlFlip: true,
|
|
78
|
+
}}
|
|
67
79
|
disabled={scrollActive % 2 === 0}
|
|
68
80
|
onClick={onNext}
|
|
69
81
|
/>
|
|
70
82
|
<Button
|
|
71
|
-
rtlFlip
|
|
72
83
|
size="sm"
|
|
73
84
|
variant="link"
|
|
74
85
|
aria-label="scroll to bottom"
|
|
75
|
-
icon={
|
|
86
|
+
icon={{
|
|
87
|
+
icon: vertical
|
|
88
|
+
? "icon-[mdi--chevron-double-down]"
|
|
89
|
+
: "icon-[mdi--chevron-double-right]",
|
|
90
|
+
rtlFlip: true,
|
|
91
|
+
}}
|
|
76
92
|
disabled={scrollActive % 2 === 0}
|
|
77
93
|
onClick={onEnd}
|
|
78
94
|
/>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@layer comp{.histogram{.histoLabel{--tw-gradient-from:var(--color) var(--tw-gradient-from-position);--tw-gradient-to:color-mix(in lab,var(--color) 20%,var(--fabric-bg)) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to);background-color:color(from var(--color) srgb r g b/5%);&:hover{background-color:color(from var(--color) srgb r g b/15%)}&[data-disabled=true]{--color:theme(colors.tint.300);color:theme(colors.tint.600)}}.histoBar{box-shadow:-2px 0 0 var(--color) inset;:global([dir=rtl]) &{box-shadow:2px 0 0 var(--color) inset}}.histoBadge{background-color:color(from var(--color) srgb r g b/15%)}}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@layer comp{.histogram{.histoLabel{--tw-gradient-from:var(--color) var(--tw-gradient-from-position);--tw-gradient-to:color-mix(in lab,var(--color) 20%,var(--fabric-bg)) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to);background-color:color(from var(--color) srgb r g b/5%);&:hover{background-color:color(from var(--color) srgb r g b/15%)}&[data-disabled=true]{--color:theme(colors.tint.300);color:theme(colors.tint.600)}}.histoBar{box-shadow:-2px 0 0 var(--color) inset;:global([dir=rtl]) &{box-shadow:2px 0 0 var(--color) inset}}.histoBadge{background-color:color(from var(--color) srgb r g b/15%)}}}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type ChildrenProp } from "@react-fabric/core/dist/types/types";
|
|
2
|
-
interface Context {
|
|
3
|
-
widths: Map<string, number>;
|
|
4
|
-
startResize: (col: HTMLElement) => void;
|
|
5
|
-
}
|
|
6
|
-
export declare const TableProvider: ({ children }: ChildrenProp) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
-
export declare const useTableContext: () => Context;
|
|
8
|
-
export {};
|