@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.
- package/.vscode/settings.json +3 -0
- package/API.md +0 -0
- package/build/buildPackageJson.js +43 -0
- package/build/scripts/test.js +37 -0
- package/bundler.config.js +25 -0
- package/globals.d.ts +7 -0
- package/package.json +102 -3
- package/rollup.config.js +15 -0
- package/run-build-deepmap.js +47 -0
- package/run-build.js +45 -0
- package/run-dts-concat.js +21 -0
- package/src/components/CSSVariableWatch.tsx +82 -0
- package/src/components/DataSource/BooleanCollectionState.ts +214 -0
- package/src/components/DataSource/BooleanDeepCollectionState.ts +208 -0
- package/src/components/DataSource/DataSourceContext.ts +20 -0
- package/src/components/DataSource/GroupRowsState.ts +74 -0
- package/src/components/DataSource/Indexer.ts +27 -0
- package/src/components/DataSource/RowSelectionState.ts +763 -0
- package/src/components/DataSource/defaultFilterTypes.ts +64 -0
- package/src/components/DataSource/index.tsx +108 -0
- package/src/components/DataSource/privateHooks/getChangeDetect.ts +7 -0
- package/src/components/DataSource/privateHooks/useLoadData.ts +783 -0
- package/src/components/DataSource/publicHooks/useDataSource.ts +19 -0
- package/src/components/DataSource/publicHooks/useDataSourceActions.ts +14 -0
- package/src/components/DataSource/state/getInitialState.ts +494 -0
- package/src/components/DataSource/state/normalizeSortInfo.ts +35 -0
- package/src/components/DataSource/state/reducer.ts +466 -0
- package/src/components/DataSource/state/rowInfoStatus.ts +27 -0
- package/src/components/DataSource/types.ts +548 -0
- package/src/components/HeadlessTable/HeadlessTableWithPinnedContainers.tsx +142 -0
- package/src/components/HeadlessTable/MappedCells.ts +251 -0
- package/src/components/HeadlessTable/RawTable.tsx +98 -0
- package/src/components/HeadlessTable/ReactHeadlessTableRenderer.tsx +1516 -0
- package/src/components/HeadlessTable/index.tsx +234 -0
- package/src/components/InfiniteTable/InfiniteCls.css.ts +164 -0
- package/src/components/InfiniteTable/InfiniteTableContext.ts +16 -0
- package/src/components/InfiniteTable/api/getImperativeApi.ts +391 -0
- package/src/components/InfiniteTable/api/getSelectionApi.ts +364 -0
- package/src/components/InfiniteTable/api/type.ts +11 -0
- package/src/components/InfiniteTable/components/ActiveCellIndicator.css.ts +51 -0
- package/src/components/InfiniteTable/components/ActiveCellIndicator.tsx +116 -0
- package/src/components/InfiniteTable/components/ActiveRowIndicator.css.ts +56 -0
- package/src/components/InfiniteTable/components/ActiveRowIndicator.tsx +94 -0
- package/src/components/InfiniteTable/components/CheckBox.css.ts +13 -0
- package/src/components/InfiniteTable/components/CheckBox.tsx +96 -0
- package/src/components/InfiniteTable/components/FilterEditors.tsx +52 -0
- package/src/components/InfiniteTable/components/InfiniteTableBody/InfiniteTableBody.tsx +27 -0
- package/src/components/InfiniteTable/components/InfiniteTableBody/index.tsx +1 -0
- package/src/components/InfiniteTable/components/InfiniteTableFooter/InfiniteTableFooter.tsx +31 -0
- package/src/components/InfiniteTable/components/InfiniteTableFooter/index.tsx +1 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableColumnHeaderFilter.tsx +102 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeader.tsx +163 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderCell.tsx +574 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderGroup.tsx +79 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderTypes.tsx +25 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderWrapper.tsx +185 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/GroupResizeHandle.tsx +159 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/ResizeHandle.css.ts +124 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/columnResizer.ts +166 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/index.tsx +146 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/buildColumnAndGroupTree.ts +240 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/header.css.ts +358 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/index.tsx +1 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/useColumnGroupResizeHandle.tsx +114 -0
- package/src/components/InfiniteTable/components/InfiniteTableHeader/useColumnResizeHandle.tsx +146 -0
- package/src/components/InfiniteTable/components/InfiniteTableLicenseFooter/footer.css.ts +7 -0
- package/src/components/InfiniteTable/components/InfiniteTableLicenseFooter/index.tsx +110 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableCell.tsx +120 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableCellTypes.ts +74 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableColumnCell.tsx +457 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRow.tsx +107 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowClassName.ts +6 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowTypes.ts +32 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowUnvirtualized.tsx +75 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/columnRendering.tsx +263 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/index.tsx +1 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/row.css.ts +74 -0
- package/src/components/InfiniteTable/components/InfiniteTableRow/useRowDOMProps.ts +199 -0
- package/src/components/InfiniteTable/components/LoadMask.css.ts +34 -0
- package/src/components/InfiniteTable/components/LoadMask.tsx +27 -0
- package/src/components/InfiniteTable/components/ScrollbarPlaceholder.tsx +56 -0
- package/src/components/InfiniteTable/components/cell.css.ts +192 -0
- package/src/components/InfiniteTable/components/icons/ArrowDown.tsx +14 -0
- package/src/components/InfiniteTable/components/icons/ArrowUp.tsx +14 -0
- package/src/components/InfiniteTable/components/icons/ExpanderIcon.css.ts +31 -0
- package/src/components/InfiniteTable/components/icons/ExpanderIcon.tsx +63 -0
- package/src/components/InfiniteTable/components/icons/Icon.tsx +18 -0
- package/src/components/InfiniteTable/components/icons/InfiniteTableIconClassName.ts +1 -0
- package/src/components/InfiniteTable/components/icons/LoadingIcon.css.ts +8 -0
- package/src/components/InfiniteTable/components/icons/LoadingIcon.tsx +45 -0
- package/src/components/InfiniteTable/components/icons/MenuIcon.tsx +50 -0
- package/src/components/InfiniteTable/components/icons/SortIcon.tsx +113 -0
- package/src/components/InfiniteTable/eventHandlers/eventHandlerTypes.ts +57 -0
- package/src/components/InfiniteTable/eventHandlers/index.ts +95 -0
- package/src/components/InfiniteTable/eventHandlers/keyboardNavigation.ts +232 -0
- package/src/components/InfiniteTable/eventHandlers/keyboardSelection.ts +110 -0
- package/src/components/InfiniteTable/eventHandlers/onCellClick.ts +94 -0
- package/src/components/InfiniteTable/eventHandlers/onKeyDown.ts +25 -0
- package/src/components/InfiniteTable/hooks/adjustColumnOrderForAllColumns.ts +70 -0
- package/src/components/InfiniteTable/hooks/reorderColumnsOnDrag.ts +476 -0
- package/src/components/InfiniteTable/hooks/useAutoSizeColumns.ts +206 -0
- package/src/components/InfiniteTable/hooks/useCellClassName.ts +80 -0
- package/src/components/InfiniteTable/hooks/useCellRendering.tsx +217 -0
- package/src/components/InfiniteTable/hooks/useColumnGroups.ts +71 -0
- package/src/components/InfiniteTable/hooks/useColumnMenu.ts +72 -0
- package/src/components/InfiniteTable/hooks/useColumnPointerEvents.ts +258 -0
- package/src/components/InfiniteTable/hooks/useColumnRowspan.ts +43 -0
- package/src/components/InfiniteTable/hooks/useColumnSizeFn.ts +24 -0
- package/src/components/InfiniteTable/hooks/useColumnsWhen.ts +582 -0
- package/src/components/InfiniteTable/hooks/useComputed.ts +186 -0
- package/src/components/InfiniteTable/hooks/useComputedVisibleColumns.ts +219 -0
- package/src/components/InfiniteTable/hooks/useDOMProps.ts +306 -0
- package/src/components/InfiniteTable/hooks/useEffectWithRaf.ts +47 -0
- package/src/components/InfiniteTable/hooks/useInfiniteTable.ts +10 -0
- package/src/components/InfiniteTable/hooks/useInfiniteTableState.ts +11 -0
- package/src/components/InfiniteTable/hooks/useInternalProps.ts +8 -0
- package/src/components/InfiniteTable/hooks/useLicense/LicenseDetails.ts +13 -0
- package/src/components/InfiniteTable/hooks/useLicense/crc32.ts +56 -0
- package/src/components/InfiniteTable/hooks/useLicense/decode.ts +147 -0
- package/src/components/InfiniteTable/hooks/useLicense/useLicense.ts +39 -0
- package/src/components/InfiniteTable/hooks/useRerenderOnKeyChange.ts +21 -0
- package/src/components/InfiniteTable/hooks/useRowHover.ts +18 -0
- package/src/components/InfiniteTable/hooks/useScrollToActiveCell.ts +48 -0
- package/src/components/InfiniteTable/hooks/useScrollToActiveRow.ts +44 -0
- package/src/components/InfiniteTable/hooks/useScrollbars.ts +51 -0
- package/src/components/InfiniteTable/hooks/useToggleGroupRow.ts +56 -0
- package/src/components/InfiniteTable/hooks/useUnpinnedRendering.tsx +165 -0
- package/src/components/InfiniteTable/hooks/useYourBrain.ts +55 -0
- package/src/components/InfiniteTable/index.tsx +352 -0
- package/src/components/InfiniteTable/internalProps.ts +4 -0
- package/src/components/InfiniteTable/state/computeColumnGroupsDepths.ts +29 -0
- package/src/components/InfiniteTable/state/getColumnVisibilityForHideEmptyGroupColumns.ts +127 -0
- package/src/components/InfiniteTable/state/getInitialState.ts +375 -0
- package/src/components/InfiniteTable/theme.css.ts +556 -0
- package/src/components/InfiniteTable/types/InfiniteTableAction.ts +6 -0
- package/src/components/InfiniteTable/types/InfiniteTableActionType.ts +12 -0
- package/src/components/InfiniteTable/types/InfiniteTableColumn.ts +478 -0
- package/src/components/InfiniteTable/types/InfiniteTableComputedValues.ts +43 -0
- package/src/components/InfiniteTable/types/InfiniteTableContextValue.ts +12 -0
- package/src/components/InfiniteTable/types/InfiniteTableInternalProps.ts +3 -0
- package/src/components/InfiniteTable/types/InfiniteTableProps.ts +511 -0
- package/src/components/InfiniteTable/types/InfiniteTableState.ts +195 -0
- package/src/components/InfiniteTable/types/Utility.ts +35 -0
- package/src/components/InfiniteTable/types/index.ts +96 -0
- package/src/components/InfiniteTable/utilities.css.ts +179 -0
- package/src/components/InfiniteTable/utils/MultiRowSelector.ts +111 -0
- package/src/components/InfiniteTable/utils/RenderHookComponentForInfinite.tsx +52 -0
- package/src/components/InfiniteTable/utils/adjustColumnOrderForPinning.ts +33 -0
- package/src/components/InfiniteTable/utils/assignFiltered.ts +29 -0
- package/src/components/InfiniteTable/utils/defaultGetColumContextMenuItems.tsx +108 -0
- package/src/components/InfiniteTable/utils/getColumnComputedType.ts +33 -0
- package/src/components/InfiniteTable/utils/getColumnForGroupBy.tsx +313 -0
- package/src/components/InfiniteTable/utils/getComputedVisibleColumns.ts +773 -0
- package/src/components/InfiniteTable/utils/getContextMenuForColumn.tsx +72 -0
- package/src/components/InfiniteTable/utils/infiniteDOMUtils.ts +189 -0
- package/src/components/InfiniteTable/utils/mapToObject.ts +20 -0
- package/src/components/InfiniteTable/utils/moveXatY.ts +25 -0
- package/src/components/InfiniteTable/utils/objectValuesExcept.ts +9 -0
- package/src/components/InfiniteTable/utils/progressiveSpeedScroller.ts +158 -0
- package/src/components/InfiniteTable/utils/rafFn.ts +13 -0
- package/src/components/InfiniteTable/utils/toCSSVarName.ts +1 -0
- package/src/components/InfiniteTable/utils/toMap.ts +24 -0
- package/src/components/Menu/Menu.tsx +750 -0
- package/src/components/Menu/MenuCls.css.ts +139 -0
- package/src/components/Menu/MenuContext.ts +10 -0
- package/src/components/Menu/MenuContextValue.ts +15 -0
- package/src/components/Menu/MenuProps.ts +98 -0
- package/src/components/Menu/MenuState.ts +56 -0
- package/src/components/Menu/MenuTriangleContext.ts +352 -0
- package/src/components/Menu/childrenToRuntimeItems.tsx +103 -0
- package/src/components/Menu/getMenuState.tsx +119 -0
- package/src/components/Menu/index.tsx +88 -0
- package/src/components/Menu/propToIdentifyMenu.ts +1 -0
- package/src/components/RawList/AvoidReactDiff.tsx +48 -0
- package/src/components/RawList/MappedItems.ts +143 -0
- package/src/components/RawList/ReactVirtualRenderer.tsx +307 -0
- package/src/components/RawList/index.tsx +42 -0
- package/src/components/RawList/types.ts +23 -0
- package/src/components/RawList/useVirtualRenderer.ts +36 -0
- package/src/components/RenderHookComponent.tsx +10 -0
- package/src/components/ResizeObserver/index.tsx +170 -0
- package/src/components/VirtualBrain/MatrixBrain.ts +1621 -0
- package/src/components/VirtualBrain/ScrollListener.ts +39 -0
- package/src/components/VirtualBrain/index.ts +664 -0
- package/src/components/VirtualList/ColumnListWithExternalScrolling.tsx +78 -0
- package/src/components/VirtualList/InfiniteListRootClassName.ts +1 -0
- package/src/components/VirtualList/RowListWithExternalScrolling.tsx +120 -0
- package/src/components/VirtualList/SpacePlaceholder.tsx +32 -0
- package/src/components/VirtualList/VirtualList.css.ts +29 -0
- package/src/components/VirtualList/VirtualList.tsx +141 -0
- package/src/components/VirtualList/VirtualRowList.tsx +34 -0
- package/src/components/VirtualList/types.ts +56 -0
- package/src/components/VirtualList/useCorrectHeightForRowElements.ts +14 -0
- package/src/components/VirtualScrollContainer/VirtualScrollContainer.css.ts +51 -0
- package/src/components/VirtualScrollContainer/getScrollableClassName.ts +30 -0
- package/src/components/VirtualScrollContainer/index.tsx +63 -0
- package/src/components/flexbox/index.ts +562 -0
- package/src/components/hooks/useComponentState/index.tsx +562 -0
- package/src/components/hooks/useComponentState/types.ts +32 -0
- package/src/components/hooks/useEffectOnceWithProperUnmount.ts +33 -0
- package/src/components/hooks/useEffectWithChanges.ts +56 -0
- package/src/components/hooks/useImmutableRef.ts +7 -0
- package/src/components/hooks/useInterceptedMap.ts +71 -0
- package/src/components/hooks/useLatest.tsx +8 -0
- package/src/components/hooks/useLazyLatest.ts +23 -0
- package/src/components/hooks/useMemoShallowObjectMerge.ts +16 -0
- package/src/components/hooks/useMounted.ts +18 -0
- package/src/components/hooks/useOnMount.ts +21 -0
- package/src/components/hooks/useOnScroll.ts +34 -0
- package/src/components/hooks/useOnce.ts +10 -0
- package/src/components/hooks/useOverlay/index.tsx +418 -0
- package/src/components/hooks/usePrevious.ts +8 -0
- package/src/components/hooks/usePropertyOld.ts +168 -0
- package/src/components/hooks/useRerender.ts +12 -0
- package/src/components/hooks/xuseProperty.ts +165 -0
- package/src/components/types/CellPosition.ts +4 -0
- package/src/components/types/NonUndefined.ts +1 -0
- package/src/components/types/RemoveObject.ts +22 -0
- package/src/components/types/Renderable.ts +3 -0
- package/src/components/types/ScrollPosition.ts +7 -0
- package/src/components/types/Setter.ts +2 -0
- package/src/components/types/Size.ts +6 -0
- package/src/components/types/SubscriptionCallback.ts +10 -0
- package/src/components/types/VoidFn.ts +1 -0
- package/src/components/utils/buildSubscriptionCallback.tsx +60 -0
- package/src/components/utils/clamp.ts +3 -0
- package/src/components/utils/debounce.ts +16 -0
- package/src/components/utils/decamelize.ts +11 -0
- package/src/components/utils/discardCallsWithEqualArg.ts +42 -0
- package/src/components/utils/getRenderIndexes.ts +33 -0
- package/src/components/utils/getScrollbarWidth.ts +31 -0
- package/src/components/utils/getVirtualRenderCount.ts +21 -0
- package/src/components/utils/isControlled.ts +12 -0
- package/src/components/utils/isControlledValue.ts +5 -0
- package/src/index.tsx +34 -0
- package/src/test.tsx +18 -0
- package/src/utils/DeepMap/index.ts +588 -0
- package/src/utils/DeepMap/once.ts +16 -0
- package/src/utils/DeepMap/sortAscending.ts +1 -0
- package/src/utils/DeepMap/tsconfig.deepmap.json +17 -0
- package/src/utils/DeepMap/xpackage.json +26 -0
- package/src/utils/debug.ts +40 -0
- package/src/utils/deepClone.ts +38 -0
- package/src/utils/getGlobal.ts +3 -0
- package/src/utils/groupAndPivot/defaultToKey.ts +3 -0
- package/src/utils/groupAndPivot/getGroupKeysForDataItem.ts +19 -0
- package/src/utils/groupAndPivot/getPivotColumnsAndColumnGroups.ts +361 -0
- package/src/utils/groupAndPivot/index.ts +1229 -0
- package/src/utils/groupAndPivot/types.ts +10 -0
- package/src/utils/join.ts +4 -0
- package/src/utils/mathIntersection.ts +21 -0
- package/src/utils/minified.d.ts +2 -0
- package/src/utils/minified.js +6 -0
- package/src/utils/multisort/index.ts +151 -0
- package/src/utils/multisort/sortTypes.ts +25 -0
- package/src/utils/notes-status.md +92 -0
- package/src/utils/pageGeometry/ConvexPoly.ts +34 -0
- package/src/utils/pageGeometry/Point.ts +51 -0
- package/src/utils/pageGeometry/PolyWithPoints.ts +52 -0
- package/src/utils/pageGeometry/Rectangle.ts +98 -0
- package/src/utils/pageGeometry/Triangle.ts +16 -0
- package/src/utils/pageGeometry/alignment/index.ts +221 -0
- package/src/utils/pageGeometry/polyContainsPoint.ts +182 -0
- package/src/utils/pageGeometry/types.ts +3 -0
- package/src/utils/proxyFnCall.ts +46 -0
- package/src/utils/raf.ts +13 -0
- package/src/utils/selectParent.ts +18 -0
- package/src/utils/shallowEqualObjects.ts +49 -0
- package/src/utils/stripVar.ts +3 -0
- package/src/utils/toUpperFirst.ts +5 -0
- package/todo.md +2 -0
- package/tsconfig.build.json +8 -0
- package/tsconfig.dev.json +7 -0
- package/tsconfig.json +30 -0
- package/tsconfig.typebundler.json +13 -0
- package/typedoc.json +4 -0
- package/README.md +0 -104
- package/index.css +0 -857
- package/index.d.ts +0 -2111
- package/index.esm.css +0 -857
- package/index.esm.js +0 -13695
- package/index.js +0 -13565
|
@@ -0,0 +1,1516 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { RefCallback } from 'react';
|
|
3
|
+
|
|
4
|
+
import { Logger } from '../../utils/debug';
|
|
5
|
+
import { arrayIntersection } from '../../utils/mathIntersection';
|
|
6
|
+
import { raf } from '../../utils/raf';
|
|
7
|
+
import { stripVar } from '../../utils/stripVar';
|
|
8
|
+
import { InternalVars } from '../InfiniteTable/theme.css';
|
|
9
|
+
import { ScrollAdjustPosition } from '../InfiniteTable/types/InfiniteTableProps';
|
|
10
|
+
import {
|
|
11
|
+
getParentInfiniteNode,
|
|
12
|
+
setInfiniteScrollPosition,
|
|
13
|
+
} from '../InfiniteTable/utils/infiniteDOMUtils';
|
|
14
|
+
import { AvoidReactDiff } from '../RawList/AvoidReactDiff';
|
|
15
|
+
import { Renderable } from '../types/Renderable';
|
|
16
|
+
import { ScrollPosition } from '../types/ScrollPosition';
|
|
17
|
+
import { SubscriptionCallback } from '../types/SubscriptionCallback';
|
|
18
|
+
import { buildSubscriptionCallback } from '../utils/buildSubscriptionCallback';
|
|
19
|
+
import {
|
|
20
|
+
FixedPosition,
|
|
21
|
+
getRenderRangeCellCount,
|
|
22
|
+
MatrixBrain,
|
|
23
|
+
TableRenderRange,
|
|
24
|
+
} from '../VirtualBrain/MatrixBrain';
|
|
25
|
+
|
|
26
|
+
import { MappedCells } from './MappedCells';
|
|
27
|
+
|
|
28
|
+
export type TableRenderCellFnParam = {
|
|
29
|
+
domRef: RefCallback<HTMLElement>;
|
|
30
|
+
rowIndex: number;
|
|
31
|
+
colIndex: number;
|
|
32
|
+
rowspan: number;
|
|
33
|
+
colspan: number;
|
|
34
|
+
hidden: boolean;
|
|
35
|
+
width: number;
|
|
36
|
+
height: number;
|
|
37
|
+
widthWithColspan: number;
|
|
38
|
+
heightWithRowspan: number;
|
|
39
|
+
rowFixed: FixedPosition;
|
|
40
|
+
colFixed: FixedPosition;
|
|
41
|
+
onMouseEnter: VoidFunction;
|
|
42
|
+
onMouseLeave: VoidFunction;
|
|
43
|
+
};
|
|
44
|
+
export type TableRenderCellFn = (param: TableRenderCellFnParam) => Renderable;
|
|
45
|
+
|
|
46
|
+
export type RenderableWithPosition = {
|
|
47
|
+
renderable: Renderable;
|
|
48
|
+
position: 'start' | 'end' | null;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const ITEM_POSITION_WITH_TRANSFORM = true;
|
|
52
|
+
|
|
53
|
+
const currentColumnTransformY = stripVar(InternalVars.currentColumnTransformY);
|
|
54
|
+
|
|
55
|
+
const scrollTopCSSVar = stripVar(InternalVars.scrollTop);
|
|
56
|
+
const columnOffsetAtIndex = stripVar(InternalVars.columnOffsetAtIndex);
|
|
57
|
+
const columnOffsetAtIndexWhileReordering = stripVar(
|
|
58
|
+
InternalVars.columnOffsetAtIndexWhileReordering,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export class ReactHeadlessTableRenderer extends Logger {
|
|
62
|
+
private brain: MatrixBrain;
|
|
63
|
+
|
|
64
|
+
private destroyed = false;
|
|
65
|
+
private scrolling = false;
|
|
66
|
+
|
|
67
|
+
public cellHoverClassNames: string[] = [];
|
|
68
|
+
|
|
69
|
+
public name: string = '';
|
|
70
|
+
|
|
71
|
+
private itemDOMElements: (HTMLElement | null)[] = [];
|
|
72
|
+
private itemDOMRefs: RefCallback<HTMLElement>[] = [];
|
|
73
|
+
private updaters: SubscriptionCallback<Renderable>[] = [];
|
|
74
|
+
|
|
75
|
+
private mappedCells: MappedCells;
|
|
76
|
+
|
|
77
|
+
private items: Renderable[] = [];
|
|
78
|
+
|
|
79
|
+
private currentHoveredRow = -1;
|
|
80
|
+
private onDestroy: VoidFunction;
|
|
81
|
+
|
|
82
|
+
private hoverRowUpdatesInProgress: Map<number, boolean> = new Map();
|
|
83
|
+
private infiniteNode: HTMLElement | null = null;
|
|
84
|
+
|
|
85
|
+
private getInfiniteNode(node: HTMLElement) {
|
|
86
|
+
if (!this.infiniteNode) {
|
|
87
|
+
this.infiniteNode = getParentInfiniteNode(node);
|
|
88
|
+
}
|
|
89
|
+
return this.infiniteNode!;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
setTransform = (
|
|
93
|
+
element: HTMLElement,
|
|
94
|
+
_rowIndex: number,
|
|
95
|
+
colIndex: number,
|
|
96
|
+
|
|
97
|
+
{
|
|
98
|
+
//@ts-ignore
|
|
99
|
+
x,
|
|
100
|
+
y,
|
|
101
|
+
//@ts-ignore
|
|
102
|
+
scrollLeft,
|
|
103
|
+
scrollTop,
|
|
104
|
+
}: { x: number; y: number; scrollLeft?: boolean; scrollTop?: boolean },
|
|
105
|
+
zIndex: number | 'auto' | undefined | null,
|
|
106
|
+
) => {
|
|
107
|
+
const columnOffsetX = `${columnOffsetAtIndex}-${colIndex}`;
|
|
108
|
+
const columnOffsetXWhileReordering = `${columnOffsetAtIndexWhileReordering}-${colIndex}`;
|
|
109
|
+
// const columnZIndex = `${columnZIndexAtIndex}-${colIndex}`;
|
|
110
|
+
|
|
111
|
+
// const infiniteNode = this.getInfiniteNode(element);
|
|
112
|
+
|
|
113
|
+
// TODO this would be needed if it were not managed by the grid/table component
|
|
114
|
+
// infiniteNode.style.setProperty(
|
|
115
|
+
// columnOffsetX,
|
|
116
|
+
// scrollLeft ? `calc( ${x}px + var(${scrollLeftCSSVar}) )` : `${x}px`,
|
|
117
|
+
// );
|
|
118
|
+
element.style.setProperty(
|
|
119
|
+
currentColumnTransformY,
|
|
120
|
+
scrollTop ? `calc( ${y}px + var(${scrollTopCSSVar}) )` : `${y}px`,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// this does not change, but we need for initial setup
|
|
124
|
+
element.style.transform = `translate3d(var(${columnOffsetXWhileReordering}, var(${columnOffsetX})), ${InternalVars.currentColumnTransformY}, 0)`;
|
|
125
|
+
|
|
126
|
+
if (zIndex != null) {
|
|
127
|
+
// TODO this would be needed if zIndex would not be managed in grid
|
|
128
|
+
// this.infiniteNode!.style.setProperty(columnZIndex, `${zIndex}`);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
constructor(brain: MatrixBrain) {
|
|
133
|
+
super('ReactHeadlessTableRenderer');
|
|
134
|
+
this.brain = brain;
|
|
135
|
+
|
|
136
|
+
this.mappedCells = new MappedCells();
|
|
137
|
+
|
|
138
|
+
const removeOnScroll = brain.onScroll(this.adjustFixedElementsOnScroll);
|
|
139
|
+
const removeOnSizeChange = brain.onAvailableSizeChange(() => {
|
|
140
|
+
this.adjustFixedElementsOnScroll();
|
|
141
|
+
//for whatever reason, sometimes there's a misplaced fixed cell and we need to
|
|
142
|
+
//have it executed again, on a raf
|
|
143
|
+
raf(() => {
|
|
144
|
+
if (this.destroyed) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
this.adjustFixedElementsOnScroll();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
const removeOnScrollStart = brain.onScrollStart(this.onScrollStart);
|
|
151
|
+
const removeOnScrollStop = brain.onScrollStop(this.onScrollStop);
|
|
152
|
+
|
|
153
|
+
this.onDestroy = () => {
|
|
154
|
+
removeOnScroll();
|
|
155
|
+
removeOnSizeChange();
|
|
156
|
+
removeOnScrollStart();
|
|
157
|
+
removeOnScrollStop();
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public getFullyVisibleRowsRange = () => {
|
|
162
|
+
let {
|
|
163
|
+
start: [startRow],
|
|
164
|
+
end: [endRow],
|
|
165
|
+
} = this.brain.getRenderRange();
|
|
166
|
+
|
|
167
|
+
while (!this.isRowFullyVisible(startRow)) {
|
|
168
|
+
startRow++;
|
|
169
|
+
|
|
170
|
+
if (startRow === endRow) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
while (!this.isRowFullyVisible(endRow)) {
|
|
175
|
+
endRow--;
|
|
176
|
+
|
|
177
|
+
if (endRow === startRow) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { start: startRow, end: endRow };
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
public getScrollPositionForScrollRowIntoView = (
|
|
186
|
+
rowIndex: number,
|
|
187
|
+
config: {
|
|
188
|
+
scrollAdjustPosition?: ScrollAdjustPosition;
|
|
189
|
+
offset?: number;
|
|
190
|
+
} = { offset: 0 },
|
|
191
|
+
): ScrollPosition | null => {
|
|
192
|
+
if (this.destroyed) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
const { brain } = this;
|
|
196
|
+
const scrollPosition = brain.getScrollPosition();
|
|
197
|
+
let { scrollAdjustPosition, offset = 0 } = config;
|
|
198
|
+
if (this.isRowFullyVisible(rowIndex) && !scrollAdjustPosition) {
|
|
199
|
+
return scrollPosition;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const rowOffset = brain.getItemOffsetFor(rowIndex, 'vertical');
|
|
203
|
+
const rowHeight = brain.getItemSize(rowIndex, 'vertical');
|
|
204
|
+
|
|
205
|
+
const fixedStartRowsHeight = brain.getFixedStartRowsHeight();
|
|
206
|
+
const fixedEndRowsHeight = brain.getFixedEndRowsHeight();
|
|
207
|
+
|
|
208
|
+
const top = scrollPosition.scrollTop;
|
|
209
|
+
|
|
210
|
+
const availableSize = brain.getAvailableSize();
|
|
211
|
+
|
|
212
|
+
if (!availableSize.height) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const bottom = top + availableSize.height;
|
|
216
|
+
|
|
217
|
+
if (!scrollAdjustPosition) {
|
|
218
|
+
scrollAdjustPosition =
|
|
219
|
+
rowOffset > bottom - fixedEndRowsHeight
|
|
220
|
+
? 'end'
|
|
221
|
+
: rowOffset < top + fixedStartRowsHeight
|
|
222
|
+
? 'start'
|
|
223
|
+
: 'end';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let scrollTop = scrollPosition.scrollTop;
|
|
227
|
+
if (scrollAdjustPosition === 'center') {
|
|
228
|
+
scrollTop =
|
|
229
|
+
rowOffset -
|
|
230
|
+
Math.floor(
|
|
231
|
+
(brain.getAvailableSize().height -
|
|
232
|
+
fixedStartRowsHeight -
|
|
233
|
+
fixedEndRowsHeight) /
|
|
234
|
+
2,
|
|
235
|
+
);
|
|
236
|
+
} else if (scrollAdjustPosition === 'start') {
|
|
237
|
+
offset = -offset;
|
|
238
|
+
scrollTop += rowOffset - top + offset - fixedStartRowsHeight;
|
|
239
|
+
} else {
|
|
240
|
+
offset += rowHeight;
|
|
241
|
+
scrollTop += rowOffset - bottom + offset + fixedEndRowsHeight;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
...scrollPosition,
|
|
246
|
+
scrollTop,
|
|
247
|
+
};
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
public getScrollPositionForScrollColumnIntoView = (
|
|
251
|
+
colIndex: number,
|
|
252
|
+
config: {
|
|
253
|
+
scrollAdjustPosition?: ScrollAdjustPosition;
|
|
254
|
+
offset?: number;
|
|
255
|
+
} = { offset: 0 },
|
|
256
|
+
): ScrollPosition | null => {
|
|
257
|
+
if (this.destroyed) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const { brain } = this;
|
|
261
|
+
const scrollPosition = brain.getScrollPosition();
|
|
262
|
+
let { scrollAdjustPosition, offset = 0 } = config;
|
|
263
|
+
if (this.isColumnFullyVisible(colIndex) && !scrollAdjustPosition) {
|
|
264
|
+
return scrollPosition;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const colOffset = brain.getItemOffsetFor(colIndex, 'horizontal');
|
|
268
|
+
const colWidth = brain.getItemSize(colIndex, 'horizontal');
|
|
269
|
+
|
|
270
|
+
const fixedStartColsWidth = brain.getFixedStartColsWidth();
|
|
271
|
+
const fixedEndColsWidth = brain.getFixedStartColsWidth();
|
|
272
|
+
|
|
273
|
+
const left = scrollPosition.scrollLeft;
|
|
274
|
+
|
|
275
|
+
const availableSize = brain.getAvailableSize();
|
|
276
|
+
|
|
277
|
+
if (!availableSize.width) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const right = left + availableSize.width;
|
|
281
|
+
|
|
282
|
+
if (!scrollAdjustPosition) {
|
|
283
|
+
scrollAdjustPosition =
|
|
284
|
+
colOffset > right - fixedEndColsWidth
|
|
285
|
+
? 'end'
|
|
286
|
+
: colOffset < left + fixedStartColsWidth
|
|
287
|
+
? 'start'
|
|
288
|
+
: 'end';
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
let scrollLeft = scrollPosition.scrollLeft;
|
|
292
|
+
if (scrollAdjustPosition === 'center') {
|
|
293
|
+
scrollLeft =
|
|
294
|
+
colOffset -
|
|
295
|
+
Math.floor(
|
|
296
|
+
(brain.getAvailableSize().width -
|
|
297
|
+
fixedStartColsWidth -
|
|
298
|
+
fixedEndColsWidth) /
|
|
299
|
+
2,
|
|
300
|
+
);
|
|
301
|
+
} else if (scrollAdjustPosition === 'start') {
|
|
302
|
+
offset = -offset;
|
|
303
|
+
scrollLeft += colOffset - left + offset - fixedStartColsWidth;
|
|
304
|
+
} else {
|
|
305
|
+
offset += colWidth;
|
|
306
|
+
scrollLeft += colOffset - right + offset + fixedEndColsWidth;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
...scrollPosition,
|
|
311
|
+
scrollLeft,
|
|
312
|
+
};
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
public getScrollPositionForScrollCellIntoView = (
|
|
316
|
+
rowIndex: number,
|
|
317
|
+
colIndex: number,
|
|
318
|
+
config: {
|
|
319
|
+
rowScrollAdjustPosition?: ScrollAdjustPosition;
|
|
320
|
+
colScrollAdjustPosition?: ScrollAdjustPosition;
|
|
321
|
+
scrollAdjustPosition?: ScrollAdjustPosition;
|
|
322
|
+
offsetTop: number;
|
|
323
|
+
offsetLeft: number;
|
|
324
|
+
} = { offsetLeft: 0, offsetTop: 0 },
|
|
325
|
+
): ScrollPosition | null => {
|
|
326
|
+
if (this.destroyed) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
const scrollPosForCol = this.getScrollPositionForScrollColumnIntoView(
|
|
330
|
+
colIndex,
|
|
331
|
+
{
|
|
332
|
+
scrollAdjustPosition:
|
|
333
|
+
config.colScrollAdjustPosition || config.scrollAdjustPosition,
|
|
334
|
+
offset: config.offsetLeft,
|
|
335
|
+
},
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
const scrollPosForRow = this.getScrollPositionForScrollRowIntoView(
|
|
339
|
+
rowIndex,
|
|
340
|
+
{
|
|
341
|
+
scrollAdjustPosition:
|
|
342
|
+
config.rowScrollAdjustPosition || config.scrollAdjustPosition,
|
|
343
|
+
offset: config.offsetTop,
|
|
344
|
+
},
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
if (!scrollPosForCol || !scrollPosForRow) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const { scrollLeft } = scrollPosForCol;
|
|
352
|
+
const { scrollTop } = scrollPosForRow;
|
|
353
|
+
|
|
354
|
+
return { scrollLeft, scrollTop };
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
public isRowFullyVisible = (rowIndex: number, offsetMargin = 2) => {
|
|
358
|
+
return this.isRowVisible(
|
|
359
|
+
rowIndex,
|
|
360
|
+
this.brain.getRowHeight(rowIndex) - offsetMargin,
|
|
361
|
+
);
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
public isRowVisible = (rowIndex: number, offsetMargin = 10) => {
|
|
365
|
+
if (!this.isRowRendered(rowIndex)) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const { brain } = this;
|
|
370
|
+
|
|
371
|
+
if (brain.isRowFixed(rowIndex)) {
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const {
|
|
376
|
+
start: [startRow],
|
|
377
|
+
end: [endRow],
|
|
378
|
+
} = this.brain.getRenderRange();
|
|
379
|
+
|
|
380
|
+
const midRow = Math.floor((startRow + endRow) / 2);
|
|
381
|
+
|
|
382
|
+
if (rowIndex < startRow) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
if (rowIndex >= endRow) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (rowIndex >= midRow) {
|
|
390
|
+
const lastVisibleRow = brain.getItemAt(
|
|
391
|
+
brain.getAvailableSize().height +
|
|
392
|
+
brain.getScrollPosition().scrollTop -
|
|
393
|
+
offsetMargin,
|
|
394
|
+
'vertical',
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
return rowIndex <= lastVisibleRow;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (rowIndex < midRow) {
|
|
401
|
+
const firstVisibleRow = brain.getItemAt(
|
|
402
|
+
brain.getScrollPosition().scrollTop + offsetMargin,
|
|
403
|
+
'vertical',
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
return rowIndex >= firstVisibleRow;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return true;
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
public isRowRendered = (rowIndex: number) => {
|
|
413
|
+
const elements = this.mappedCells.getElementsForRowIndex(rowIndex);
|
|
414
|
+
|
|
415
|
+
return elements.length > 0;
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
public isCellVisible = (rowIndex: number, colIndex: number) => {
|
|
419
|
+
return this.isRowVisible(rowIndex) && this.isColumnVisible(colIndex);
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
public isCellFullyVisible = (rowIndex: number, colIndex: number) => {
|
|
423
|
+
return this.isRowFullyVisible(rowIndex) && this.isColumnVisible(colIndex);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
public isColumnFullyVisible = (colIndex: number, offsetMargin = 2) => {
|
|
427
|
+
return this.isColumnVisible(
|
|
428
|
+
colIndex,
|
|
429
|
+
this.brain.getColWidth(colIndex) - offsetMargin,
|
|
430
|
+
);
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
public isColumnVisible = (colIndex: number, offsetMargin = 10) => {
|
|
434
|
+
if (!this.isColumnRendered(colIndex)) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const { brain } = this;
|
|
439
|
+
|
|
440
|
+
if (brain.isColFixed(colIndex)) {
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const {
|
|
445
|
+
start: [_, startCol],
|
|
446
|
+
end: [__, endCol],
|
|
447
|
+
} = brain.getRenderRange();
|
|
448
|
+
|
|
449
|
+
if (colIndex < startCol) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
if (colIndex >= endCol) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const midCol = Math.floor((startCol + endCol) / 2);
|
|
457
|
+
|
|
458
|
+
if (colIndex >= midCol) {
|
|
459
|
+
const lastVisibleCol = brain.getItemAt(
|
|
460
|
+
brain.getAvailableSize().width +
|
|
461
|
+
brain.getScrollPosition().scrollLeft -
|
|
462
|
+
offsetMargin -
|
|
463
|
+
brain.getFixedEndColsWidth(),
|
|
464
|
+
'horizontal',
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
return colIndex <= lastVisibleCol;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (colIndex < midCol) {
|
|
471
|
+
const firstVisibleCol = brain.getItemAt(
|
|
472
|
+
brain.getScrollPosition().scrollLeft +
|
|
473
|
+
offsetMargin +
|
|
474
|
+
brain.getFixedStartColsWidth(),
|
|
475
|
+
'horizontal',
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
return colIndex >= firstVisibleCol;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return true;
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
public isCellRendered = (rowIndex: number, colIndex: number) => {
|
|
485
|
+
return this.isRowRendered(rowIndex) && this.isColumnRendered(colIndex);
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
public isColumnRendered = (colIndex: number) => {
|
|
489
|
+
const {
|
|
490
|
+
start: [startRow],
|
|
491
|
+
} = this.brain.getRenderRange();
|
|
492
|
+
|
|
493
|
+
return this.mappedCells.getRenderedNodeForCell(startRow, colIndex) !== null;
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
getExtraSpanCellsForRange = (range: TableRenderRange) => {
|
|
497
|
+
const { start, end } = range;
|
|
498
|
+
const [startRow, startCol] = start;
|
|
499
|
+
const [endRow, endCol] = end;
|
|
500
|
+
|
|
501
|
+
return this.brain.getExtraSpanCellsForRange({
|
|
502
|
+
horizontal: { startIndex: startCol, endIndex: endCol },
|
|
503
|
+
vertical: { startIndex: startRow, endIndex: endRow },
|
|
504
|
+
});
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
renderRange = (
|
|
508
|
+
range: TableRenderRange,
|
|
509
|
+
|
|
510
|
+
{
|
|
511
|
+
renderCell,
|
|
512
|
+
force,
|
|
513
|
+
onRender,
|
|
514
|
+
}: {
|
|
515
|
+
force?: boolean;
|
|
516
|
+
renderCell: TableRenderCellFn;
|
|
517
|
+
onRender: (items: Renderable[]) => void;
|
|
518
|
+
},
|
|
519
|
+
): Renderable[] => {
|
|
520
|
+
if (this.destroyed) {
|
|
521
|
+
return [];
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const { start, end } = range;
|
|
525
|
+
|
|
526
|
+
if (__DEV__) {
|
|
527
|
+
this.debug(`Render range ${start}-${end}. Force ${force}`);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const { mappedCells } = this;
|
|
531
|
+
|
|
532
|
+
const fixedRanges = this.getFixedRanges(range);
|
|
533
|
+
const ranges = [range, ...fixedRanges];
|
|
534
|
+
|
|
535
|
+
const extraCellsMap = new Map<string, boolean>();
|
|
536
|
+
const extraCells = ranges.map(this.getExtraSpanCellsForRange).flat();
|
|
537
|
+
/**
|
|
538
|
+
* We can have some extra cells outside the render range that should still
|
|
539
|
+
* be visible (even though they are outside). This is due to row/col spanning.
|
|
540
|
+
*
|
|
541
|
+
* All cells from the extra cells are cells outside the render range
|
|
542
|
+
* that span and cover cells from either the first row or the first column
|
|
543
|
+
* in the render range
|
|
544
|
+
*
|
|
545
|
+
* here we build a map for faster accessing
|
|
546
|
+
*/
|
|
547
|
+
if (extraCells) {
|
|
548
|
+
extraCells.forEach(([rowIndex, colIndex]) => {
|
|
549
|
+
extraCellsMap.set(`${rowIndex}:${colIndex}`, true);
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* the render count is always the rows times cols that are inside the viewport
|
|
555
|
+
* and is not modified by row or column spanning
|
|
556
|
+
*/
|
|
557
|
+
const renderCount = ranges.reduce(
|
|
558
|
+
(sum, range) => sum + getRenderRangeCellCount(range),
|
|
559
|
+
0,
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
// renderCount += 4;
|
|
563
|
+
|
|
564
|
+
// const { fixedRowsStart, fixedColsStart, fixedRowsEnd, fixedColsEnd } =
|
|
565
|
+
// this.brain.getFixedCellInfo();
|
|
566
|
+
|
|
567
|
+
// console.log(ranges, renderCount);
|
|
568
|
+
|
|
569
|
+
// if (fixedRowsStart && fixedColsStart) {
|
|
570
|
+
// // renderCount -= fixedRowsStart * fixedColsStart;
|
|
571
|
+
// }
|
|
572
|
+
// if (fixedRowsStart && fixedColsEnd) {
|
|
573
|
+
// // renderCount -= fixedRowsStart * fixedColsEnd;
|
|
574
|
+
// }
|
|
575
|
+
// if (fixedRowsEnd && fixedColsStart) {
|
|
576
|
+
// // renderCount -= fixedRowsEnd * fixedColsStart;
|
|
577
|
+
// }
|
|
578
|
+
// if (fixedRowsEnd && fixedColsEnd) {
|
|
579
|
+
// // renderCount -= fixedRowsEnd * fixedColsEnd;
|
|
580
|
+
// }
|
|
581
|
+
|
|
582
|
+
if (this.itemDOMElements.length >= renderCount) {
|
|
583
|
+
mappedCells.discardElementsStartingWith(renderCount, (elementIndex) => {
|
|
584
|
+
// when less items become rendered
|
|
585
|
+
// we unmount the extra items by calling destroy on the updater
|
|
586
|
+
// so we don't need to re-render the whole container
|
|
587
|
+
if (this.updaters[elementIndex]) {
|
|
588
|
+
this.updaters[elementIndex].destroy();
|
|
589
|
+
}
|
|
590
|
+
if (__DEV__) {
|
|
591
|
+
// console.log(`Discard element ${elementIndex}`);
|
|
592
|
+
this.debug(`Discard element ${elementIndex}`);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
this.itemDOMElements.length = Math.min(
|
|
596
|
+
this.itemDOMElements.length,
|
|
597
|
+
renderCount,
|
|
598
|
+
);
|
|
599
|
+
this.itemDOMRefs.length = Math.min(this.itemDOMRefs.length, renderCount);
|
|
600
|
+
this.updaters.length = Math.min(this.updaters.length, renderCount);
|
|
601
|
+
this.items.length = Math.min(this.items.length, renderCount);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// we only need to keep those that are outside all ranges
|
|
605
|
+
// so we need to do an intersection of all those elements
|
|
606
|
+
const elementsOutsideRanges: number[] = arrayIntersection(
|
|
607
|
+
...ranges.map(mappedCells.getElementsOutsideRenderRange),
|
|
608
|
+
);
|
|
609
|
+
|
|
610
|
+
const elementsOutsideItemRange = elementsOutsideRanges.filter(
|
|
611
|
+
(elementIndex) => {
|
|
612
|
+
const cell = this.mappedCells.getRenderedCellAtElement(elementIndex);
|
|
613
|
+
|
|
614
|
+
// keep those elements that host a cell that is in the extraCells map
|
|
615
|
+
// We do this in order not to do extra work and rerender it later in case
|
|
616
|
+
// it's already rendered
|
|
617
|
+
//
|
|
618
|
+
// so we need to filter those elements out
|
|
619
|
+
if (cell && extraCellsMap.has(`${cell[0]}:${cell[1]}`)) {
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// and only keep those elements that correspond to cells
|
|
624
|
+
// outside the render range and outside the extra cells
|
|
625
|
+
return true;
|
|
626
|
+
},
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
if (this.items.length > renderCount) {
|
|
630
|
+
this.items.length = renderCount;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// start from the last rendered, and render additional elements, until we have renderCount
|
|
634
|
+
// this loop might not even execute the body once if all the elements are present
|
|
635
|
+
for (let i = this.items.length; i < renderCount; i++) {
|
|
636
|
+
this.renderElement(i);
|
|
637
|
+
// push at start
|
|
638
|
+
elementsOutsideItemRange.splice(0, 0, i);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const visitedCells = new Map<string, boolean>();
|
|
642
|
+
|
|
643
|
+
ranges.forEach((range) => {
|
|
644
|
+
const { start, end } = range;
|
|
645
|
+
const [startRow, startCol] = start;
|
|
646
|
+
const [endRow, endCol] = end;
|
|
647
|
+
|
|
648
|
+
for (let row = startRow; row < endRow; row++) {
|
|
649
|
+
for (let col = startCol; col < endCol; col++) {
|
|
650
|
+
const key = `${row}:${col}`;
|
|
651
|
+
if (visitedCells.has(key)) {
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
visitedCells.set(key, true);
|
|
655
|
+
const cellRendered = mappedCells.isCellRendered(row, col);
|
|
656
|
+
|
|
657
|
+
// for cells that belong to the first row of the render range
|
|
658
|
+
// or to the first column of the render range
|
|
659
|
+
// if they are "covered" (spanned by) by previous cells
|
|
660
|
+
// those cells we want to "throw" away and instead of them
|
|
661
|
+
// we render the spanning cell
|
|
662
|
+
// all other spanned cells (further below or to the right), we keep as rendered
|
|
663
|
+
// we do this in order to preserve a constant renderCount
|
|
664
|
+
if (row === startRow || col === startCol) {
|
|
665
|
+
const parentCell = this.isCellCovered(row, col);
|
|
666
|
+
|
|
667
|
+
// if this cell is covered by another (parent) cell
|
|
668
|
+
// which is outside of the render range (so which is in the extra cells collection)
|
|
669
|
+
if (
|
|
670
|
+
parentCell &&
|
|
671
|
+
extraCellsMap.has(`${parentCell[0]}:${parentCell[1]}`)
|
|
672
|
+
) {
|
|
673
|
+
// then we can take that element and reuse it
|
|
674
|
+
// for other cells
|
|
675
|
+
const elIndexForCoveredCell = mappedCells.getElementIndexForCell(
|
|
676
|
+
row,
|
|
677
|
+
col,
|
|
678
|
+
);
|
|
679
|
+
|
|
680
|
+
if (elIndexForCoveredCell != null) {
|
|
681
|
+
elementsOutsideItemRange.push(elIndexForCoveredCell);
|
|
682
|
+
}
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (cellRendered && !force) {
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const elementIndex = cellRendered
|
|
692
|
+
? mappedCells.getElementIndexForCell(row, col)
|
|
693
|
+
: mappedCells.getElementFromListForColumn(
|
|
694
|
+
elementsOutsideItemRange,
|
|
695
|
+
col,
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
if (elementIndex == null) {
|
|
699
|
+
if (__DEV__) {
|
|
700
|
+
this.error(`Cannot find element to render cell ${row}:${col}`);
|
|
701
|
+
}
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
this.renderCellAtElement(row, col, elementIndex, renderCell);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
extraCells.forEach(([rowIndex, colIndex]) => {
|
|
711
|
+
if (mappedCells.isCellRendered(rowIndex, colIndex)) {
|
|
712
|
+
if (force) {
|
|
713
|
+
const elementIndex = mappedCells.getElementIndexForCell(
|
|
714
|
+
rowIndex,
|
|
715
|
+
colIndex,
|
|
716
|
+
)!;
|
|
717
|
+
this.renderCellAtElement(
|
|
718
|
+
rowIndex,
|
|
719
|
+
colIndex,
|
|
720
|
+
elementIndex,
|
|
721
|
+
renderCell,
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const elementIndex = elementsOutsideItemRange.pop();
|
|
728
|
+
if (elementIndex == null) {
|
|
729
|
+
if (__DEV__) {
|
|
730
|
+
this.error(
|
|
731
|
+
`Cannot find element to render cell ${rowIndex}-${colIndex}`,
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
this.renderCellAtElement(rowIndex, colIndex, elementIndex, renderCell);
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
// OLD we need to spread and create a new array
|
|
740
|
+
// OLD as otherwise the AvoidReactDiff component will receive the same array
|
|
741
|
+
// OLD and since it uses setState internally, it will not render/update
|
|
742
|
+
// const result = [...this.items];
|
|
743
|
+
let result = this.items;
|
|
744
|
+
|
|
745
|
+
// TODO why does this optimisation not work
|
|
746
|
+
// if (this.items.length > this.prevLength) {
|
|
747
|
+
// // only assign and do a render when
|
|
748
|
+
// // we have more items than last time
|
|
749
|
+
// // so we need to show new items
|
|
750
|
+
result = [...this.items];
|
|
751
|
+
|
|
752
|
+
this.adjustFixedElementsOnScroll();
|
|
753
|
+
if (onRender) {
|
|
754
|
+
onRender(result);
|
|
755
|
+
}
|
|
756
|
+
// this.prevLength = result.length;
|
|
757
|
+
// }
|
|
758
|
+
|
|
759
|
+
return result;
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
private renderElement(elementIndex: number) {
|
|
763
|
+
const domRef = (node: HTMLElement | null) => {
|
|
764
|
+
if (node) {
|
|
765
|
+
this.itemDOMElements[elementIndex] = node;
|
|
766
|
+
node.style.position = 'absolute';
|
|
767
|
+
node.style.left = '0px';
|
|
768
|
+
node.style.top = '0px';
|
|
769
|
+
this.updateElementPosition(elementIndex);
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
this.itemDOMRefs[elementIndex] = domRef;
|
|
773
|
+
this.updaters[elementIndex] = buildSubscriptionCallback<Renderable>();
|
|
774
|
+
|
|
775
|
+
const item = (
|
|
776
|
+
<AvoidReactDiff
|
|
777
|
+
key={elementIndex}
|
|
778
|
+
name={`${elementIndex}`}
|
|
779
|
+
updater={this.updaters[elementIndex]}
|
|
780
|
+
/>
|
|
781
|
+
);
|
|
782
|
+
this.items[elementIndex] = item;
|
|
783
|
+
|
|
784
|
+
return item;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
getFixedRanges = (
|
|
788
|
+
currentRenderRange: TableRenderRange,
|
|
789
|
+
): TableRenderRange[] => {
|
|
790
|
+
const { fixedRowsStart, fixedRowsEnd, fixedColsStart, fixedColsEnd } =
|
|
791
|
+
this.brain.getFixedCellInfo();
|
|
792
|
+
if (!fixedRowsStart && !fixedColsStart && !fixedRowsEnd && !fixedColsEnd) {
|
|
793
|
+
return [];
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* The current range includes all non-fixed cells in the viewport
|
|
797
|
+
*
|
|
798
|
+
* So for example, if we have 10x10 (10 rows and 10 cols), with
|
|
799
|
+
* fixed rows start = 2
|
|
800
|
+
* fixed rows end = 2
|
|
801
|
+
* fixed cols start = 2
|
|
802
|
+
* fixed cols end = 2
|
|
803
|
+
*
|
|
804
|
+
* then the current range will be [2, 2] to [8, 8]
|
|
805
|
+
*
|
|
806
|
+
*
|
|
807
|
+
*
|
|
808
|
+
*/
|
|
809
|
+
const colCount = this.brain.getColCount();
|
|
810
|
+
const rowCount = this.brain.getRowCount();
|
|
811
|
+
|
|
812
|
+
const { start, end } = currentRenderRange;
|
|
813
|
+
const [startRow, startCol] = start;
|
|
814
|
+
const [endRow, endCol] = end;
|
|
815
|
+
|
|
816
|
+
const arr: TableRenderRange[] = [];
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* *--*-----*--*
|
|
820
|
+
* | 1| 2 |3 |
|
|
821
|
+
* *--*-----*--*
|
|
822
|
+
* | | | |
|
|
823
|
+
* |4 | 5 |6 |
|
|
824
|
+
* *--*-----*--*
|
|
825
|
+
* |7 |8 |9 |
|
|
826
|
+
* *--*-----*--*
|
|
827
|
+
*/
|
|
828
|
+
|
|
829
|
+
if (fixedColsStart) {
|
|
830
|
+
/**
|
|
831
|
+
* if we have overlap, both cols fixed at start AND rows fixed at start and end
|
|
832
|
+
*
|
|
833
|
+
* then for this if-branch, we push to the resulting array
|
|
834
|
+
* both 1, 4 and 7
|
|
835
|
+
*
|
|
836
|
+
* and when we'll get to fixedRowsStart, we'll only push 2 there
|
|
837
|
+
* and when we'll get to fixedRowsEnd, we'll only push 8 there
|
|
838
|
+
*
|
|
839
|
+
*
|
|
840
|
+
*/
|
|
841
|
+
if (fixedRowsStart) {
|
|
842
|
+
// range 1
|
|
843
|
+
arr.push({
|
|
844
|
+
rowFixed: 'start',
|
|
845
|
+
colFixed: 'start',
|
|
846
|
+
start: [0, 0],
|
|
847
|
+
end: [fixedRowsStart, fixedColsStart],
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
if (fixedRowsEnd) {
|
|
851
|
+
// range 7
|
|
852
|
+
arr.push({
|
|
853
|
+
rowFixed: 'end',
|
|
854
|
+
colFixed: 'start',
|
|
855
|
+
start: [rowCount - fixedRowsEnd, 0],
|
|
856
|
+
end: [rowCount, fixedColsStart],
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
// range 4
|
|
860
|
+
arr.push({
|
|
861
|
+
rowFixed: false,
|
|
862
|
+
colFixed: 'start',
|
|
863
|
+
start: [startRow, 0],
|
|
864
|
+
end: [endRow, fixedColsStart],
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
if (fixedColsEnd) {
|
|
868
|
+
/**
|
|
869
|
+
* if we have overlap, both cols fixed at end and rows fixed at start and end
|
|
870
|
+
*
|
|
871
|
+
* then for this if-branch, we push to the resulting array
|
|
872
|
+
* both 3, 6 and 9
|
|
873
|
+
*
|
|
874
|
+
* and when we'll get to fixedRowsStart, we'll only push 2 there
|
|
875
|
+
* and when we'll get to fixedRowsEnd, we'll only push 8 there
|
|
876
|
+
*
|
|
877
|
+
*/
|
|
878
|
+
if (fixedRowsStart) {
|
|
879
|
+
// range 3
|
|
880
|
+
arr.push({
|
|
881
|
+
colFixed: 'end',
|
|
882
|
+
rowFixed: 'start',
|
|
883
|
+
start: [0, colCount - fixedColsEnd],
|
|
884
|
+
end: [fixedRowsStart, colCount],
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
if (fixedRowsEnd) {
|
|
888
|
+
// range 9
|
|
889
|
+
arr.push({
|
|
890
|
+
colFixed: 'end',
|
|
891
|
+
rowFixed: 'end',
|
|
892
|
+
start: [rowCount - fixedRowsEnd, colCount - fixedColsEnd],
|
|
893
|
+
end: [rowCount, colCount],
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
// range 6
|
|
897
|
+
arr.push({
|
|
898
|
+
colFixed: 'end',
|
|
899
|
+
rowFixed: false,
|
|
900
|
+
start: [startRow, colCount - fixedColsEnd],
|
|
901
|
+
end: [endRow, colCount],
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
if (fixedRowsStart) {
|
|
906
|
+
/**
|
|
907
|
+
* If we have cols start and end, this will be only section 2
|
|
908
|
+
* otherwise, if we only have cols start, though we only push 1 range, it will include section 2 and 3
|
|
909
|
+
* and if we only have cols end, though we only push 1 range it will include section 1 and 2
|
|
910
|
+
* and if we have no fixed cols, this will be one range that inclues 1, 2 and 3
|
|
911
|
+
*/
|
|
912
|
+
const fixedRowsStartRange: TableRenderRange = {
|
|
913
|
+
start: [0, startCol],
|
|
914
|
+
end: [fixedRowsStart, endCol],
|
|
915
|
+
rowFixed: 'start',
|
|
916
|
+
colFixed: false,
|
|
917
|
+
};
|
|
918
|
+
arr.push(fixedRowsStartRange);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
if (fixedRowsEnd) {
|
|
922
|
+
/**
|
|
923
|
+
* Likewise for fixedRowsEnd
|
|
924
|
+
*/
|
|
925
|
+
const fixedRowsEndRange: TableRenderRange = {
|
|
926
|
+
rowFixed: 'end',
|
|
927
|
+
colFixed: false,
|
|
928
|
+
start: [rowCount - fixedRowsEnd, startCol],
|
|
929
|
+
end: [rowCount, endCol],
|
|
930
|
+
};
|
|
931
|
+
arr.push(fixedRowsEndRange);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
return arr;
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
private isCellFixed = (
|
|
938
|
+
rowIndex: number,
|
|
939
|
+
colIndex: number,
|
|
940
|
+
): { row: FixedPosition; col: FixedPosition } => {
|
|
941
|
+
const { fixedRowsStart, fixedRowsEnd, fixedColsStart, fixedColsEnd } =
|
|
942
|
+
this.brain.getFixedCellInfo();
|
|
943
|
+
|
|
944
|
+
const colCount = this.brain.getColCount();
|
|
945
|
+
const rowCount = this.brain.getRowCount();
|
|
946
|
+
|
|
947
|
+
let rowFixed = false;
|
|
948
|
+
let colFixed = false;
|
|
949
|
+
|
|
950
|
+
let pos: FixedPosition = false;
|
|
951
|
+
|
|
952
|
+
if (rowIndex < fixedRowsStart) {
|
|
953
|
+
rowFixed = true;
|
|
954
|
+
pos = 'start';
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
if (fixedRowsEnd && !rowFixed) {
|
|
958
|
+
const firstRowFixedEnd = rowCount - fixedRowsEnd;
|
|
959
|
+
if (rowIndex >= firstRowFixedEnd) {
|
|
960
|
+
rowFixed = true;
|
|
961
|
+
pos = 'end';
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
if (colIndex < fixedColsStart) {
|
|
966
|
+
colFixed = true;
|
|
967
|
+
pos = 'start';
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
if (fixedColsEnd && !colFixed) {
|
|
971
|
+
const firstColFixedEnd = colCount - fixedColsEnd;
|
|
972
|
+
|
|
973
|
+
if (colIndex >= firstColFixedEnd) {
|
|
974
|
+
colFixed = true;
|
|
975
|
+
pos = 'end';
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
return {
|
|
980
|
+
row: rowFixed ? pos : false,
|
|
981
|
+
col: colFixed ? pos : false,
|
|
982
|
+
};
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
private isCellCovered = (rowIndex: number, colIndex: number) => {
|
|
986
|
+
const rowspanParent = this.brain.getRowspanParent(rowIndex, colIndex);
|
|
987
|
+
const colspanParent = this.brain.getColspanParent(rowIndex, colIndex);
|
|
988
|
+
|
|
989
|
+
const coveredByAnotherRow = rowspanParent != rowIndex;
|
|
990
|
+
const coveredByAnotherCol = colspanParent != colIndex;
|
|
991
|
+
|
|
992
|
+
const covered = coveredByAnotherRow || coveredByAnotherCol;
|
|
993
|
+
|
|
994
|
+
return covered ? [rowspanParent, colspanParent] : false;
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
private renderCellAtElement(
|
|
998
|
+
rowIndex: number,
|
|
999
|
+
colIndex: number,
|
|
1000
|
+
elementIndex: number,
|
|
1001
|
+
renderCell: TableRenderCellFn,
|
|
1002
|
+
) {
|
|
1003
|
+
if (this.destroyed) {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
const covered = this.isCellCovered(rowIndex, colIndex);
|
|
1008
|
+
|
|
1009
|
+
const height = this.brain.getRowHeight(rowIndex);
|
|
1010
|
+
const width = this.brain.getColWidth(colIndex);
|
|
1011
|
+
|
|
1012
|
+
const rowspan = this.brain.getRowspan(rowIndex, colIndex);
|
|
1013
|
+
const colspan = this.brain.getColspan(rowIndex, colIndex);
|
|
1014
|
+
|
|
1015
|
+
const heightWithRowspan =
|
|
1016
|
+
rowspan === 1
|
|
1017
|
+
? height
|
|
1018
|
+
: this.brain.getRowHeightWithSpan(rowIndex, colIndex, rowspan);
|
|
1019
|
+
|
|
1020
|
+
const widthWithColspan =
|
|
1021
|
+
colspan === 1
|
|
1022
|
+
? width
|
|
1023
|
+
: this.brain.getColWidthWithSpan(rowIndex, colIndex, colspan);
|
|
1024
|
+
|
|
1025
|
+
const { row: rowFixed, col: colFixed } = this.isCellFixed(
|
|
1026
|
+
rowIndex,
|
|
1027
|
+
colIndex,
|
|
1028
|
+
);
|
|
1029
|
+
|
|
1030
|
+
const hidden = !!covered;
|
|
1031
|
+
|
|
1032
|
+
const renderedNode = renderCell({
|
|
1033
|
+
rowIndex,
|
|
1034
|
+
colIndex,
|
|
1035
|
+
height,
|
|
1036
|
+
width,
|
|
1037
|
+
rowspan,
|
|
1038
|
+
colspan,
|
|
1039
|
+
rowFixed,
|
|
1040
|
+
colFixed,
|
|
1041
|
+
hidden,
|
|
1042
|
+
heightWithRowspan,
|
|
1043
|
+
widthWithColspan,
|
|
1044
|
+
onMouseEnter: this.onMouseEnter.bind(null, rowIndex),
|
|
1045
|
+
onMouseLeave: this.onMouseLeave.bind(null, rowIndex),
|
|
1046
|
+
domRef: this.itemDOMRefs[elementIndex],
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
const itemUpdater = this.updaters[elementIndex];
|
|
1050
|
+
|
|
1051
|
+
if (!itemUpdater) {
|
|
1052
|
+
this.error(
|
|
1053
|
+
`Cannot find item updater for item ${rowIndex},${colIndex} at this time... sorry.`,
|
|
1054
|
+
);
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// console.log('render row', rowIndex);
|
|
1059
|
+
|
|
1060
|
+
this.mappedCells.renderCellAtElement(
|
|
1061
|
+
rowIndex,
|
|
1062
|
+
colIndex,
|
|
1063
|
+
elementIndex,
|
|
1064
|
+
renderedNode,
|
|
1065
|
+
);
|
|
1066
|
+
|
|
1067
|
+
if (__DEV__) {
|
|
1068
|
+
this.debug(
|
|
1069
|
+
`Render cell ${rowIndex},${colIndex} at element ${elementIndex}`,
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
// console.log('update', rowIndex, colIndex, renderedNode);
|
|
1074
|
+
itemUpdater(renderedNode);
|
|
1075
|
+
|
|
1076
|
+
this.updateElementPosition(elementIndex, { hidden, rowspan, colspan });
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
private onMouseEnter = (rowIndex: number) => {
|
|
1081
|
+
this.currentHoveredRow = rowIndex;
|
|
1082
|
+
|
|
1083
|
+
if (this.scrolling) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
this.addHoverClass(rowIndex);
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
private addHoverClass = (rowIndex: number) => {
|
|
1090
|
+
this.mappedCells.getElementsForRowIndex(rowIndex).forEach((elIndex) => {
|
|
1091
|
+
const node = this.itemDOMElements[elIndex];
|
|
1092
|
+
|
|
1093
|
+
if (node) {
|
|
1094
|
+
this.cellHoverClassNames.forEach((cls) => {
|
|
1095
|
+
node.classList.add(cls);
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
private onMouseLeave = (rowIndex: number) => {
|
|
1102
|
+
if (this.currentHoveredRow != -1 && this.currentHoveredRow === rowIndex) {
|
|
1103
|
+
this.removeHoverClass(rowIndex);
|
|
1104
|
+
}
|
|
1105
|
+
this.currentHoveredRow = -1;
|
|
1106
|
+
if (this.scrolling) {
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
this.removeHoverClass(rowIndex);
|
|
1110
|
+
};
|
|
1111
|
+
|
|
1112
|
+
private removeHoverClass = (rowIndex: number) => {
|
|
1113
|
+
this.mappedCells.getElementsForRowIndex(rowIndex).forEach((elIndex) => {
|
|
1114
|
+
const node = this.itemDOMElements[elIndex];
|
|
1115
|
+
|
|
1116
|
+
if (node) {
|
|
1117
|
+
this.cellHoverClassNames.forEach((cls) => {
|
|
1118
|
+
node.classList.remove(cls);
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
private updateHoverClassNamesForRow = (rowIndex: number) => {
|
|
1125
|
+
if (this.scrolling) {
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
if (__DEV__ && !this.hoverRowUpdatesInProgress) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
if (this.hoverRowUpdatesInProgress.has(rowIndex)) {
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
this.hoverRowUpdatesInProgress.set(rowIndex, true);
|
|
1136
|
+
|
|
1137
|
+
const checkHoverClass = () => {
|
|
1138
|
+
if (this.currentHoveredRow != -1 && !this.scrolling) {
|
|
1139
|
+
if (this.currentHoveredRow === rowIndex) {
|
|
1140
|
+
this.addHoverClass(rowIndex);
|
|
1141
|
+
} else {
|
|
1142
|
+
this.removeHoverClass(rowIndex);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
raf(() => {
|
|
1147
|
+
if (this.destroyed) {
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
checkHoverClass();
|
|
1151
|
+
|
|
1152
|
+
this.hoverRowUpdatesInProgress.delete(rowIndex);
|
|
1153
|
+
});
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
private updateElementPosition = (
|
|
1157
|
+
elementIndex: number,
|
|
1158
|
+
options?: { hidden: boolean; rowspan: number; colspan: number },
|
|
1159
|
+
) => {
|
|
1160
|
+
if (this.destroyed) {
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
const itemElement = this.itemDOMElements[elementIndex];
|
|
1164
|
+
const cell = this.mappedCells.getRenderedCellAtElement(elementIndex);
|
|
1165
|
+
|
|
1166
|
+
if (cell == null) {
|
|
1167
|
+
if (__DEV__) {
|
|
1168
|
+
this.error(`Cannot find item for element ${elementIndex}`);
|
|
1169
|
+
}
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
const [rowIndex, colIndex] = cell;
|
|
1173
|
+
|
|
1174
|
+
const itemPosition = this.brain.getCellOffset(rowIndex, colIndex);
|
|
1175
|
+
|
|
1176
|
+
if (itemPosition == null) {
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
const { x, y } = itemPosition;
|
|
1181
|
+
|
|
1182
|
+
if (itemElement) {
|
|
1183
|
+
this.updateHoverClassNamesForRow(rowIndex);
|
|
1184
|
+
|
|
1185
|
+
// itemElement.style.gridColumn = `${colIndex} / span 1`;
|
|
1186
|
+
// itemElement.style.gridRow = `${rowIndex} / span 1`;
|
|
1187
|
+
|
|
1188
|
+
// (itemElement.dataset as any).elementIndex = elementIndex;
|
|
1189
|
+
(itemElement.dataset as any).rowIndex = rowIndex;
|
|
1190
|
+
|
|
1191
|
+
(itemElement.dataset as any).colIndex = colIndex;
|
|
1192
|
+
|
|
1193
|
+
if (ITEM_POSITION_WITH_TRANSFORM) {
|
|
1194
|
+
this.setTransform(itemElement, rowIndex, colIndex, { x, y }, null);
|
|
1195
|
+
|
|
1196
|
+
itemElement.style.willChange = 'transform';
|
|
1197
|
+
itemElement.style.backfaceVisibility = 'hidden';
|
|
1198
|
+
// need to set it to auto
|
|
1199
|
+
// in case some fixed cells are reused
|
|
1200
|
+
// as the fixed cells had a zIndex
|
|
1201
|
+
const hidden = options
|
|
1202
|
+
? options.hidden
|
|
1203
|
+
: !!this.isCellCovered(rowIndex, colIndex);
|
|
1204
|
+
itemElement.style.zIndex = hidden
|
|
1205
|
+
? '-1'
|
|
1206
|
+
: // #updatezindex - we need to allow elements use their own zIndex, so we
|
|
1207
|
+
// resort to allowing them to have it as a data-z-index attribute
|
|
1208
|
+
itemElement.dataset.zIndex || 'auto';
|
|
1209
|
+
} else {
|
|
1210
|
+
itemElement.style.display = '';
|
|
1211
|
+
itemElement.style.left = `${x}px`;
|
|
1212
|
+
itemElement.style.top = `${y}px`;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
|
|
1217
|
+
private onScrollStart = () => {
|
|
1218
|
+
this.scrolling = true;
|
|
1219
|
+
// if (this.currentHoveredRow != -1) {
|
|
1220
|
+
// this.removeHoverClass(this.currentHoveredRow);
|
|
1221
|
+
// }
|
|
1222
|
+
};
|
|
1223
|
+
|
|
1224
|
+
private onScrollStop = () => {
|
|
1225
|
+
this.scrolling = false;
|
|
1226
|
+
|
|
1227
|
+
if (this.currentHoveredRow != -1) {
|
|
1228
|
+
this.addHoverClass(this.currentHoveredRow);
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
public adjustFixedElementsOnScroll = (
|
|
1233
|
+
scrollPosition: ScrollPosition = this.brain.getScrollPosition(),
|
|
1234
|
+
) => {
|
|
1235
|
+
const { mappedCells, brain, itemDOMElements } = this;
|
|
1236
|
+
|
|
1237
|
+
const cols = this.brain.getColCount();
|
|
1238
|
+
const rows = this.brain.getRowCount();
|
|
1239
|
+
|
|
1240
|
+
const { fixedColsStart, fixedColsEnd, fixedRowsStart, fixedRowsEnd } =
|
|
1241
|
+
this.brain.getFixedCellInfo();
|
|
1242
|
+
|
|
1243
|
+
if (!fixedColsStart && !fixedColsEnd && !fixedRowsStart && !fixedRowsEnd) {
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
if (itemDOMElements[0]) {
|
|
1248
|
+
setInfiniteScrollPosition(
|
|
1249
|
+
scrollPosition,
|
|
1250
|
+
this.getInfiniteNode(itemDOMElements[0]!),
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
const fixedEndColsOffsets = this.brain.getFixedEndColsOffsets({
|
|
1255
|
+
skipScroll: true,
|
|
1256
|
+
});
|
|
1257
|
+
const fixedEndRowsOffsets = this.brain.getFixedEndRowsOffsets({
|
|
1258
|
+
skipScroll: true,
|
|
1259
|
+
});
|
|
1260
|
+
|
|
1261
|
+
const { start, end } = this.brain.getRenderRange();
|
|
1262
|
+
|
|
1263
|
+
const [startRow, startCol] = start;
|
|
1264
|
+
const [endRow, endCol] = end;
|
|
1265
|
+
|
|
1266
|
+
function adjustElementPosition(
|
|
1267
|
+
rowIndex: number,
|
|
1268
|
+
colIndex: number,
|
|
1269
|
+
fn: (
|
|
1270
|
+
rowIndex: number,
|
|
1271
|
+
colIndex: number,
|
|
1272
|
+
node: HTMLElement,
|
|
1273
|
+
{ x, y }: { x: number; y: number },
|
|
1274
|
+
) => void,
|
|
1275
|
+
) {
|
|
1276
|
+
const elementIndex = mappedCells.getElementIndexForCell(
|
|
1277
|
+
rowIndex,
|
|
1278
|
+
colIndex,
|
|
1279
|
+
);
|
|
1280
|
+
if (elementIndex === null) {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
const itemPosition = brain.getCellOffset(rowIndex, colIndex);
|
|
1284
|
+
const node = itemDOMElements[elementIndex];
|
|
1285
|
+
|
|
1286
|
+
if (elementIndex != null && node && itemPosition) {
|
|
1287
|
+
fn(rowIndex, colIndex, node!, itemPosition);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
const adjustColStart = (
|
|
1292
|
+
_rowIndex: number,
|
|
1293
|
+
colIndex: number,
|
|
1294
|
+
node: HTMLElement,
|
|
1295
|
+
{ x, y }: { x: number; y: number },
|
|
1296
|
+
) => {
|
|
1297
|
+
this.setTransform(
|
|
1298
|
+
node,
|
|
1299
|
+
_rowIndex,
|
|
1300
|
+
colIndex,
|
|
1301
|
+
{ x: x, y, scrollLeft: true },
|
|
1302
|
+
fixedColsStart - colIndex,
|
|
1303
|
+
);
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1306
|
+
const adjustRowStart = (
|
|
1307
|
+
rowIndex: number,
|
|
1308
|
+
_colIndex: number,
|
|
1309
|
+
node: HTMLElement,
|
|
1310
|
+
coords: { x: number; y: number },
|
|
1311
|
+
) => {
|
|
1312
|
+
this.setTransform(
|
|
1313
|
+
node,
|
|
1314
|
+
rowIndex,
|
|
1315
|
+
_colIndex,
|
|
1316
|
+
|
|
1317
|
+
{ x: coords.x, y: coords.y, scrollTop: true },
|
|
1318
|
+
fixedRowsStart - rowIndex,
|
|
1319
|
+
);
|
|
1320
|
+
};
|
|
1321
|
+
|
|
1322
|
+
const adjustColEnd = (
|
|
1323
|
+
_rowIndex: number,
|
|
1324
|
+
colIndex: number,
|
|
1325
|
+
node: HTMLElement,
|
|
1326
|
+
{ y }: { y: number },
|
|
1327
|
+
) => {
|
|
1328
|
+
const val = fixedEndColsOffsets[colIndex];
|
|
1329
|
+
|
|
1330
|
+
this.setTransform(
|
|
1331
|
+
node,
|
|
1332
|
+
_rowIndex,
|
|
1333
|
+
colIndex,
|
|
1334
|
+
{ x: val, y, scrollLeft: true },
|
|
1335
|
+
cols - colIndex,
|
|
1336
|
+
);
|
|
1337
|
+
};
|
|
1338
|
+
|
|
1339
|
+
const adjustRowEnd = (
|
|
1340
|
+
rowIndex: number,
|
|
1341
|
+
_colIndex: number,
|
|
1342
|
+
node: HTMLElement,
|
|
1343
|
+
coords: { x: number; y: number },
|
|
1344
|
+
) => {
|
|
1345
|
+
this.setTransform(
|
|
1346
|
+
node,
|
|
1347
|
+
rowIndex,
|
|
1348
|
+
_colIndex,
|
|
1349
|
+
{ x: coords.x, y: fixedEndRowsOffsets[rowIndex], scrollTop: true },
|
|
1350
|
+
rows - rowIndex,
|
|
1351
|
+
);
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
const adjustColStartRowStart = (
|
|
1355
|
+
_rowIndex: number,
|
|
1356
|
+
_colIndex: number,
|
|
1357
|
+
node: HTMLElement,
|
|
1358
|
+
{ x, y }: { x: number; y: number },
|
|
1359
|
+
) => {
|
|
1360
|
+
this.setTransform(
|
|
1361
|
+
node,
|
|
1362
|
+
_rowIndex,
|
|
1363
|
+
_colIndex,
|
|
1364
|
+
{ x: x, scrollLeft: true, y: y, scrollTop: true },
|
|
1365
|
+
100_000,
|
|
1366
|
+
);
|
|
1367
|
+
};
|
|
1368
|
+
|
|
1369
|
+
const adjustColStartRowEnd = (
|
|
1370
|
+
_rowIndex: number,
|
|
1371
|
+
_colIndex: number,
|
|
1372
|
+
node: HTMLElement,
|
|
1373
|
+
{ x }: { x: number; y: number },
|
|
1374
|
+
) => {
|
|
1375
|
+
this.setTransform(
|
|
1376
|
+
node,
|
|
1377
|
+
_rowIndex,
|
|
1378
|
+
_colIndex,
|
|
1379
|
+
{
|
|
1380
|
+
x: x,
|
|
1381
|
+
scrollLeft: true,
|
|
1382
|
+
y: fixedEndRowsOffsets[_rowIndex],
|
|
1383
|
+
scrollTop: true,
|
|
1384
|
+
},
|
|
1385
|
+
200_000,
|
|
1386
|
+
);
|
|
1387
|
+
};
|
|
1388
|
+
|
|
1389
|
+
const adjustColEndRowStart = (
|
|
1390
|
+
_rowIndex: number,
|
|
1391
|
+
colIndex: number,
|
|
1392
|
+
node: HTMLElement,
|
|
1393
|
+
coords: { y: number },
|
|
1394
|
+
) => {
|
|
1395
|
+
this.setTransform(
|
|
1396
|
+
node,
|
|
1397
|
+
_rowIndex,
|
|
1398
|
+
colIndex,
|
|
1399
|
+
{
|
|
1400
|
+
x: fixedEndColsOffsets[colIndex],
|
|
1401
|
+
y: coords.y,
|
|
1402
|
+
scrollLeft: true,
|
|
1403
|
+
scrollTop: true,
|
|
1404
|
+
},
|
|
1405
|
+
300_000,
|
|
1406
|
+
);
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
const adjustColEndRowEnd = (
|
|
1410
|
+
rowIndex: number,
|
|
1411
|
+
colIndex: number,
|
|
1412
|
+
node: HTMLElement,
|
|
1413
|
+
) => {
|
|
1414
|
+
this.setTransform(
|
|
1415
|
+
node,
|
|
1416
|
+
rowIndex,
|
|
1417
|
+
colIndex,
|
|
1418
|
+
{
|
|
1419
|
+
x: fixedEndColsOffsets[colIndex],
|
|
1420
|
+
y: fixedEndRowsOffsets[rowIndex],
|
|
1421
|
+
scrollLeft: true,
|
|
1422
|
+
scrollTop: true,
|
|
1423
|
+
},
|
|
1424
|
+
400_000,
|
|
1425
|
+
);
|
|
1426
|
+
};
|
|
1427
|
+
|
|
1428
|
+
if (fixedColsStart || fixedColsEnd) {
|
|
1429
|
+
for (let rowIndex = startRow; rowIndex < endRow; rowIndex++) {
|
|
1430
|
+
for (let colIndex = 0; colIndex < fixedColsStart; colIndex++) {
|
|
1431
|
+
adjustElementPosition(rowIndex, colIndex, adjustColStart);
|
|
1432
|
+
}
|
|
1433
|
+
if (fixedColsEnd) {
|
|
1434
|
+
const firstColFixedEnd = cols - fixedColsEnd;
|
|
1435
|
+
|
|
1436
|
+
for (let colIndex = firstColFixedEnd; colIndex < cols; colIndex++) {
|
|
1437
|
+
adjustElementPosition(rowIndex, colIndex, adjustColEnd);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
if (fixedRowsStart || fixedRowsEnd) {
|
|
1444
|
+
for (let colIndex = startCol; colIndex < endCol; colIndex++) {
|
|
1445
|
+
for (let rowIndex = 0; rowIndex < fixedRowsStart; rowIndex++) {
|
|
1446
|
+
adjustElementPosition(rowIndex, colIndex, adjustRowStart);
|
|
1447
|
+
}
|
|
1448
|
+
if (fixedRowsEnd) {
|
|
1449
|
+
const firstRowFixedEnd = rows - fixedRowsEnd;
|
|
1450
|
+
for (let rowIndex = firstRowFixedEnd; rowIndex < rows; rowIndex++) {
|
|
1451
|
+
adjustElementPosition(rowIndex, colIndex, adjustRowEnd);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
if (fixedColsStart && fixedRowsStart) {
|
|
1458
|
+
for (let rowIndex = 0; rowIndex < fixedRowsStart; rowIndex++) {
|
|
1459
|
+
for (let colIndex = 0; colIndex < fixedColsStart; colIndex++) {
|
|
1460
|
+
adjustElementPosition(rowIndex, colIndex, adjustColStartRowStart);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (fixedColsStart && fixedRowsEnd) {
|
|
1465
|
+
const firstRowFixedEnd = rows - fixedRowsEnd;
|
|
1466
|
+
for (let rowIndex = firstRowFixedEnd; rowIndex < rows; rowIndex++) {
|
|
1467
|
+
for (let colIndex = 0; colIndex < fixedColsStart; colIndex++) {
|
|
1468
|
+
adjustElementPosition(rowIndex, colIndex, adjustColStartRowEnd);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
if (fixedColsEnd && fixedRowsStart) {
|
|
1474
|
+
const firstColFixedEnd = cols - fixedColsEnd;
|
|
1475
|
+
for (let rowIndex = 0; rowIndex < fixedRowsStart; rowIndex++) {
|
|
1476
|
+
for (let colIndex = firstColFixedEnd; colIndex < cols; colIndex++) {
|
|
1477
|
+
adjustElementPosition(rowIndex, colIndex, adjustColEndRowStart);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
if (fixedColsEnd && fixedRowsEnd) {
|
|
1483
|
+
const firstRowFixedEnd = rows - fixedRowsEnd;
|
|
1484
|
+
const firstColFixedEnd = cols - fixedColsEnd;
|
|
1485
|
+
|
|
1486
|
+
for (let rowIndex = firstRowFixedEnd; rowIndex < rows; rowIndex++) {
|
|
1487
|
+
for (let colIndex = firstColFixedEnd; colIndex < cols; colIndex++) {
|
|
1488
|
+
adjustElementPosition(rowIndex, colIndex, adjustColEndRowEnd);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
destroy = () => {
|
|
1495
|
+
if (this.destroyed) {
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
this.destroyed = true;
|
|
1499
|
+
this.reset();
|
|
1500
|
+
this.onDestroy();
|
|
1501
|
+
|
|
1502
|
+
this.hoverRowUpdatesInProgress.clear();
|
|
1503
|
+
|
|
1504
|
+
(this as any).hoverRowUpdatesInProgress = null;
|
|
1505
|
+
(this as any).brain = null;
|
|
1506
|
+
(this as any).mappedCells = null;
|
|
1507
|
+
};
|
|
1508
|
+
|
|
1509
|
+
reset() {
|
|
1510
|
+
this.itemDOMElements = [];
|
|
1511
|
+
this.itemDOMRefs = [];
|
|
1512
|
+
this.updaters = [];
|
|
1513
|
+
this.items = [];
|
|
1514
|
+
this.mappedCells.reset();
|
|
1515
|
+
}
|
|
1516
|
+
}
|