ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
111 lines • 5.19 kB
JavaScript
import * as React from 'react';
import { useEffect, useMemo, useRef } from 'react';
import union from 'lodash/union.js';
import difference from 'lodash/difference.js';
import { useListContextWithProps } from "../controller/list/useListContextWithProps.js";
import { OptionalResourceContextProvider, useResourceContext } from "../core/index.js";
import { useEvent } from "../util/index.js";
import { DataTableCallbacksContext } from "./DataTableCallbacksContext.js";
import { DataTableConfigContext } from "./DataTableConfigContext.js";
import { DataTableDataContext } from "./DataTableDataContext.js";
import { DataTableSelectedIdsContext } from "./DataTableSelectedIdsContext.js";
import { DataTableSortContext } from "./DataTableSortContext.js";
import { DataTableStoreContext } from "./DataTableStoreContext.js";
export const DataTableBase = function DataTable(props) {
const resourceFromContext = useResourceContext(props);
const { children, empty, expand, hiddenColumns = emptyArray, hasBulkActions, hover, loading, isRowSelectable, isRowExpandable, resource, rowClick, expandSingle = false, } = props;
const { sort, data, isPending, onSelect, onToggleItem, selectedIds, setSort, total, } = useListContextWithProps(props);
const storeKey = props.storeKey || `${resourceFromContext}.datatable`;
const handleSort = useEvent((event) => {
event.stopPropagation();
if (!setSort)
return;
const newField = event.currentTarget.dataset.field || 'id';
const newOrder = sort?.field === newField
? sort?.order === 'ASC'
? 'DESC'
: 'ASC'
: event.currentTarget.dataset.order || 'ASC';
setSort({ field: newField, order: newOrder });
});
const lastSelected = useRef(null);
useEffect(() => {
if (!selectedIds || selectedIds.length === 0) {
lastSelected.current = null;
}
}, [JSON.stringify(selectedIds)]); // eslint-disable-line react-hooks/exhaustive-deps
// we manage row selection here instead of in the rows level to allow shift+click to select an array of rows
const handleToggleItem = useEvent((id, event) => {
if (!data)
return;
const ids = data.map(record => record.id);
const lastSelectedIndex = ids.indexOf(lastSelected.current);
if (event.shiftKey && lastSelectedIndex !== -1) {
const index = ids.indexOf(id);
const idsBetweenSelections = ids.slice(Math.min(lastSelectedIndex, index), Math.max(lastSelectedIndex, index) + 1);
const isClickedItemSelected = selectedIds?.includes(id);
const newSelectedIds = isClickedItemSelected
? difference(selectedIds, idsBetweenSelections)
: union(selectedIds, idsBetweenSelections);
onSelect?.(isRowSelectable
? newSelectedIds.filter((id) => isRowSelectable(data.find(record => record.id === id)))
: newSelectedIds);
}
else {
onToggleItem?.(id);
}
lastSelected.current = id;
});
const storeContextValue = useMemo(() => ({
storeKey,
defaultHiddenColumns: hiddenColumns,
}), [storeKey, hiddenColumns]);
const configContextValue = useMemo(() => ({
expand,
expandSingle,
hasBulkActions,
hover,
}), [expand, expandSingle, hasBulkActions, hover]);
const callbacksContextValue = useMemo(() => ({
handleSort: setSort ? handleSort : undefined,
handleToggleItem: onToggleItem ? handleToggleItem : undefined,
isRowExpandable,
isRowSelectable,
onSelect,
rowClick,
}), [
setSort,
handleSort,
handleToggleItem,
isRowExpandable,
isRowSelectable,
onSelect,
onToggleItem,
rowClick,
]);
if (isPending === true) {
return loading;
}
/**
* Once loaded, the data for the list may be empty. Instead of
* displaying the table header with zero data rows,
* the DataTable displays the empty component.
*/
if (data == null || data.length === 0 || total === 0) {
return empty ?? null;
}
/**
* After the initial load, if the data for the list isn't empty,
* and even if the data is refreshing (e.g. after a filter change),
* the DataTable displays the current data.
*/
return (React.createElement(DataTableStoreContext.Provider, { value: storeContextValue },
React.createElement(DataTableSortContext.Provider, { value: sort },
React.createElement(DataTableSelectedIdsContext.Provider, { value: selectedIds },
React.createElement(DataTableCallbacksContext.Provider, { value: callbacksContextValue },
React.createElement(DataTableConfigContext.Provider, { value: configContextValue },
React.createElement(OptionalResourceContextProvider, { value: resource },
React.createElement(DataTableDataContext.Provider, { value: data }, children))))))));
};
const emptyArray = [];
//# sourceMappingURL=DataTableBase.js.map