UNPKG

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
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