@visactor/react-vtable
Version:
The react version of VTable
178 lines (165 loc) • 10.6 kB
JavaScript
import React, { useState, useEffect, useRef, useImperativeHandle, useCallback } from "react";
import withContainer from "../containers/withContainer";
import RootTableContext from "../context/table";
import { isEqual, isNil, pickWithout } from "@visactor/vutils";
import { toArray } from "../util";
import { REACT_PRIVATE_PROPS } from "../constants";
import { bindEventsToTable, TABLE_EVENTS_KEYS, TABLE_EVENTS } from "../eventsUtils";
import { VTableReactAttributePlugin } from "../table-components/custom/vtable-react-attribute-plugin";
import { reactEnvModule } from "../table-components/custom/vtable-browser-env-contribution";
import { container, isBrowserEnv } from "@visactor/vtable/es/vrender";
isBrowserEnv() && container.load(reactEnvModule);
const notOptionKeys = [ ...REACT_PRIVATE_PROPS, ...TABLE_EVENTS_KEYS, "skipFunctionDiff", "onError", "onReady", "option", "records", "container", "vtableConstrouctor" ], getComponentId = (child, index) => `${child && child.type && (child.type.displayName || child.type.name)}-${index}`, parseOptionFromChildren = props => {
const optionFromChildren = {};
return toArray(props.children).map(((child, index) => {
const parseOption = child && child.type && child.type.parseOption;
if (parseOption && child.props) {
const optionResult = parseOption(isNil(child.props.componentId) ? Object.assign(Object.assign({}, child.props), {
componentId: getComponentId(child, index)
}) : child.props);
child.key && (optionResult.option.key = child.key), optionResult.isSingle ? optionFromChildren[optionResult.optionName] = optionResult.option : (optionFromChildren[optionResult.optionName] || (optionFromChildren[optionResult.optionName] = []),
optionFromChildren[optionResult.optionName].push(optionResult.option));
}
})), optionFromChildren;
}, BaseTable = React.forwardRef(((props, ref) => {
const [updateId, setUpdateId] = useState(0), tableContext = useRef({});
useImperativeHandle(ref, (() => {
var _a;
return null === (_a = tableContext.current) || void 0 === _a ? void 0 : _a.table;
}));
const hasOption = !!props.option, hasRecords = !!props.records, isUnmount = useRef(!1), prevOption = useRef(pickWithout(props, notOptionKeys)), optionFromChildren = useRef(null), prevRecords = useRef(props.records), eventsBinded = React.useRef(null), skipFunctionDiff = !!props.skipFunctionDiff, keepColumnWidthChange = !!props.keepColumnWidthChange, columnWidths = useRef(new Map), pivotColumnWidths = useRef([]), pivotHeaderColumnWidths = useRef([]), parseOption = useCallback((props => hasOption && props.option ? hasRecords && props.records ? Object.assign(Object.assign({}, props.option), {
clearDOM: !1,
records: props.records
}) : Object.assign(Object.assign({}, props.option), {
clearDOM: !1
}) : Object.assign(Object.assign(Object.assign({
records: props.records
}, prevOption.current), optionFromChildren.current), {
clearDOM: !1,
customConfig: Object.assign(Object.assign({}, prevOption.current.customConfig), {
createReactContainer: !0
})
})), [ hasOption, hasRecords ]), createTable = useCallback((props => {
var _a;
const vtable = new props.vtableConstrouctor(props.container, parseOption(props));
vtable.scenegraph.stage.reactAttribute = props.ReactDOM, vtable.scenegraph.stage.pluginService.register(null !== (_a = props.reactAttributePlugin) && void 0 !== _a ? _a : new VTableReactAttributePlugin),
vtable.scenegraph.stage.params.ReactDOM = props.ReactDOM, tableContext.current = Object.assign(Object.assign({}, tableContext.current), {
table: vtable
}), isUnmount.current = !1, columnWidths.current.clear(), pivotColumnWidths.current = [],
pivotHeaderColumnWidths.current = [], vtable.on("resize_column_end", (args => {
const table = tableContext.current.table;
if (!keepColumnWidthChange) return;
const {col: col, colWidths: colWidths} = args, width = colWidths[col];
if (vtable.isPivotTable()) {
const path = table.getCellHeaderPaths(col, table.columnHeaderLevelCount);
let dimensions;
dimensions = "rowHeader" === path.cellLocation ? path.rowHeaderPaths : path.colHeaderPaths;
let found = !1;
pivotColumnWidths.current.forEach((item => {
JSON.stringify(item.dimensions) === JSON.stringify(dimensions) && (item.width = width,
found = !0);
})), found || pivotColumnWidths.current.push({
dimensions: dimensions,
width: width
});
} else {
const define = table.getBodyColumnDefine(col, 0);
(null == define ? void 0 : define.key) && columnWidths.current.set(define.key, width);
}
}));
}), [ parseOption ]), handleTableRender = useCallback((() => {
if (!isUnmount.current) {
if (!tableContext.current || !tableContext.current.table) return;
bindEventsToTable(tableContext.current.table, props, eventsBinded.current, TABLE_EVENTS),
setUpdateId(updateId + 1), props.onReady && props.onReady(tableContext.current.table, 0 === updateId);
}
}), [ updateId, setUpdateId, props ]), renderTable = useCallback((() => {
tableContext.current.table && (tableContext.current.table.render(), handleTableRender());
}), [ handleTableRender ]);
return useEffect((() => {
var _a;
const newOptionFromChildren = hasOption ? null : parseOptionFromChildren(props);
if (!(null === (_a = tableContext.current) || void 0 === _a ? void 0 : _a.table)) return hasOption || (optionFromChildren.current = newOptionFromChildren),
createTable(props), renderTable(), void (eventsBinded.current = props);
if (hasOption) {
if (isEqual(eventsBinded.current.option, props.option, {
skipFunction: skipFunctionDiff
})) {
if (hasRecords && !isEqual(eventsBinded.current.records, props.records, {
skipFunction: skipFunctionDiff
})) {
if (keepColumnWidthChange) {
const columnWidthConfig = updateWidthCache(columnWidths.current, pivotColumnWidths.current, tableContext.current.table);
tableContext.current.table.internalProps.columnWidthConfig = columnWidthConfig,
tableContext.current.table.internalProps.columnWidthConfigForRowHeader = columnWidthConfig;
}
tableContext.current.table.setRecords(props.records), handleTableRender(), eventsBinded.current = props;
}
} else {
const option = parseOption(props);
if (keepColumnWidthChange) {
const columnWidthConfig = updateWidthCache(columnWidths.current, pivotColumnWidths.current, tableContext.current.table);
option.columnWidthConfig = columnWidthConfig, option.columnWidthConfigForRowHeader = columnWidthConfig;
}
tableContext.current.table.updateOption(option), handleTableRender(), eventsBinded.current = props;
}
return;
}
const newOption = pickWithout(props, notOptionKeys);
if (isEqual(newOption, prevOption.current, {
skipFunction: skipFunctionDiff
}) && isEqual(newOptionFromChildren, optionFromChildren.current, {
skipFunction: skipFunctionDiff
})) {
if (hasRecords && !isEqual(props.records, prevRecords.current, {
skipFunction: skipFunctionDiff
})) {
if (prevRecords.current = props.records, keepColumnWidthChange) {
const columnWidthConfig = updateWidthCache(columnWidths.current, pivotColumnWidths.current, tableContext.current.table);
tableContext.current.table.internalProps.columnWidthConfig = columnWidthConfig,
tableContext.current.table.internalProps.columnWidthConfigForRowHeader = columnWidthConfig;
}
tableContext.current.table.setRecords(props.records), handleTableRender(), eventsBinded.current = props;
}
} else {
prevOption.current = newOption, optionFromChildren.current = newOptionFromChildren;
const option = parseOption(props);
if (keepColumnWidthChange) {
const columnWidthConfig = updateWidthCache(columnWidths.current, pivotColumnWidths.current, tableContext.current.table);
option.columnWidthConfig = columnWidthConfig, option.columnWidthConfigForRowHeader = columnWidthConfig;
}
tableContext.current.table.updateOption(option), handleTableRender(), eventsBinded.current = props;
}
}), [ createTable, hasOption, hasRecords, parseOption, handleTableRender, renderTable, skipFunctionDiff, props ]),
useEffect((() => () => {
tableContext && tableContext.current && tableContext.current.table && (tableContext.current.table.release(),
tableContext.current = null), eventsBinded.current = null, isUnmount.current = !0;
}), []), React.createElement(RootTableContext.Provider, {
value: tableContext.current
}, toArray(props.children).map(((child, index) => {
if ("string" == typeof child) return;
const childId = getComponentId(child, index);
return React.createElement(React.Fragment, {
key: childId
}, React.cloneElement(child, {
updateId: updateId,
componentId: childId,
componentIndex: index
}));
})));
}));
export const createTable = (componentName, defaultProps, callback) => {
const Com = withContainer(BaseTable, componentName, (props => defaultProps ? Object.assign(props, defaultProps) : props));
return Com.displayName = componentName, Com;
};
function updateWidthCache(columnWidths, pivotColumnWidths, table) {
if (table.isPivotTable()) return pivotColumnWidths;
const columnWidthConfig = [];
return columnWidths.forEach(((width, key) => {
columnWidthConfig.push({
key: key,
width: width
});
})), columnWidthConfig;
}
//# sourceMappingURL=base-table.js.map