Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Core api refactoring #130

Merged
merged 5 commits into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export const COL_RESIZE_STOP = 'colResizing:stop';
export const ROWS_UPDATED = 'rowsUpdated';
export const COLUMNS_UPDATED = 'columnsUpdated';

export const COLUMNS_SORTING_CHANGE = 'columnsSortingChange';
export const COLUMNS_SORTED = 'columnsSorted';
export const SORT_MODEL_CHANGE = 'sortModelChange';

export const MULTIPLE_KEY_PRESS_CHANGED = 'multipleKeyPressChange';
4 changes: 3 additions & 1 deletion packages/grid/x-grid-modules/src/gridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { useApi, useColumns, useKeyboard, useRows } from './hooks/root';
import { useLogger, useLoggerFactory } from './hooks/utils';
import { debounce } from './utils';
import { mergeOptions } from './utils/mergeOptions';
import { useEvents } from './hooks/root/useEvents';

/**
* Data Grid component implementing [[GridComponentProps]].
Expand Down Expand Up @@ -63,7 +64,8 @@ export const GridComponent: React.FC<GridComponentProps> = React.memo(
apiRef = internalApiRef;
}

const initialised = useApi(rootContainerRef, windowRef, internalOptions, apiRef);
const initialised = useApi(rootContainerRef, internalOptions, apiRef);
useEvents(rootContainerRef, internalOptions, apiRef);
const internalColumns = useColumns(internalOptions, columns, apiRef);
const internalRows = useRows(internalOptions, rows, initialised, apiRef);
useKeyboard(internalOptions, initialised, apiRef);
Expand Down
47 changes: 22 additions & 25 deletions packages/grid/x-grid-modules/src/hooks/features/useSorting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ColDef,
ColParams,
Columns,
ColumnSortedParams,
SortModelParams,
FeatureModeConstant,
FieldComparatorList,
GridOptions,
Expand All @@ -16,10 +16,9 @@ import {
} from '../../models';
import {
COLUMN_HEADER_CLICK,
COLUMNS_SORTED,
MULTIPLE_KEY_PRESS_CHANGED,
ROWS_UPDATED,
COLUMNS_SORTING_CHANGE,
SORT_MODEL_CHANGE,
} from '../../constants/eventsConstants';
import { useLogger } from '../utils';
import { isDesc, nextSortDirection } from '../../utils';
Expand All @@ -39,12 +38,11 @@ export const useSorting = (
const originalOrder = React.useRef<RowId[]>([]);
const comparatorList = React.useRef<FieldComparatorList>([]);

const getColumnsSortedParams = React.useCallback(
(): ColumnSortedParams => ({
sortedColumns: sortModelRef.current.map((model) =>
apiRef.current!.getColumnFromField(model.field),
),
const getSortModelParams = React.useCallback(
(): SortModelParams => ({
sortModel: sortModelRef.current,
api: apiRef.current,
columns: apiRef.current!.getAllColumns(),
}),
[sortModelRef, apiRef],
);
Expand Down Expand Up @@ -126,21 +124,27 @@ export const useSorting = (
}

apiRef.current!.setRowModels([...sorted]);
apiRef.current!.emit(COLUMNS_SORTED, getColumnsSortedParams());
}, [apiRef, sortModelRef, comparatorListAggregate, getOriginalOrderedRows, logger]);

const setSortModel = React.useCallback(
(sortModel: SortModel) => {
sortModelRef.current = sortModel;
comparatorList.current = buildComparatorList(sortModel);
apiRef.current!.emit(COLUMNS_SORTING_CHANGE, getColumnsSortedParams());
apiRef.current!.emit(SORT_MODEL_CHANGE, getSortModelParams());
if (options.sortingMode === FeatureModeConstant.client) {
applySorting();
} else {
apiRef.current!.emit(COLUMNS_SORTED, getColumnsSortedParams());
}
},
[sortModelRef, comparatorList, apiRef, applySorting, buildComparatorList, options.sortingMode],
[
sortModelRef,
comparatorList,
apiRef,
applySorting,
buildComparatorList,
options.sortingMode,
getSortModelParams,
logger,
],
);

const sortColumn = React.useCallback(
Expand Down Expand Up @@ -189,15 +193,9 @@ export const useSorting = (
[allowMultipleSorting, options.enableMultipleColumnsSorting],
);

const onColumnsSorted = React.useCallback(
(handler: (param: ColumnSortedParams) => void): (() => void) => {
return apiRef!.current!.registerEvent(COLUMNS_SORTED, handler);
},
[apiRef],
);
const onColumnsSortingChange = React.useCallback(
(handler: (param: ColumnSortedParams) => void): (() => void) => {
return apiRef!.current!.registerEvent(COLUMNS_SORTING_CHANGE, handler);
const onSortModelChange = React.useCallback(
(handler: (param: SortModelParams) => void): (() => void) => {
return apiRef!.current!.registerEvent(SORT_MODEL_CHANGE, handler);
},
[apiRef],
);
Expand Down Expand Up @@ -244,10 +242,9 @@ export const useSorting = (
useApiEventHandler(apiRef, ROWS_UPDATED, onRowsUpdated);
useApiEventHandler(apiRef, MULTIPLE_KEY_PRESS_CHANGED, onMultipleKeyPressed);

useApiEventHandler(apiRef, COLUMNS_SORTING_CHANGE, options.onColumnsSortingChange);
useApiEventHandler(apiRef, COLUMNS_SORTED, options.onColumnsSorted);
useApiEventHandler(apiRef, SORT_MODEL_CHANGE, options.onSortModelChange);

const sortApi: SortApi = { getSortModel, setSortModel, onColumnsSorted, onColumnsSortingChange };
const sortApi: SortApi = { getSortModel, setSortModel, onSortModelChange };

useApiMethod(apiRef, sortApi, 'SortApi');
};
193 changes: 9 additions & 184 deletions packages/grid/x-grid-modules/src/hooks/root/useApi.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,19 @@
import * as React from 'react';
import { useLogger } from '../utils/useLogger';
import {
CELL_CLICK,
CLICK_EVENT,
COL_RESIZE_START,
COL_RESIZE_STOP,
COLUMN_HEADER_CLICK,
UNMOUNT,
KEYDOWN_EVENT,
KEYUP_EVENT,
RESIZE,
ROW_CLICK,
HOVER_EVENT,
CELL_HOVER,
ROW_HOVER,
COLUMN_HEADER_HOVER,
} from '../../constants/eventsConstants';
import { GridOptions, ApiRef, CellParams, ColParams, RowParams } from '../../models';
import { UNMOUNT } from '../../constants/eventsConstants';
import { GridOptions, ApiRef } from '../../models';
import { GridApi } from '../../models/api/gridApi';
import {
CELL_CSS_CLASS,
HEADER_CELL_CSS_CLASS,
ROW_CSS_CLASS,
} from '../../constants/cssClassesConstants';
import {
findParentElementFromClassName,
getDataFromElem,
getFieldFromHeaderElem,
getIdFromRowElem,
isCell,
isHeaderCell,
} from '../../utils/domUtils';
import { useApiMethod } from './useApiMethod';
import { useApiEventHandler } from './useApiEventHandler';
import { buildCellParams, buildRowParams } from '../../utils/paramsUtils';

const EventEmitter = require('events').EventEmitter;

// TODO Split this effect in useEvents and UseApi
export function useApi(
gridRootRef: React.RefObject<HTMLDivElement>,
windowRef: React.RefObject<HTMLDivElement>,
options: GridOptions,
apiRef: ApiRef,
): boolean {
const [isApiInitialised, setApiInitialised] = React.useState(false);
const [initialised, setInit] = React.useState(false);
const isResizingRef = React.useRef(false);
const logger = useLogger('useApi');

const initApi = React.useCallback(() => {
Expand All @@ -64,121 +31,13 @@ export function useApi(

const emitEvent = React.useCallback(
(name: string, ...args: any[]) => {
if (apiRef && apiRef.current && isApiInitialised) {
if (apiRef && apiRef.current && apiRef.current?.isInitialised) {
apiRef.current.emit(name, ...args);
}
},
[apiRef, isApiInitialised],
);

const getHandler = React.useCallback(
(name: string) => (...args: any[]) => emitEvent(name, ...args),
[emitEvent],
);

const handleResizeStart = React.useCallback(() => {
isResizingRef.current = true;
}, [isResizingRef]);

const handleResizeStop = React.useCallback(() => {
isResizingRef.current = false;
}, [isResizingRef]);

const getEventParams = React.useCallback(
(event: any) => {
if (event.target == null) {
return null;
}
const elem = event.target as HTMLElement;
const eventParams: { cell?: CellParams; row?: RowParams; header?: ColParams } = {};

if (isCell(elem)) {
const cellEl = findParentElementFromClassName(elem, CELL_CSS_CLASS)! as HTMLElement;
const rowEl = findParentElementFromClassName(elem, ROW_CSS_CLASS)! as HTMLElement;
const id = getIdFromRowElem(rowEl);
const rowModel = apiRef!.current!.getRowFromId(id);
const rowIndex = apiRef!.current!.getRowIndexFromId(id);
const field = getDataFromElem(cellEl, 'field');
const value = getDataFromElem(cellEl, 'value');
const column = apiRef.current!.getColumnFromField(field);
if (!column || !column.disableClickEventBubbling) {
const commonParams = {
data: rowModel.data,
rowIndex,
colDef: column,
rowModel,
api: apiRef.current!,
};
eventParams.cell = buildCellParams({
...commonParams,
element: cellEl,
value,
});
eventParams.row = buildRowParams({
...commonParams,
element: rowEl,
});
}
} else if (isHeaderCell(elem) && !isResizingRef.current) {
const headerCell = findParentElementFromClassName(elem, HEADER_CELL_CSS_CLASS)!;
const field = getFieldFromHeaderElem(headerCell);
const column = apiRef.current!.getColumnFromField(field);
const colIndex = apiRef.current!.getColumnIndex(field);
const colHeaderParams: ColParams = {
field,
colDef: column,
colIndex,
api: apiRef.current!,
};
eventParams.header = colHeaderParams;
}
return eventParams;
},
[apiRef],
);

const onClickHandler = React.useCallback(
(event: MouseEvent) => {
const eventParams = getEventParams(event);

if (!eventParams) {
return;
}

if (eventParams.cell) {
emitEvent(CELL_CLICK, eventParams.cell);
}
if (eventParams.row) {
emitEvent(ROW_CLICK, eventParams.row);
}
if (eventParams.header) {
emitEvent(COLUMN_HEADER_CLICK, eventParams.header);
}
},
[emitEvent, getEventParams],
);

const onHoverHandler = React.useCallback(
(event: any) => {
const eventParams = getEventParams(event);

if (!eventParams) {
return;
}

if (eventParams.cell) {
emitEvent(CELL_HOVER, eventParams.cell);
}
if (eventParams.row) {
emitEvent(ROW_HOVER, eventParams.row);
}
if (eventParams.header) {
emitEvent(COLUMN_HEADER_HOVER, eventParams.header);
}
},
[emitEvent, getEventParams],
);

const registerEvent = React.useCallback(
(event: string, handler: (param: any) => void): (() => void) => {
logger.debug(`Binding ${event} event`);
Expand All @@ -191,59 +50,25 @@ export function useApi(
},
[apiRef, logger],
);
const onUnmount = React.useCallback(
(handler: (param: any) => void): (() => void) => {
return registerEvent(UNMOUNT, handler);
},
[registerEvent],
);
const onResize = React.useCallback(
(handler: (param: any) => void): (() => void) => {
return registerEvent(RESIZE, handler);
},
[registerEvent],
);
const resize = React.useCallback(() => apiRef.current?.emit(RESIZE), [apiRef]);
useApiMethod(apiRef, { registerEvent, onUnmount, onResize, resize }, 'CoreApi');

useApiMethod(apiRef, { registerEvent, emitEvent }, 'CoreApi');
React.useEffect(() => {
if (gridRootRef && gridRootRef.current && isApiInitialised) {
logger.debug('Binding events listeners');
const keyDownHandler = getHandler(KEYDOWN_EVENT);
const keyUpHandler = getHandler(KEYUP_EVENT);
const gridRootElem = gridRootRef.current;

gridRootRef.current.addEventListener(CLICK_EVENT, onClickHandler, { capture: true });
gridRootRef.current.addEventListener(HOVER_EVENT, onHoverHandler, { capture: true });
document.addEventListener(KEYDOWN_EVENT, keyDownHandler);
document.addEventListener(KEYUP_EVENT, keyUpHandler);

apiRef.current!.isInitialised = true;
apiRef.current!.rootElementRef = gridRootRef;

setInit(true);
const api = apiRef.current!;

return () => {
logger.debug('Clearing all events listeners');
logger.debug('Unmounting Grid component');
api.emit(UNMOUNT);
gridRootElem.removeEventListener(CLICK_EVENT, onClickHandler, { capture: true });
gridRootElem.removeEventListener(HOVER_EVENT, onHoverHandler, { capture: true });
document.removeEventListener(KEYDOWN_EVENT, keyDownHandler);
document.removeEventListener(KEYUP_EVENT, keyUpHandler);
logger.debug('Clearing all events listeners');
api.removeAllListeners();
};
}

return undefined;
}, [gridRootRef, isApiInitialised, getHandler, logger, onClickHandler, onHoverHandler, apiRef]);

useApiEventHandler(apiRef, COL_RESIZE_START, handleResizeStart);
useApiEventHandler(apiRef, COL_RESIZE_STOP, handleResizeStop);

useApiEventHandler(apiRef, COLUMN_HEADER_CLICK, options.onColumnHeaderClick);
useApiEventHandler(apiRef, CELL_CLICK, options.onCellClick);
useApiEventHandler(apiRef, ROW_CLICK, options.onRowClick);
useApiEventHandler(apiRef, CELL_HOVER, options.onCellHover);
useApiEventHandler(apiRef, ROW_HOVER, options.onRowHover);
}, [gridRootRef, isApiInitialised, logger, apiRef]);

return initialised;
}
Loading