@react-fabric/data 1.0.0-beta.8 → 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.
Files changed (141) hide show
  1. package/{src/histogram/Histogram.module.css → css/_histogram.css} +16 -13
  2. package/css/styles.css +24 -0
  3. package/dist/cjs/checklist/CheckList.js +59 -33
  4. package/dist/cjs/histogram/Histogram.js +41 -26
  5. package/dist/cjs/hooks/useFilteredList.js +100 -17
  6. package/dist/cjs/hooks/usePagination.js +29 -8
  7. package/dist/cjs/hooks/useSelectableList.js +30 -5
  8. package/dist/cjs/i18n/{ar.json.js → ar/data.json.js} +8 -1
  9. package/dist/cjs/i18n/{en.json.js → en/data.json.js} +8 -1
  10. package/dist/cjs/i18n/index.js +4 -4
  11. package/dist/cjs/index.js +30 -0
  12. package/dist/cjs/json/JsonViewer.js +80 -43
  13. package/dist/cjs/pagination/Pagination.js +24 -15
  14. package/dist/cjs/table/AddColumn.js +5 -5
  15. package/dist/cjs/table/BodyCell.js +20 -13
  16. package/dist/cjs/table/BodyRow.js +41 -28
  17. package/dist/cjs/table/CheckboxCell.js +10 -9
  18. package/dist/cjs/table/ColumnFilters.js +100 -0
  19. package/dist/cjs/table/EmptyCell.js +4 -4
  20. package/dist/cjs/table/HeaderCell.js +79 -53
  21. package/dist/cjs/table/HtmlTable.js +84 -0
  22. package/dist/cjs/table/{Context.js → Provider.js} +8 -10
  23. package/dist/cjs/table/Table.js +99 -33
  24. package/dist/cjs/{tree/types.js → table/context.js} +9 -5
  25. package/dist/cjs/table/types.js +29 -0
  26. package/dist/cjs/table/useResizer.js +10 -10
  27. package/dist/cjs/table/useTableColumns.js +4 -4
  28. package/dist/cjs/table/useVirtualTable.js +129 -22
  29. package/dist/cjs/tree/TreeNode.js +66 -46
  30. package/dist/cjs/tree/TreePanel.js +60 -24
  31. package/dist/cjs/tree/useTree.js +212 -47
  32. package/dist/cjs/tree/utils.js +63 -34
  33. package/dist/cjs/utils/getColor.js +58 -0
  34. package/dist/cjs/virtual/Gallery.js +119 -61
  35. package/dist/cjs/virtual/List.js +116 -55
  36. package/dist/cjs/virtual/Scroller.js +16 -8
  37. package/dist/esm/checklist/CheckList.js +61 -35
  38. package/dist/esm/histogram/Histogram.js +43 -28
  39. package/dist/esm/hooks/useFilteredList.js +101 -18
  40. package/dist/esm/hooks/usePagination.js +29 -8
  41. package/dist/esm/hooks/useSelectableList.js +30 -5
  42. package/dist/esm/i18n/{ar.json.js → ar/data.json.js} +8 -2
  43. package/dist/esm/i18n/{en.json.js → en/data.json.js} +8 -2
  44. package/dist/esm/i18n/index.js +2 -2
  45. package/dist/esm/index.js +31 -0
  46. package/dist/esm/json/JsonViewer.js +82 -45
  47. package/dist/esm/pagination/Pagination.js +25 -16
  48. package/dist/esm/table/AddColumn.js +6 -6
  49. package/dist/esm/table/BodyCell.js +21 -14
  50. package/dist/esm/table/BodyRow.js +41 -28
  51. package/dist/esm/table/CheckboxCell.js +11 -10
  52. package/dist/esm/table/ColumnFilters.js +100 -0
  53. package/dist/esm/table/EmptyCell.js +4 -4
  54. package/dist/esm/table/HeaderCell.js +80 -54
  55. package/dist/esm/table/HtmlTable.js +84 -0
  56. package/dist/esm/table/{Context.js → Provider.js} +11 -12
  57. package/dist/esm/table/Table.js +100 -34
  58. package/dist/esm/{tree/types.js → table/context.js} +8 -4
  59. package/dist/esm/table/types.js +29 -0
  60. package/dist/esm/table/useResizer.js +10 -10
  61. package/dist/esm/table/useTableColumns.js +4 -4
  62. package/dist/esm/table/useVirtualTable.js +131 -24
  63. package/dist/esm/tree/TreeNode.js +69 -49
  64. package/dist/esm/tree/TreePanel.js +62 -26
  65. package/dist/esm/tree/useTree.js +215 -50
  66. package/dist/esm/tree/utils.js +64 -35
  67. package/dist/esm/utils/getColor.js +58 -0
  68. package/dist/esm/virtual/Gallery.js +121 -63
  69. package/dist/esm/virtual/List.js +118 -57
  70. package/dist/esm/virtual/Scroller.js +17 -9
  71. package/dist/types/checklist/CheckList.d.ts +25 -6
  72. package/dist/types/histogram/Histogram.d.ts +28 -6
  73. package/dist/types/hooks/useFilteredList.d.ts +62 -5
  74. package/dist/types/hooks/usePagination.d.ts +18 -2
  75. package/dist/types/hooks/useSelectableList.d.ts +24 -1
  76. package/dist/types/index.d.ts +27 -0
  77. package/dist/types/json/JsonViewer.d.ts +23 -3
  78. package/dist/types/pagination/Pagination.d.ts +8 -2
  79. package/dist/types/table/AddColumn.d.ts +2 -2
  80. package/dist/types/table/BodyCell.d.ts +2 -2
  81. package/dist/types/table/BodyRow.d.ts +9 -9
  82. package/dist/types/table/CheckboxCell.d.ts +3 -3
  83. package/dist/types/table/ColumnFilters.d.ts +12 -0
  84. package/dist/types/table/EmptyCell.d.ts +1 -1
  85. package/dist/types/table/HeaderCell.d.ts +1 -1
  86. package/dist/types/table/HtmlTable.d.ts +21 -0
  87. package/dist/types/table/Provider.d.ts +2 -0
  88. package/dist/types/table/Table.d.ts +10 -1
  89. package/dist/types/table/context.d.ts +7 -0
  90. package/dist/types/table/types.d.ts +52 -10
  91. package/dist/types/table/useResizer.d.ts +1 -1
  92. package/dist/types/table/useTableColumns.d.ts +1 -1
  93. package/dist/types/table/useVirtualTable.d.ts +31 -12
  94. package/dist/types/tree/TreeNode.d.ts +1 -1
  95. package/dist/types/tree/TreePanel.d.ts +36 -1
  96. package/dist/types/tree/types.d.ts +75 -28
  97. package/dist/types/tree/useTree.d.ts +8 -12
  98. package/dist/types/tree/utils.d.ts +15 -8
  99. package/dist/types/utils/getColor.d.ts +43 -0
  100. package/dist/types/virtual/Gallery.d.ts +37 -6
  101. package/dist/types/virtual/List.d.ts +38 -6
  102. package/dist/types/virtual/Scroller.d.ts +1 -1
  103. package/package.json +17 -19
  104. package/src/checklist/CheckList.tsx +68 -71
  105. package/src/histogram/Histogram.tsx +47 -48
  106. package/src/hooks/useFilteredList.tsx +111 -28
  107. package/src/hooks/usePagination.tsx +39 -39
  108. package/src/hooks/useSelectableList.ts +45 -33
  109. package/src/i18n/{ar.json → ar/data.json} +5 -0
  110. package/src/i18n/{en.json → en/data.json} +5 -0
  111. package/src/i18n/index.ts +2 -2
  112. package/src/index.ts +23 -17
  113. package/src/json/JsonViewer.tsx +89 -120
  114. package/src/pagination/Pagination.tsx +104 -105
  115. package/src/table/AddColumn.tsx +6 -15
  116. package/src/table/BodyCell.tsx +27 -36
  117. package/src/table/BodyRow.tsx +36 -59
  118. package/src/table/CheckboxCell.tsx +12 -15
  119. package/src/table/ColumnFilters.tsx +93 -0
  120. package/src/table/EmptyCell.tsx +5 -18
  121. package/src/table/HeaderCell.tsx +72 -53
  122. package/src/table/HtmlTable.tsx +106 -0
  123. package/src/table/{Context.tsx → Provider.tsx} +11 -28
  124. package/src/table/Table.tsx +98 -83
  125. package/src/table/context.ts +33 -0
  126. package/src/table/types.ts +53 -27
  127. package/src/table/useResizer.ts +5 -9
  128. package/src/table/useTableColumns.ts +4 -6
  129. package/src/table/useVirtualTable.ts +136 -37
  130. package/src/tree/TreeNode.tsx +91 -86
  131. package/src/tree/TreePanel.tsx +87 -51
  132. package/src/tree/types.ts +85 -46
  133. package/src/tree/useTree.ts +210 -65
  134. package/src/tree/utils.ts +81 -62
  135. package/src/utils/getColor.ts +55 -0
  136. package/src/virtual/Gallery.tsx +129 -120
  137. package/src/virtual/List.tsx +124 -91
  138. package/src/virtual/Scroller.tsx +25 -9
  139. package/dist/cjs/histogram/Histogram.module.css +0 -1
  140. package/dist/esm/histogram/Histogram.module.css +0 -1
  141. package/dist/types/table/Context.d.ts +0 -8
@@ -23,9 +23,8 @@
23
23
 
24
24
  import { Skeleton, useDebounce, useEffectDebugger } from "@react-fabric/core";
25
25
  import { type TestProps } from "@react-fabric/core/dist/types/types";
26
- import { debounce } from "@react-fabric/utilities";
26
+ import { cn, debounce } from "@react-fabric/utilities";
27
27
  import { useVirtualizer } from "@tanstack/react-virtual";
28
- import classNames from "classnames";
29
28
  import memoize from "memoize-one";
30
29
  import {
31
30
  memo,
@@ -49,11 +48,7 @@ export interface VirtualGalleryRef {
49
48
  }
50
49
 
51
50
  export interface VirtualGalleryProps<T> extends TestProps {
52
- children: (props: {
53
- data: T;
54
- index: number;
55
- isLast: boolean;
56
- }) => ReactElement;
51
+ children: (props: { item: T; index: number; isLast: boolean }) => ReactElement;
57
52
  galleryRef?: Ref<VirtualGalleryRef | undefined>;
58
53
  /**
59
54
  * fixed columns
@@ -67,6 +62,12 @@ export interface VirtualGalleryProps<T> extends TestProps {
67
62
  * default item width
68
63
  */
69
64
  defaultWidth?: number;
65
+ /**
66
+ * full width list
67
+ */
68
+ fullWidth?: boolean;
69
+ maxWidth?: string | number;
70
+ minWidth?: string | number;
70
71
  /**
71
72
  * padding
72
73
  */
@@ -75,6 +76,7 @@ export interface VirtualGalleryProps<T> extends TestProps {
75
76
  * data list
76
77
  */
77
78
  items: T[];
79
+ total?: number;
78
80
  /**
79
81
  * loading state
80
82
  */
@@ -87,19 +89,23 @@ export interface VirtualGalleryProps<T> extends TestProps {
87
89
  /**
88
90
  * load more callback
89
91
  */
90
- onLoadMore?: () => void;
92
+ onLoadMore?: (lastIndex?: number) => void;
91
93
  /**
92
94
  * scroll handler
93
95
  */
94
96
  onScroll?: (top: number) => void;
95
97
  }
96
98
 
97
- const createItemList = memoize((items) => items);
99
+ const createItemList = memoize((items) => items as never);
98
100
 
99
- const _VirtualGallery = <T extends KeyValue>({
101
+ const VirtualGalleryComponent = <T extends AnyObject>({
100
102
  items,
101
103
  children,
102
104
  columns,
105
+ fullWidth,
106
+ maxWidth,
107
+ minWidth,
108
+ total = 0,
103
109
  padding = "md",
104
110
  defaultHeight: height = 48,
105
111
  defaultWidth: width = 48,
@@ -112,36 +118,33 @@ const _VirtualGallery = <T extends KeyValue>({
112
118
  ...aria
113
119
  }: VirtualGalleryProps<T>) => {
114
120
  const count = useDeferredValue(items.length);
115
- const extraSize = useMemo(() => (onLoadMore ? 64 : 0), [onLoadMore]);
121
+ const extraSize = useMemo(() => (onLoadMore ? 8 : 0), [onLoadMore]);
116
122
  const itemList: Array<{
117
123
  index: number;
118
- data: T;
124
+ item: T;
119
125
  isLast: boolean;
120
126
  isSticky: boolean;
121
127
  }> = createItemList(
122
- items.map((item: AnyObject, idx) => {
128
+ items.map((item, index) => {
123
129
  return {
124
- index: idx,
125
- data: item,
126
- isLast: idx + 1 === items.length,
130
+ index,
131
+ item,
132
+ isLast: index + 1 === items.length,
127
133
  };
128
134
  }),
129
135
  );
130
136
 
131
137
  const scrollerRef = useRef<HTMLDivElement>(null);
132
138
  const [columnCount, setColumnCount] = useState(1);
133
- const columnMap = useMemo(
134
- () => new Array(columnCount).fill(0).map((_, idx) => idx),
135
- [columnCount],
136
- );
139
+ const columnMap = useMemo(() => new Array(columnCount).fill(0).map((_, idx) => idx), [columnCount]);
137
140
  useEffectDebugger(
138
141
  () => {
139
142
  if (scrollerRef.current) {
140
143
  const el = scrollerRef.current;
141
144
  const handler = () => {
145
+ const pad = parseInt(getComputedStyle(el.firstElementChild?.firstElementChild as HTMLElement).padding ?? 8);
142
146
  setColumnCount(
143
- columns ??
144
- Math.max(1, Math.floor(((el?.offsetWidth ?? 800) - 32) / width)),
147
+ columns ?? Math.max(1, Math.floor(((el?.offsetWidth ?? 800) - 32 - (isNaN(pad) ? 8 : pad) * 2) / width)),
145
148
  );
146
149
  };
147
150
  const ob = new ResizeObserver(handler);
@@ -161,183 +164,162 @@ const _VirtualGallery = <T extends KeyValue>({
161
164
  count: Math.ceil(count / columnCount),
162
165
  getScrollElement: () => scrollerRef.current,
163
166
  estimateSize: () => height,
167
+ overscan: 0,
164
168
  });
165
169
 
166
170
  const virtualItems = virtualizer.getVirtualItems();
167
171
 
168
- const currentIndex = useRef(0);
172
+ const currentIndexRef = useRef(0);
169
173
  useEffect(() => {
170
- currentIndex.current = virtualItems[1]?.index ?? 0;
171
- if (
172
- scrollerRef.current &&
173
- virtualItems[0] &&
174
- scrollerRef.current.scrollTop < virtualItems[0].size
175
- )
176
- currentIndex.current = 0;
174
+ currentIndexRef.current = virtualItems[0]?.index ?? 0;
175
+ if (scrollerRef.current && virtualItems[0] && scrollerRef.current.scrollTop < virtualItems[0].size)
176
+ currentIndexRef.current = 0;
177
177
  }, [virtualItems]);
178
178
 
179
179
  const calculateActiveScroll = useCallback(() => {
180
- const {
181
- scrollTop = 0,
182
- scrollHeight = 0,
183
- offsetHeight = 0,
184
- } = (scrollerRef.current ?? {}) as HTMLElement;
180
+ const { scrollTop = 0, scrollHeight = 0, offsetHeight = 0 } = (scrollerRef.current ?? {}) as HTMLElement;
185
181
  if (scrollHeight === offsetHeight) return 0;
186
182
 
187
183
  if (scrollTop === 0) return 1;
188
184
  if (scrollTop >= scrollHeight - offsetHeight - extraSize * 2) return 2;
189
185
 
190
186
  return 3;
187
+ // eslint-disable-next-line @eslint-react/exhaustive-deps
191
188
  }, []);
192
189
 
193
190
  const [scrollActive, setScrollActive] = useState(0);
194
- const fireScrollEvent = useDebounce(
195
- (idx: number) => onScroll?.(currentIndex.current * idx),
196
- [onScroll],
197
- );
191
+ const fireScrollEvent = useDebounce((idx: number) => onScroll?.(currentIndexRef.current * idx), [onScroll]);
198
192
  const handleScroll = useCallback(() => {
199
193
  setScrollActive(calculateActiveScroll());
200
194
  fireScrollEvent(columnCount);
195
+ // eslint-disable-next-line @eslint-react/exhaustive-deps
201
196
  }, [columnCount, onLoadMore]);
202
197
 
203
198
  useEffect(() => {
199
+ // eslint-disable-next-line @eslint-react/set-state-in-effect
204
200
  setScrollActive(calculateActiveScroll());
205
201
  }, [count, calculateActiveScroll]);
206
202
 
207
203
  useEffect(() => {
208
- const db = debounce(() => {
209
- const lastItem = virtualItems?.slice(-1).pop();
210
- if (
211
- lastItem &&
212
- !loading &&
213
- lastItem.index * columnCount + columnCount >= count - 1
214
- )
215
- onLoadMore?.();
216
- });
217
- db();
218
- return () => db.cancel();
219
- }, [onLoadMore, loading, itemList, virtualItems, count, columnCount]);
220
-
221
- useEffect(() => {
222
- const firstItem = virtualItems[0]?.index;
223
- if (
224
- onLoadMore &&
225
- firstItem !== undefined &&
226
- items[firstItem * columnCount] === null
227
- ) {
204
+ if (onLoadMore) {
205
+ const firstItem = virtualItems[0]?.index;
206
+ const lastItem = virtualItems?.slice(-1).pop()?.index;
207
+ const firstIndex = firstItem * columnCount;
208
+ const lastIndex = (lastItem ?? 0) * columnCount + columnCount;
209
+ const canLoadPrevPage = firstItem !== undefined && items[firstIndex] === null;
210
+ const canLoadNextPage = lastItem !== undefined && lastIndex >= count - 1 && count < total;
228
211
  const db = debounce(onLoadMore);
229
- db(firstItem * columnCount);
212
+ if (canLoadPrevPage) {
213
+ db(firstIndex);
214
+ } else if (!loading && canLoadNextPage) {
215
+ db(lastIndex + 1);
216
+ }
230
217
  return () => db.cancel();
231
218
  }
232
- }, [onLoadMore, items, columnCount, virtualItems, count]);
219
+ // eslint-disable-next-line @eslint-react/exhaustive-deps
220
+ }, [onLoadMore, virtualItems]);
233
221
 
222
+ const isRenderedRef = useRef(false);
234
223
  useLayoutEffect(() => {
235
- setTimeout(() => {
236
- initialScroll &&
237
- virtualizer.scrollToIndex(Math.floor(initialScroll / columnCount), {
238
- align: "start",
239
- });
240
- }, 100);
241
- }, [columnCount]);
224
+ if (!isRenderedRef.current && itemList.length > 0) {
225
+ isRenderedRef.current = true;
226
+ if (initialScroll) {
227
+ const tmr = setTimeout(() => {
228
+ virtualizer.scrollToIndex(Math.floor(initialScroll / columnCount), {
229
+ align: "start",
230
+ });
231
+ }, 200);
232
+ return () => {
233
+ clearTimeout(tmr);
234
+ };
235
+ }
236
+ }
237
+ // eslint-disable-next-line @eslint-react/exhaustive-deps
238
+ }, [columnCount, initialScroll, itemList]);
242
239
 
243
240
  useImperativeHandle(
244
241
  galleryRef,
245
242
  () => ({
246
243
  scrollToItem(index) {
247
244
  virtualizer.scrollToIndex(Math.floor(index / columnCount), {
248
- align: "start",
245
+ align: "auto",
249
246
  });
250
247
  },
251
248
  hilight(index) {
252
- scrollerRef.current
253
- ?.querySelector(".hilight")
254
- ?.classList.remove("hilight", "ring-1");
255
- virtualizer.scrollToIndex(Math.floor(index / columnCount), {
256
- align: "start",
249
+ const el = scrollerRef.current?.querySelector("[data-selected='true']") as HTMLElement;
250
+ if (el) el.dataset.selected = "false";
251
+ virtualizer.scrollToIndex(Math.floor(index), {
252
+ align: "auto",
257
253
  });
258
254
  setTimeout(() => {
259
- scrollerRef.current
260
- ?.querySelector(`[data-index="${index}"]`)
261
- ?.classList.add("hilight", "ring-1");
255
+ const el = scrollerRef.current?.querySelector(`[data-index="${index}"]`) as HTMLElement;
256
+ if (el) el.dataset.selected = "true";
262
257
  }, 100);
263
258
  },
264
259
  unhilight() {
265
- scrollerRef.current
266
- ?.querySelector(".hilight")
267
- ?.classList.remove("hilight", "ring-1");
260
+ const el = scrollerRef.current?.querySelector("[data-selected='true']") as HTMLElement;
261
+ if (el) el.dataset.selected = "false";
268
262
  },
269
263
  }),
270
264
  [virtualizer, columnCount],
271
265
  );
272
266
 
273
267
  return (
274
- <div
275
- ref={scrollerRef}
276
- onScroll={handleScroll}
277
- className={classNames(
278
- "area-content bg-base overflow-auto contain-strict",
279
- )}
280
- {...aria}
281
- >
282
- <div
283
- className={classNames(
284
- "inline-flex flex-nowrap gap-2 justify-center min-h-full min-w-full",
285
- )}
286
- >
268
+ <div ref={scrollerRef} onScroll={handleScroll} className={cn("area-content bg-default overflow-auto")} {...aria}>
269
+ <div className={cn("flex flex-nowrap justify-center gap-2 min-h-full")}>
287
270
  <div
288
- className={classNames(
271
+ className={cn(
289
272
  "box-content",
273
+ fullWidth && "flex-1",
290
274
  padding === "sm" && "p-1",
291
275
  padding === "md" && "p-2",
292
276
  padding === "lg" && "p-4",
293
277
  )}
278
+ style={{
279
+ minWidth,
280
+ maxWidth,
281
+ }}
294
282
  >
295
283
  <div
296
284
  style={{
297
- height: virtualizer.getTotalSize(),
285
+ height: virtualizer.getTotalSize() + extraSize,
298
286
  }}
299
287
  >
300
288
  <div style={{ height: virtualItems[0]?.start }} />
301
- {virtualItems.map(({ key, index, measureElement }) => (
302
- <div
303
- className="flex"
304
- key={key}
305
- data-index={index}
306
- ref={measureElement}
307
- >
289
+ {virtualItems.map(({ key, index }) => (
290
+ <div className="flex" key={key} data-index={index} ref={virtualizer.measureElement}>
308
291
  {columnMap.map((col) => (
309
292
  <div
310
293
  key={`${key}:${col}`}
311
294
  data-index={index * columnCount + col}
312
- className={classNames("grid rounded-capped")}
295
+ className={cn("grid rounded-capped")}
296
+ style={{
297
+ minWidth: width,
298
+ minHeight: height,
299
+ }}
313
300
  >
314
- {itemList[index * columnCount + col] &&
315
- children(
316
- itemList[index * columnCount + col] as AnyObject,
317
- )}
301
+ {itemList[index * columnCount + col]?.item
302
+ ? children(itemList[index * columnCount + col])
303
+ : itemList[index * columnCount + col]?.item === null && <Skeleton className="p-2" />}
318
304
  </div>
319
305
  ))}
320
306
  </div>
321
307
  ))}
322
- {onLoadMore && (
323
- <div className="h-16">{loading && <Skeleton />}</div>
308
+ {loading && (
309
+ <div>
310
+ <Skeleton />
311
+ </div>
324
312
  )}
325
313
  </div>
326
314
  </div>
327
315
  {!hideScroller && (
328
- <div className={classNames("self-end sticky bottom-2")}>
316
+ <div className={cn("self-end sticky bottom-2")}>
329
317
  <Scroller
330
318
  vertical
331
319
  scrollActive={scrollActive}
332
320
  onStart={() => virtualizer.scrollToIndex(0)}
333
- onPrevious={() =>
334
- scrollerRef.current &&
335
- virtualizer.scrollBy(-scrollerRef.current.offsetHeight)
336
- }
337
- onNext={() =>
338
- scrollerRef.current &&
339
- virtualizer.scrollBy(scrollerRef.current.offsetHeight)
340
- }
321
+ onPrevious={() => scrollerRef.current && virtualizer.scrollBy(-scrollerRef.current.offsetHeight)}
322
+ onNext={() => scrollerRef.current && virtualizer.scrollBy(scrollerRef.current.offsetHeight)}
341
323
  onEnd={() => virtualizer.scrollToIndex(count - 1)}
342
324
  />
343
325
  </div>
@@ -346,7 +328,34 @@ const _VirtualGallery = <T extends KeyValue>({
346
328
  </div>
347
329
  );
348
330
  };
349
- _VirtualGallery.displayName = "VirtualGallery";
350
331
 
351
332
  const GenericMemo: <T>(c: T) => T = memo;
352
- export const VirtualGallery = GenericMemo(_VirtualGallery);
333
+
334
+ /**
335
+ * VirtualGallery component provides a virtualized gallery view for displaying a large list of items efficiently.
336
+ * It supports features like fixed columns, loading states, and customizable item rendering.
337
+ * The component uses virtualization to render only the visible items, improving performance for large datasets.
338
+ * It also provides a scroller for easy navigation through the items.
339
+ *
340
+ * @example
341
+ * ```jsx
342
+ * <VirtualGallery
343
+ * items={items}
344
+ * columns={3}
345
+ * defaultHeight={100}
346
+ * defaultWidth={100}
347
+ * fullWidth={true}
348
+ * onLoadMore={(lastIndex) => console.log("Load more items from index:", lastIndex)}
349
+ * onScroll={(top) => console.log("Scrolled to top:", top)}
350
+ * >
351
+ * {({ item, index, isLast }) => (
352
+ * <div className="gallery-item" key={item.id}>
353
+ * <img src={item.image} alt={item.label} />
354
+ * <p>{item.label}</p>
355
+ * </div>
356
+ * )}
357
+ * </VirtualGallery>
358
+ * ```
359
+ * @see {@link https://tanstack.com/docs/react-virtual/latest/overview}
360
+ */
361
+ export const VirtualGallery = GenericMemo(VirtualGalleryComponent);