@infinite-table/infinite-react 0.4.13 → 0.5.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 (282) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/API.md +0 -0
  3. package/build/buildPackageJson.js +43 -0
  4. package/build/scripts/test.js +37 -0
  5. package/bundler.config.js +25 -0
  6. package/globals.d.ts +7 -0
  7. package/package.json +102 -3
  8. package/rollup.config.js +15 -0
  9. package/run-build-deepmap.js +47 -0
  10. package/run-build.js +45 -0
  11. package/run-dts-concat.js +21 -0
  12. package/src/components/CSSVariableWatch.tsx +82 -0
  13. package/src/components/DataSource/BooleanCollectionState.ts +214 -0
  14. package/src/components/DataSource/BooleanDeepCollectionState.ts +208 -0
  15. package/src/components/DataSource/DataSourceContext.ts +20 -0
  16. package/src/components/DataSource/GroupRowsState.ts +74 -0
  17. package/src/components/DataSource/Indexer.ts +27 -0
  18. package/src/components/DataSource/RowSelectionState.ts +763 -0
  19. package/src/components/DataSource/defaultFilterTypes.ts +64 -0
  20. package/src/components/DataSource/index.tsx +108 -0
  21. package/src/components/DataSource/privateHooks/getChangeDetect.ts +7 -0
  22. package/src/components/DataSource/privateHooks/useLoadData.ts +783 -0
  23. package/src/components/DataSource/publicHooks/useDataSource.ts +19 -0
  24. package/src/components/DataSource/publicHooks/useDataSourceActions.ts +14 -0
  25. package/src/components/DataSource/state/getInitialState.ts +494 -0
  26. package/src/components/DataSource/state/normalizeSortInfo.ts +35 -0
  27. package/src/components/DataSource/state/reducer.ts +466 -0
  28. package/src/components/DataSource/state/rowInfoStatus.ts +27 -0
  29. package/src/components/DataSource/types.ts +548 -0
  30. package/src/components/HeadlessTable/HeadlessTableWithPinnedContainers.tsx +142 -0
  31. package/src/components/HeadlessTable/MappedCells.ts +251 -0
  32. package/src/components/HeadlessTable/RawTable.tsx +98 -0
  33. package/src/components/HeadlessTable/ReactHeadlessTableRenderer.tsx +1516 -0
  34. package/src/components/HeadlessTable/index.tsx +234 -0
  35. package/src/components/InfiniteTable/InfiniteCls.css.ts +164 -0
  36. package/src/components/InfiniteTable/InfiniteTableContext.ts +16 -0
  37. package/src/components/InfiniteTable/api/getImperativeApi.ts +391 -0
  38. package/src/components/InfiniteTable/api/getSelectionApi.ts +364 -0
  39. package/src/components/InfiniteTable/api/type.ts +11 -0
  40. package/src/components/InfiniteTable/components/ActiveCellIndicator.css.ts +51 -0
  41. package/src/components/InfiniteTable/components/ActiveCellIndicator.tsx +116 -0
  42. package/src/components/InfiniteTable/components/ActiveRowIndicator.css.ts +56 -0
  43. package/src/components/InfiniteTable/components/ActiveRowIndicator.tsx +94 -0
  44. package/src/components/InfiniteTable/components/CheckBox.css.ts +13 -0
  45. package/src/components/InfiniteTable/components/CheckBox.tsx +96 -0
  46. package/src/components/InfiniteTable/components/FilterEditors.tsx +52 -0
  47. package/src/components/InfiniteTable/components/InfiniteTableBody/InfiniteTableBody.tsx +27 -0
  48. package/src/components/InfiniteTable/components/InfiniteTableBody/index.tsx +1 -0
  49. package/src/components/InfiniteTable/components/InfiniteTableFooter/InfiniteTableFooter.tsx +31 -0
  50. package/src/components/InfiniteTable/components/InfiniteTableFooter/index.tsx +1 -0
  51. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableColumnHeaderFilter.tsx +102 -0
  52. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeader.tsx +163 -0
  53. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderCell.tsx +574 -0
  54. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderGroup.tsx +79 -0
  55. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderTypes.tsx +25 -0
  56. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderWrapper.tsx +185 -0
  57. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/GroupResizeHandle.tsx +159 -0
  58. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/ResizeHandle.css.ts +124 -0
  59. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/columnResizer.ts +166 -0
  60. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/index.tsx +146 -0
  61. package/src/components/InfiniteTable/components/InfiniteTableHeader/buildColumnAndGroupTree.ts +240 -0
  62. package/src/components/InfiniteTable/components/InfiniteTableHeader/header.css.ts +358 -0
  63. package/src/components/InfiniteTable/components/InfiniteTableHeader/index.tsx +1 -0
  64. package/src/components/InfiniteTable/components/InfiniteTableHeader/useColumnGroupResizeHandle.tsx +114 -0
  65. package/src/components/InfiniteTable/components/InfiniteTableHeader/useColumnResizeHandle.tsx +146 -0
  66. package/src/components/InfiniteTable/components/InfiniteTableLicenseFooter/footer.css.ts +7 -0
  67. package/src/components/InfiniteTable/components/InfiniteTableLicenseFooter/index.tsx +110 -0
  68. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableCell.tsx +120 -0
  69. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableCellTypes.ts +74 -0
  70. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableColumnCell.tsx +457 -0
  71. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRow.tsx +107 -0
  72. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowClassName.ts +6 -0
  73. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowTypes.ts +32 -0
  74. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowUnvirtualized.tsx +75 -0
  75. package/src/components/InfiniteTable/components/InfiniteTableRow/columnRendering.tsx +263 -0
  76. package/src/components/InfiniteTable/components/InfiniteTableRow/index.tsx +1 -0
  77. package/src/components/InfiniteTable/components/InfiniteTableRow/row.css.ts +74 -0
  78. package/src/components/InfiniteTable/components/InfiniteTableRow/useRowDOMProps.ts +199 -0
  79. package/src/components/InfiniteTable/components/LoadMask.css.ts +34 -0
  80. package/src/components/InfiniteTable/components/LoadMask.tsx +27 -0
  81. package/src/components/InfiniteTable/components/ScrollbarPlaceholder.tsx +56 -0
  82. package/src/components/InfiniteTable/components/cell.css.ts +192 -0
  83. package/src/components/InfiniteTable/components/icons/ArrowDown.tsx +14 -0
  84. package/src/components/InfiniteTable/components/icons/ArrowUp.tsx +14 -0
  85. package/src/components/InfiniteTable/components/icons/ExpanderIcon.css.ts +31 -0
  86. package/src/components/InfiniteTable/components/icons/ExpanderIcon.tsx +63 -0
  87. package/src/components/InfiniteTable/components/icons/Icon.tsx +18 -0
  88. package/src/components/InfiniteTable/components/icons/InfiniteTableIconClassName.ts +1 -0
  89. package/src/components/InfiniteTable/components/icons/LoadingIcon.css.ts +8 -0
  90. package/src/components/InfiniteTable/components/icons/LoadingIcon.tsx +45 -0
  91. package/src/components/InfiniteTable/components/icons/MenuIcon.tsx +50 -0
  92. package/src/components/InfiniteTable/components/icons/SortIcon.tsx +113 -0
  93. package/src/components/InfiniteTable/eventHandlers/eventHandlerTypes.ts +57 -0
  94. package/src/components/InfiniteTable/eventHandlers/index.ts +95 -0
  95. package/src/components/InfiniteTable/eventHandlers/keyboardNavigation.ts +232 -0
  96. package/src/components/InfiniteTable/eventHandlers/keyboardSelection.ts +110 -0
  97. package/src/components/InfiniteTable/eventHandlers/onCellClick.ts +94 -0
  98. package/src/components/InfiniteTable/eventHandlers/onKeyDown.ts +25 -0
  99. package/src/components/InfiniteTable/hooks/adjustColumnOrderForAllColumns.ts +70 -0
  100. package/src/components/InfiniteTable/hooks/reorderColumnsOnDrag.ts +476 -0
  101. package/src/components/InfiniteTable/hooks/useAutoSizeColumns.ts +206 -0
  102. package/src/components/InfiniteTable/hooks/useCellClassName.ts +80 -0
  103. package/src/components/InfiniteTable/hooks/useCellRendering.tsx +217 -0
  104. package/src/components/InfiniteTable/hooks/useColumnGroups.ts +71 -0
  105. package/src/components/InfiniteTable/hooks/useColumnMenu.ts +72 -0
  106. package/src/components/InfiniteTable/hooks/useColumnPointerEvents.ts +258 -0
  107. package/src/components/InfiniteTable/hooks/useColumnRowspan.ts +43 -0
  108. package/src/components/InfiniteTable/hooks/useColumnSizeFn.ts +24 -0
  109. package/src/components/InfiniteTable/hooks/useColumnsWhen.ts +582 -0
  110. package/src/components/InfiniteTable/hooks/useComputed.ts +186 -0
  111. package/src/components/InfiniteTable/hooks/useComputedVisibleColumns.ts +219 -0
  112. package/src/components/InfiniteTable/hooks/useDOMProps.ts +306 -0
  113. package/src/components/InfiniteTable/hooks/useEffectWithRaf.ts +47 -0
  114. package/src/components/InfiniteTable/hooks/useInfiniteTable.ts +10 -0
  115. package/src/components/InfiniteTable/hooks/useInfiniteTableState.ts +11 -0
  116. package/src/components/InfiniteTable/hooks/useInternalProps.ts +8 -0
  117. package/src/components/InfiniteTable/hooks/useLicense/LicenseDetails.ts +13 -0
  118. package/src/components/InfiniteTable/hooks/useLicense/crc32.ts +56 -0
  119. package/src/components/InfiniteTable/hooks/useLicense/decode.ts +147 -0
  120. package/src/components/InfiniteTable/hooks/useLicense/useLicense.ts +39 -0
  121. package/src/components/InfiniteTable/hooks/useRerenderOnKeyChange.ts +21 -0
  122. package/src/components/InfiniteTable/hooks/useRowHover.ts +18 -0
  123. package/src/components/InfiniteTable/hooks/useScrollToActiveCell.ts +48 -0
  124. package/src/components/InfiniteTable/hooks/useScrollToActiveRow.ts +44 -0
  125. package/src/components/InfiniteTable/hooks/useScrollbars.ts +51 -0
  126. package/src/components/InfiniteTable/hooks/useToggleGroupRow.ts +56 -0
  127. package/src/components/InfiniteTable/hooks/useUnpinnedRendering.tsx +165 -0
  128. package/src/components/InfiniteTable/hooks/useYourBrain.ts +55 -0
  129. package/src/components/InfiniteTable/index.tsx +352 -0
  130. package/src/components/InfiniteTable/internalProps.ts +4 -0
  131. package/src/components/InfiniteTable/state/computeColumnGroupsDepths.ts +29 -0
  132. package/src/components/InfiniteTable/state/getColumnVisibilityForHideEmptyGroupColumns.ts +127 -0
  133. package/src/components/InfiniteTable/state/getInitialState.ts +375 -0
  134. package/src/components/InfiniteTable/theme.css.ts +556 -0
  135. package/src/components/InfiniteTable/types/InfiniteTableAction.ts +6 -0
  136. package/src/components/InfiniteTable/types/InfiniteTableActionType.ts +12 -0
  137. package/src/components/InfiniteTable/types/InfiniteTableColumn.ts +478 -0
  138. package/src/components/InfiniteTable/types/InfiniteTableComputedValues.ts +43 -0
  139. package/src/components/InfiniteTable/types/InfiniteTableContextValue.ts +12 -0
  140. package/src/components/InfiniteTable/types/InfiniteTableInternalProps.ts +3 -0
  141. package/src/components/InfiniteTable/types/InfiniteTableProps.ts +511 -0
  142. package/src/components/InfiniteTable/types/InfiniteTableState.ts +195 -0
  143. package/src/components/InfiniteTable/types/Utility.ts +35 -0
  144. package/src/components/InfiniteTable/types/index.ts +96 -0
  145. package/src/components/InfiniteTable/utilities.css.ts +179 -0
  146. package/src/components/InfiniteTable/utils/MultiRowSelector.ts +111 -0
  147. package/src/components/InfiniteTable/utils/RenderHookComponentForInfinite.tsx +52 -0
  148. package/src/components/InfiniteTable/utils/adjustColumnOrderForPinning.ts +33 -0
  149. package/src/components/InfiniteTable/utils/assignFiltered.ts +29 -0
  150. package/src/components/InfiniteTable/utils/defaultGetColumContextMenuItems.tsx +108 -0
  151. package/src/components/InfiniteTable/utils/getColumnComputedType.ts +33 -0
  152. package/src/components/InfiniteTable/utils/getColumnForGroupBy.tsx +313 -0
  153. package/src/components/InfiniteTable/utils/getComputedVisibleColumns.ts +773 -0
  154. package/src/components/InfiniteTable/utils/getContextMenuForColumn.tsx +72 -0
  155. package/src/components/InfiniteTable/utils/infiniteDOMUtils.ts +189 -0
  156. package/src/components/InfiniteTable/utils/mapToObject.ts +20 -0
  157. package/src/components/InfiniteTable/utils/moveXatY.ts +25 -0
  158. package/src/components/InfiniteTable/utils/objectValuesExcept.ts +9 -0
  159. package/src/components/InfiniteTable/utils/progressiveSpeedScroller.ts +158 -0
  160. package/src/components/InfiniteTable/utils/rafFn.ts +13 -0
  161. package/src/components/InfiniteTable/utils/toCSSVarName.ts +1 -0
  162. package/src/components/InfiniteTable/utils/toMap.ts +24 -0
  163. package/src/components/Menu/Menu.tsx +750 -0
  164. package/src/components/Menu/MenuCls.css.ts +139 -0
  165. package/src/components/Menu/MenuContext.ts +10 -0
  166. package/src/components/Menu/MenuContextValue.ts +15 -0
  167. package/src/components/Menu/MenuProps.ts +98 -0
  168. package/src/components/Menu/MenuState.ts +56 -0
  169. package/src/components/Menu/MenuTriangleContext.ts +352 -0
  170. package/src/components/Menu/childrenToRuntimeItems.tsx +103 -0
  171. package/src/components/Menu/getMenuState.tsx +119 -0
  172. package/src/components/Menu/index.tsx +88 -0
  173. package/src/components/Menu/propToIdentifyMenu.ts +1 -0
  174. package/src/components/RawList/AvoidReactDiff.tsx +48 -0
  175. package/src/components/RawList/MappedItems.ts +143 -0
  176. package/src/components/RawList/ReactVirtualRenderer.tsx +307 -0
  177. package/src/components/RawList/index.tsx +42 -0
  178. package/src/components/RawList/types.ts +23 -0
  179. package/src/components/RawList/useVirtualRenderer.ts +36 -0
  180. package/src/components/RenderHookComponent.tsx +10 -0
  181. package/src/components/ResizeObserver/index.tsx +170 -0
  182. package/src/components/VirtualBrain/MatrixBrain.ts +1621 -0
  183. package/src/components/VirtualBrain/ScrollListener.ts +39 -0
  184. package/src/components/VirtualBrain/index.ts +664 -0
  185. package/src/components/VirtualList/ColumnListWithExternalScrolling.tsx +78 -0
  186. package/src/components/VirtualList/InfiniteListRootClassName.ts +1 -0
  187. package/src/components/VirtualList/RowListWithExternalScrolling.tsx +120 -0
  188. package/src/components/VirtualList/SpacePlaceholder.tsx +32 -0
  189. package/src/components/VirtualList/VirtualList.css.ts +29 -0
  190. package/src/components/VirtualList/VirtualList.tsx +141 -0
  191. package/src/components/VirtualList/VirtualRowList.tsx +34 -0
  192. package/src/components/VirtualList/types.ts +56 -0
  193. package/src/components/VirtualList/useCorrectHeightForRowElements.ts +14 -0
  194. package/src/components/VirtualScrollContainer/VirtualScrollContainer.css.ts +51 -0
  195. package/src/components/VirtualScrollContainer/getScrollableClassName.ts +30 -0
  196. package/src/components/VirtualScrollContainer/index.tsx +63 -0
  197. package/src/components/flexbox/index.ts +562 -0
  198. package/src/components/hooks/useComponentState/index.tsx +562 -0
  199. package/src/components/hooks/useComponentState/types.ts +32 -0
  200. package/src/components/hooks/useEffectOnceWithProperUnmount.ts +33 -0
  201. package/src/components/hooks/useEffectWithChanges.ts +56 -0
  202. package/src/components/hooks/useImmutableRef.ts +7 -0
  203. package/src/components/hooks/useInterceptedMap.ts +71 -0
  204. package/src/components/hooks/useLatest.tsx +8 -0
  205. package/src/components/hooks/useLazyLatest.ts +23 -0
  206. package/src/components/hooks/useMemoShallowObjectMerge.ts +16 -0
  207. package/src/components/hooks/useMounted.ts +18 -0
  208. package/src/components/hooks/useOnMount.ts +21 -0
  209. package/src/components/hooks/useOnScroll.ts +34 -0
  210. package/src/components/hooks/useOnce.ts +10 -0
  211. package/src/components/hooks/useOverlay/index.tsx +418 -0
  212. package/src/components/hooks/usePrevious.ts +8 -0
  213. package/src/components/hooks/usePropertyOld.ts +168 -0
  214. package/src/components/hooks/useRerender.ts +12 -0
  215. package/src/components/hooks/xuseProperty.ts +165 -0
  216. package/src/components/types/CellPosition.ts +4 -0
  217. package/src/components/types/NonUndefined.ts +1 -0
  218. package/src/components/types/RemoveObject.ts +22 -0
  219. package/src/components/types/Renderable.ts +3 -0
  220. package/src/components/types/ScrollPosition.ts +7 -0
  221. package/src/components/types/Setter.ts +2 -0
  222. package/src/components/types/Size.ts +6 -0
  223. package/src/components/types/SubscriptionCallback.ts +10 -0
  224. package/src/components/types/VoidFn.ts +1 -0
  225. package/src/components/utils/buildSubscriptionCallback.tsx +60 -0
  226. package/src/components/utils/clamp.ts +3 -0
  227. package/src/components/utils/debounce.ts +16 -0
  228. package/src/components/utils/decamelize.ts +11 -0
  229. package/src/components/utils/discardCallsWithEqualArg.ts +42 -0
  230. package/src/components/utils/getRenderIndexes.ts +33 -0
  231. package/src/components/utils/getScrollbarWidth.ts +31 -0
  232. package/src/components/utils/getVirtualRenderCount.ts +21 -0
  233. package/src/components/utils/isControlled.ts +12 -0
  234. package/src/components/utils/isControlledValue.ts +5 -0
  235. package/src/index.tsx +34 -0
  236. package/src/test.tsx +18 -0
  237. package/src/utils/DeepMap/index.ts +588 -0
  238. package/src/utils/DeepMap/once.ts +16 -0
  239. package/src/utils/DeepMap/sortAscending.ts +1 -0
  240. package/src/utils/DeepMap/tsconfig.deepmap.json +17 -0
  241. package/src/utils/DeepMap/xpackage.json +26 -0
  242. package/src/utils/debug.ts +40 -0
  243. package/src/utils/deepClone.ts +38 -0
  244. package/src/utils/getGlobal.ts +3 -0
  245. package/src/utils/groupAndPivot/defaultToKey.ts +3 -0
  246. package/src/utils/groupAndPivot/getGroupKeysForDataItem.ts +19 -0
  247. package/src/utils/groupAndPivot/getPivotColumnsAndColumnGroups.ts +361 -0
  248. package/src/utils/groupAndPivot/index.ts +1229 -0
  249. package/src/utils/groupAndPivot/types.ts +10 -0
  250. package/src/utils/join.ts +4 -0
  251. package/src/utils/mathIntersection.ts +21 -0
  252. package/src/utils/minified.d.ts +2 -0
  253. package/src/utils/minified.js +6 -0
  254. package/src/utils/multisort/index.ts +151 -0
  255. package/src/utils/multisort/sortTypes.ts +25 -0
  256. package/src/utils/notes-status.md +92 -0
  257. package/src/utils/pageGeometry/ConvexPoly.ts +34 -0
  258. package/src/utils/pageGeometry/Point.ts +51 -0
  259. package/src/utils/pageGeometry/PolyWithPoints.ts +52 -0
  260. package/src/utils/pageGeometry/Rectangle.ts +98 -0
  261. package/src/utils/pageGeometry/Triangle.ts +16 -0
  262. package/src/utils/pageGeometry/alignment/index.ts +221 -0
  263. package/src/utils/pageGeometry/polyContainsPoint.ts +182 -0
  264. package/src/utils/pageGeometry/types.ts +3 -0
  265. package/src/utils/proxyFnCall.ts +46 -0
  266. package/src/utils/raf.ts +13 -0
  267. package/src/utils/selectParent.ts +18 -0
  268. package/src/utils/shallowEqualObjects.ts +49 -0
  269. package/src/utils/stripVar.ts +3 -0
  270. package/src/utils/toUpperFirst.ts +5 -0
  271. package/todo.md +2 -0
  272. package/tsconfig.build.json +8 -0
  273. package/tsconfig.dev.json +7 -0
  274. package/tsconfig.json +30 -0
  275. package/tsconfig.typebundler.json +13 -0
  276. package/typedoc.json +4 -0
  277. package/README.md +0 -104
  278. package/index.css +0 -857
  279. package/index.d.ts +0 -2111
  280. package/index.esm.css +0 -857
  281. package/index.esm.js +0 -13695
  282. package/index.js +0 -13565
@@ -0,0 +1,307 @@
1
+ import * as React from 'react';
2
+ import type { RefCallback } from 'react';
3
+ import type { Renderable } from '../types/Renderable';
4
+ import type { RenderItem } from './types';
5
+ import type { SubscriptionCallback } from '../types/SubscriptionCallback';
6
+ import type { RenderRange } from '../VirtualBrain';
7
+
8
+ import { dbg, Logger } from '../../utils/debug';
9
+
10
+ import { VirtualBrain } from '../VirtualBrain';
11
+
12
+ import { MappedItems } from './MappedItems';
13
+ import { AvoidReactDiff } from './AvoidReactDiff';
14
+ import { buildSubscriptionCallback } from '../utils/buildSubscriptionCallback';
15
+
16
+ const ITEM_POSITION_WITH_TRANSFORM = true;
17
+
18
+ export class ReactVirtualRenderer extends Logger {
19
+ private mappedItems: MappedItems;
20
+ // needed for hot reload and react hooks executing twice in dev
21
+ private destroyed: boolean = false;
22
+
23
+ private itemDOMElements: Record<number, HTMLElement | null> = {};
24
+ private itemDOMRefs: Record<number, RefCallback<HTMLElement>> = {};
25
+ private updaters: Record<number, SubscriptionCallback<Renderable>> = {};
26
+
27
+ private onRender: (items: Renderable[]) => void = () => null;
28
+ private brain: VirtualBrain;
29
+
30
+ private items: Renderable[] = [];
31
+ prevLength: number = 0;
32
+
33
+ constructor(
34
+ brain: VirtualBrain,
35
+ {
36
+ onRender,
37
+ channel,
38
+ }: {
39
+ onRender?: ReactVirtualRenderer['onRender'];
40
+ channel?: string;
41
+ },
42
+ ) {
43
+ super(
44
+ `ReactVirtualRenderer:${brain.getOptions().mainAxis}` +
45
+ (channel ? `:${channel}` : ''),
46
+ );
47
+
48
+ if (onRender) {
49
+ this.onRender = onRender;
50
+ }
51
+
52
+ this.brain = brain;
53
+ this.mappedItems = new MappedItems(brain.getOptions().mainAxis);
54
+ }
55
+
56
+ renderRange = (
57
+ range: RenderRange,
58
+ {
59
+ renderItem,
60
+ force,
61
+ onRender,
62
+ }: {
63
+ renderItem: RenderItem;
64
+ force: boolean;
65
+ onRender?: (items: Renderable[]) => void;
66
+ },
67
+ ): Renderable[] => {
68
+ // needed for hot reload and react hooks executing twice in dev
69
+ if (this.destroyed) {
70
+ // console.warn('DESTROYED');
71
+ return [];
72
+ }
73
+ const { mappedItems } = this;
74
+ const { renderStartIndex, renderEndIndex } = range;
75
+
76
+ if (__DEV__) {
77
+ this.debug(
78
+ `Render range ${renderStartIndex}-${renderEndIndex}. Force ${force}`,
79
+ );
80
+ }
81
+
82
+ const renderCount =
83
+ renderEndIndex === -1 ? 0 : renderEndIndex - renderStartIndex + 1;
84
+
85
+ if (this.itemDOMElements[renderCount]) {
86
+ mappedItems.discardElementsStartingWith(renderCount, (elementIndex) => {
87
+ delete this.itemDOMElements[elementIndex];
88
+ delete this.itemDOMRefs[elementIndex];
89
+
90
+ // when less items become rendered
91
+ // we unmount the extra items by calling destroy on the updater
92
+ // so we don't need to re-render the whole container
93
+ if (this.updaters[elementIndex]) {
94
+ this.updaters[elementIndex].destroy();
95
+ delete this.updaters[elementIndex];
96
+ }
97
+
98
+ delete this.items[elementIndex];
99
+ if (__DEV__) {
100
+ this.debug(`Discard element ${elementIndex}`);
101
+ }
102
+ });
103
+ }
104
+ if (this.items.length > renderCount) {
105
+ this.items.length = renderCount;
106
+ }
107
+
108
+ const elementsOutsideItemRange =
109
+ this.mappedItems.getElementsOutsideItemRange(
110
+ renderStartIndex,
111
+ renderEndIndex,
112
+ );
113
+
114
+ // start from the last rendered, and render additional elements, until we have renderCount
115
+ // this loop might not even execute the body once if all the elements are present
116
+ for (let i = this.items.length; i < renderCount; i++) {
117
+ this.renderElement(i);
118
+ // push at start
119
+ elementsOutsideItemRange.splice(0, 0, i);
120
+ }
121
+
122
+ for (let i = renderStartIndex; i <= renderEndIndex; i++) {
123
+ if (mappedItems.isRenderedItem(i)) {
124
+ if (force) {
125
+ this.renderItemAtElement(i, undefined, renderItem);
126
+ }
127
+ continue;
128
+ }
129
+
130
+ const elementIndex = elementsOutsideItemRange.pop();
131
+ if (elementIndex == null) {
132
+ if (__DEV__) {
133
+ this.error(`Cannot find element to render item ${i}`);
134
+ }
135
+ continue;
136
+ }
137
+ this.renderItemAtElement(i, elementIndex, renderItem);
138
+ }
139
+
140
+ // OLD we need to spread and create a new array
141
+ // OLD as otherwise the AvoidReactDiff component will receive the same array
142
+ // OLD and since it uses setState internally, it will not render/update
143
+ // const result = [...this.items];
144
+ let result = this.items;
145
+
146
+ // TODO why does this optimisation not work
147
+ // if (this.items.length > this.prevLength) {
148
+ // // only assign and do a render when
149
+ // // we have more items than last time
150
+ // // so we need to show new items
151
+ result = [...this.items];
152
+
153
+ if (this.onRender) {
154
+ this.onRender(result);
155
+ }
156
+ if (onRender) {
157
+ onRender(result);
158
+ }
159
+ // this.prevLength = result.length;
160
+ // }
161
+
162
+ return result;
163
+ };
164
+
165
+ private renderElement(elementIndex: number) {
166
+ const domRef = (node: HTMLElement | null) => {
167
+ if (node) {
168
+ this.itemDOMElements[elementIndex] = node;
169
+ this.updateElementPosition(elementIndex);
170
+ }
171
+ };
172
+ this.itemDOMRefs[elementIndex] = domRef;
173
+ this.updaters[elementIndex] = buildSubscriptionCallback<Renderable>();
174
+
175
+ const item = (
176
+ <AvoidReactDiff
177
+ key={elementIndex}
178
+ name={`${elementIndex}`}
179
+ updater={this.updaters[elementIndex]}
180
+ />
181
+ );
182
+
183
+ // if (__DEV__) {
184
+ // this.debug(`Mount element ${elementIndex}`);
185
+ // }
186
+ this.items[elementIndex] = item;
187
+
188
+ return item;
189
+ }
190
+
191
+ private renderItemAtElement(
192
+ itemIndex: number,
193
+ elementIndex = this.mappedItems.getElementIndexForItem(itemIndex) as number,
194
+ renderItem: RenderItem,
195
+ // swapSpanned?: boolean,
196
+ ) {
197
+ // needed for hot reload and react hooks executing twice in dev
198
+ if (this.destroyed) {
199
+ return;
200
+ }
201
+ const spanParent = this.brain.getItemSpanParent(itemIndex);
202
+ let covered = false;
203
+ if (spanParent !== itemIndex) {
204
+ // if (swapSpanned) {
205
+ // debugger;
206
+ // itemIndex = spanParent;
207
+ // } else {
208
+
209
+ covered = true;
210
+ // }
211
+ }
212
+ const itemSize = this.brain.getItemSize(itemIndex);
213
+ const itemSpan = this.brain.getItemSpan(itemIndex);
214
+ const itemSizeWithSpan =
215
+ itemSpan === 1
216
+ ? itemSize
217
+ : this.brain.getItemSizeWithSpan(itemIndex, itemSpan);
218
+
219
+ const renderedNode = renderItem({
220
+ spanParent,
221
+ itemIndex,
222
+ itemSize,
223
+ itemSizeWithSpan,
224
+ itemSpan,
225
+ covered,
226
+ domRef: this.itemDOMRefs[elementIndex],
227
+ });
228
+
229
+ const itemUpdater = this.updaters[elementIndex];
230
+
231
+ if (!itemUpdater) {
232
+ this.error(
233
+ `Cannot find item updater for item ${itemIndex} at this time... sorry.`,
234
+ );
235
+ return;
236
+ }
237
+ this.mappedItems.renderItemAtElement(itemIndex, elementIndex, renderedNode);
238
+
239
+ if (__DEV__) {
240
+ dbg(`ReactVirtualRenderer:${this.brain.getOptions().mainAxis}`)(
241
+ `Render item ${itemIndex} at element ${elementIndex}`,
242
+ );
243
+ }
244
+ itemUpdater(renderedNode);
245
+
246
+ this.updateElementPosition(elementIndex);
247
+ }
248
+
249
+ private updateElementPosition = (elementIndex: number) => {
250
+ const itemElement = this.itemDOMElements[elementIndex];
251
+ const itemIndex =
252
+ this.mappedItems.getItemRenderedAtElementIndex(elementIndex);
253
+
254
+ const options = this.brain.getOptions();
255
+
256
+ if (itemIndex == null) {
257
+ if (__DEV__) {
258
+ this.error(`Cannot find item for element ${elementIndex}`);
259
+ }
260
+ return;
261
+ }
262
+
263
+ const itemPosition = this.brain.getItemOffsetFor(itemIndex);
264
+
265
+ if (itemPosition == null) {
266
+ return;
267
+ }
268
+
269
+ if (itemElement) {
270
+ if (__DEV__) {
271
+ (itemElement.dataset as any).elementIndex = elementIndex;
272
+ (itemElement.dataset as any).itemIndex = itemIndex;
273
+ }
274
+
275
+ if (ITEM_POSITION_WITH_TRANSFORM) {
276
+ itemElement.style.transform =
277
+ options.mainAxis === 'vertical'
278
+ ? `translateY(${itemPosition}px)`
279
+ : `translateX(${itemPosition}px)`;
280
+ itemElement.style.visibility = '';
281
+ } else {
282
+ itemElement.style.display = '';
283
+ itemElement.style[
284
+ options.mainAxis === 'vertical' ? 'top' : 'left'
285
+ ] = `${itemPosition}px`;
286
+ }
287
+ }
288
+ };
289
+
290
+ destroy = () => {
291
+ this.destroyed = true;
292
+ this.reset();
293
+
294
+ (this as any).onRender = null;
295
+ (this as any).renderItem = null;
296
+ (this as any).brain = null;
297
+ (this as any).mappedItems = null;
298
+ };
299
+
300
+ reset() {
301
+ this.itemDOMElements = {};
302
+ this.itemDOMRefs = {};
303
+ this.updaters = {};
304
+ this.items = [];
305
+ this.mappedItems.reset();
306
+ }
307
+ }
@@ -0,0 +1,42 @@
1
+ import * as React from 'react';
2
+ import { useEffect } from 'react';
3
+
4
+ import { AvoidReactDiff } from './AvoidReactDiff';
5
+ import { RawListProps } from './types';
6
+ import { useLatest } from '../hooks/useLatest';
7
+ import { useVirtualRenderer } from './useVirtualRenderer';
8
+
9
+ function RawListFn(props: RawListProps) {
10
+ const { renderItem, brain, debugChannel } = props;
11
+
12
+ const { onRenderUpdater, renderer } = useVirtualRenderer({
13
+ brain,
14
+ debugChannel,
15
+ });
16
+ const getRenderItem = useLatest(renderItem);
17
+
18
+ useEffect(() => {
19
+ const renderRange = brain.getRenderRange();
20
+
21
+ renderer.renderRange(renderRange, {
22
+ renderItem,
23
+ force: true,
24
+ onRender: onRenderUpdater,
25
+ });
26
+ }, [brain, renderItem, onRenderUpdater]);
27
+
28
+ useEffect(() => {
29
+ const remove = brain.onRenderRangeChange((renderRange) => {
30
+ renderer.renderRange(renderRange, {
31
+ force: false,
32
+ renderItem: getRenderItem(),
33
+ onRender: onRenderUpdater,
34
+ });
35
+ });
36
+ return remove;
37
+ }, [brain, onRenderUpdater]);
38
+
39
+ return <AvoidReactDiff updater={onRenderUpdater} />;
40
+ }
41
+
42
+ export const RawList: React.FC<RawListProps> = React.memo(RawListFn);
@@ -0,0 +1,23 @@
1
+ import type { RefCallback } from 'react';
2
+ import type { Renderable } from '../types/Renderable';
3
+ import type { VirtualBrain } from '../VirtualBrain';
4
+
5
+ export type RenderItemParam = {
6
+ domRef: RefCallback<HTMLElement>;
7
+ itemIndex: number;
8
+ itemSize: number;
9
+ itemSizeWithSpan: number;
10
+ itemSpan: number;
11
+ spanParent: number;
12
+ covered: boolean;
13
+ };
14
+ export type RenderItem = (renderProps: RenderItemParam) => Renderable;
15
+ export type RawListItemSpan = (itemSpanProps: { itemIndex: number }) => number;
16
+
17
+ export type RawListProps = {
18
+ debugChannel?: string;
19
+ renderItem: RenderItem;
20
+ itemSpan?: RawListItemSpan;
21
+ brain: VirtualBrain;
22
+ repaintId?: string | number;
23
+ };
@@ -0,0 +1,36 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { Renderable } from '../types/Renderable';
4
+ import { SubscriptionCallback } from '../types/SubscriptionCallback';
5
+ import { buildSubscriptionCallback } from '../utils/buildSubscriptionCallback';
6
+
7
+ import { VirtualBrain } from '../VirtualBrain';
8
+ import { ReactVirtualRenderer } from './ReactVirtualRenderer';
9
+
10
+ function createRenderer(brain: VirtualBrain) {
11
+ const renderer = new ReactVirtualRenderer(brain, {});
12
+ const onRenderUpdater = buildSubscriptionCallback<Renderable>();
13
+
14
+ brain.onDestroy(() => {
15
+ renderer.destroy();
16
+ onRenderUpdater.destroy();
17
+ });
18
+
19
+ return {
20
+ renderer,
21
+ onRenderUpdater,
22
+ };
23
+ }
24
+ export function useVirtualRenderer({
25
+ brain,
26
+ }: {
27
+ brain: VirtualBrain;
28
+ debugChannel?: string;
29
+ }): {
30
+ onRenderUpdater: SubscriptionCallback<Renderable>;
31
+ renderer: ReactVirtualRenderer;
32
+ } {
33
+ return useMemo(() => {
34
+ return createRenderer(brain);
35
+ }, [brain]);
36
+ }
@@ -0,0 +1,10 @@
1
+ export type RenderHookComponentProps<RENDER_FN extends Function, PARAM_TYPE> = {
2
+ render: RENDER_FN;
3
+ renderParam: PARAM_TYPE;
4
+ };
5
+
6
+ export function RenderHookComponent<RENDER_FN extends Function, PARAM_TYPE>(
7
+ props: RenderHookComponentProps<RENDER_FN, PARAM_TYPE>,
8
+ ) {
9
+ return props.render(props.renderParam) ?? null;
10
+ }
@@ -0,0 +1,170 @@
1
+ import * as React from 'react';
2
+ import {
3
+ useMemo,
4
+ useRef,
5
+ useEffect,
6
+ useLayoutEffect,
7
+ useCallback,
8
+ } from 'react';
9
+
10
+ import { Size, OnResizeFn } from '../types/Size';
11
+ import { debounce } from '../utils/debounce';
12
+
13
+ interface ResizeObserverProps {
14
+ /**
15
+ * Specifies whether to call onResize after the initial render (on mount)
16
+ *
17
+ * @default true
18
+ */
19
+ notifyOnMount?: boolean;
20
+
21
+ /**
22
+ * If set to true, it will be attached using useLayoutEffect. If false, will be attached using useEffect
23
+ * @default false
24
+ */
25
+ earlyAttach?: boolean;
26
+
27
+ onResize: OnResizeFn;
28
+ }
29
+
30
+ export const setupResizeObserver = (
31
+ node: HTMLElement,
32
+ callback: OnResizeFn,
33
+ config: { debounce?: number } = { debounce: 0 },
34
+ ): (() => void) => {
35
+ const debounceTime = config.debounce ?? 0;
36
+ const RO = (window as any).ResizeObserver;
37
+
38
+ const onResizeCallback = debounceTime
39
+ ? debounce(callback, { wait: debounceTime })
40
+ : callback;
41
+
42
+ const observer = new RO((entries: any[]) => {
43
+ const entry = entries[0];
44
+
45
+ let { width, height } = entry.contentRect;
46
+
47
+ if (entry.borderBoxSize?.[0]) {
48
+ height = entry.borderBoxSize[0].blockSize;
49
+ width = entry.borderBoxSize[0].inlineSize;
50
+ } else {
51
+ // this is needed for Safari and other browsers that don't have borderBoxSize on the entry object
52
+ const rect = node.getBoundingClientRect();
53
+ height = rect.height;
54
+ width = rect.width;
55
+ }
56
+
57
+ onResizeCallback({ width, height });
58
+ });
59
+
60
+ observer.observe(node);
61
+
62
+ return () => {
63
+ observer.disconnect();
64
+ };
65
+ };
66
+
67
+ /**
68
+ * A hook that notifies you when a certain DOM element has changed it's size
69
+ *
70
+ * @param ref A React ref to a DOM element
71
+ * @param callback The function to be called when the element is resized.
72
+ */
73
+ export const useResizeObserver = (
74
+ ref: React.MutableRefObject<HTMLElement | null>,
75
+ callback: OnResizeFn,
76
+ config: { earlyAttach: boolean; debounce?: number } = {
77
+ earlyAttach: false,
78
+ debounce: 0,
79
+ },
80
+ ) => {
81
+ const sizeRef = useRef<Size>({
82
+ width: 0,
83
+ height: 0,
84
+ });
85
+
86
+ const effectFn = (callback: OnResizeFn) => {
87
+ let disconnect: () => void;
88
+ if (ref.current) {
89
+ disconnect = setupResizeObserver(
90
+ ref.current,
91
+ (size) => {
92
+ size = {
93
+ width: Math.round(size.width),
94
+ height: Math.round(size.height),
95
+ };
96
+ const prevSize = sizeRef.current;
97
+ if (
98
+ prevSize.width !== size.width ||
99
+ prevSize.height !== size.height
100
+ ) {
101
+ sizeRef.current = size;
102
+
103
+ callback(size);
104
+ }
105
+ },
106
+ { debounce: config.debounce },
107
+ );
108
+ }
109
+ return () => {
110
+ if (disconnect) {
111
+ disconnect();
112
+ }
113
+ };
114
+ };
115
+
116
+ useEffect(() => {
117
+ if (!config.earlyAttach) {
118
+ return effectFn(callback);
119
+ }
120
+ return () => {};
121
+ }, [ref.current, callback, config.earlyAttach, config.debounce]);
122
+
123
+ useLayoutEffect(() => {
124
+ if (config.earlyAttach) {
125
+ return effectFn(callback);
126
+ }
127
+ return () => {};
128
+ }, [ref.current, callback, config.earlyAttach]);
129
+ };
130
+
131
+ const ReactResizeObserver = (props: ResizeObserverProps) => {
132
+ const style = useMemo(
133
+ () => ({
134
+ position: 'absolute' as 'absolute',
135
+ top: 0,
136
+ left: 0,
137
+ width: '100%',
138
+ height: '100%',
139
+ boxSizing: 'border-box' as 'border-box',
140
+ }),
141
+ [],
142
+ );
143
+
144
+ const { notifyOnMount, earlyAttach } = props;
145
+
146
+ const firstTime = useRef(true);
147
+ const ref = useRef<HTMLDivElement>(null);
148
+
149
+ const onResize = useCallback(
150
+ (size: Size) => {
151
+ if (firstTime.current && !notifyOnMount) {
152
+ firstTime.current = false;
153
+ return;
154
+ }
155
+ props.onResize(size);
156
+ },
157
+ [props.onResize],
158
+ );
159
+
160
+ useResizeObserver(ref, onResize, { earlyAttach: earlyAttach || false });
161
+
162
+ return <div ref={ref} style={style}></div>;
163
+ };
164
+
165
+ ReactResizeObserver.defaultProps = {
166
+ notifyOnMount: true,
167
+ earlyAttach: false,
168
+ };
169
+
170
+ export default ReactResizeObserver;