react-table
Advanced tools
Comparing version 7.0.0-rc.9 to 7.0.0-rc.10
@@ -0,1 +1,22 @@ | ||
## 7.0.0-rc.10 | ||
- Optimizations made to make accessors, prop getters and other internals much faster. 10x in some cases! | ||
- Fixed docs for `usePagination` to have `pageIndex` and `pageSize` only available on the state object, not the instance | ||
- Added a plugin order restriction to make sure `useResizeColumns` always comes before `useAbsoluteLayout` | ||
- Fixed the `useFinalInstance` hook to not have an empty array as the first meta argument passed. | ||
- Fixed an issue where memoized or ref-forwarded components could not be used as cell renderers | ||
- The `toggleExpandedById` action has been renamed to `toggleExpanded` | ||
- Added the `toggleAllExpanded` action | ||
- Added the `setExpanded` action | ||
- Changed `row.isAggregated` to `row.isGrouped` | ||
- `state.expanded` and `state.selectedRowIds` are now objects (`{[rowId]: Bool}`), not arrays. This should help with mid-to-large size datasets while also being serializable (instead of a Set(), which is not as reliable) | ||
- `state.filters` is now an array of objects (`{id, value}`). Since filters do have order and can be applied incrementally, it should be an array to ensure correct order. | ||
- Moved the `flatColumns` and `flatColumnsDeps` hooks to be after row/data materialization. These hooks can then manipulate the `flatColumns` object after all data has been accessed without triggering row materialization again. | ||
- Added the `row.allCells` property and the `cellColumns` reducer hook to determine which cells to create for each row. These cells are placed into `row.allCells`. The resulting cell array is not meant to be used for display in templating and is only made available for convenience and/or advanced templating. | ||
- Added the `cells` reducer hook to determine which cells from the `row.allCells` array that should be placed into `row.cells`. The resulting cell array is the one that is intended for display in templating. | ||
- Reducers are now passed the actual instance variable, not the instanceRef | ||
- Added the `makeRenderer` utility (also exported) | ||
- Removed `column.groupByBoundary` functionality. If needed, use the `flatColumns` hook to decorate, reorganize or re-order groupBy columns | ||
- Fixed grouped row.id's to be truly unique | ||
## 7.0.0-rc.9 | ||
@@ -2,0 +23,0 @@ |
{ | ||
"name": "react-table", | ||
"version": "7.0.0-rc.9", | ||
"version": "7.0.0-rc.10", | ||
"description": "Hooks for building lightweight, fast and extendable datagrids for React", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -185,2 +185,3 @@ ![React Table Header](https://github.com/tannerlinsley/react-table/raw/master/media/header.png) | ||
<li>Eric Lanehart (@pushred)</li> | ||
<li>Anish P Patel (@anishpatelyaadada)</li> | ||
</ul> | ||
@@ -187,0 +188,0 @@ </td> |
@@ -120,4 +120,12 @@ import React from 'react' | ||
const isMountedRef = React.useRef(false) | ||
if (!isMountedRef.current) { | ||
} | ||
const handleColumn = (column, parentVisible) => { | ||
column.isVisible = parentVisible && !hiddenColumns.includes(column.id) | ||
column.isVisible = | ||
typeof column.isVisible !== 'undefined' | ||
? column.isVisible | ||
: parentVisible && !hiddenColumns.includes(column.id) | ||
@@ -124,0 +132,0 @@ let totalVisibleHeaderCount = 0 |
@@ -9,3 +9,3 @@ import React from 'react' | ||
makePropGetter, | ||
flexRender, | ||
makeRenderer, | ||
decorateColumnTree, | ||
@@ -22,4 +22,2 @@ makeHeaderGroups, | ||
let renderErr = 'Renderer Error' | ||
const defaultInitialState = {} | ||
@@ -128,7 +126,7 @@ const defaultColumnInstance = {} | ||
].reduce( | ||
(s, handler) => handler(s, action, state, instanceRef) || s, | ||
(s, handler) => handler(s, action, state, getInstance()) || s, | ||
state | ||
) | ||
}, | ||
[getStateReducers, getStateReducer] | ||
[getStateReducers, getStateReducer, getInstance] | ||
) | ||
@@ -178,73 +176,10 @@ | ||
// Snapshot hook and disallow more from being added | ||
const getFlatColumns = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'flatColumns' | ||
) | ||
// Snapshot hook and disallow more from being added | ||
const getFlatColumnsDeps = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'flatColumnsDeps' | ||
) | ||
// Get the flat list of all columns and allow hooks to decorate | ||
// those columns (and trigger this memoization via deps) | ||
let flatColumns = React.useMemo( | ||
() => | ||
reduceHooks( | ||
getFlatColumns(), | ||
flattenBy(columns, 'columns'), | ||
getInstance() | ||
), | ||
[ | ||
columns, | ||
getFlatColumns, | ||
getInstance, | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
...reduceHooks(getFlatColumnsDeps(), [], getInstance()), | ||
] | ||
) | ||
let flatColumns = React.useMemo(() => flattenBy(columns, 'columns'), [ | ||
columns, | ||
]) | ||
getInstance().flatColumns = flatColumns | ||
// Snapshot hook and disallow more from being added | ||
const getHeaderGroups = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'headerGroups' | ||
) | ||
// Snapshot hook and disallow more from being added | ||
const getHeaderGroupsDeps = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'headerGroupsDeps' | ||
) | ||
// Make the headerGroups | ||
const headerGroups = React.useMemo( | ||
() => | ||
reduceHooks( | ||
getHeaderGroups(), | ||
makeHeaderGroups(flatColumns, defaultColumn), | ||
getInstance() | ||
), | ||
[ | ||
defaultColumn, | ||
flatColumns, | ||
getHeaderGroups, | ||
getInstance, | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
...reduceHooks(getHeaderGroupsDeps(), [], getInstance()), | ||
] | ||
) | ||
getInstance().headerGroups = headerGroups | ||
const headers = React.useMemo( | ||
() => (headerGroups.length ? headerGroups[0].headers : []), | ||
[headerGroups] | ||
) | ||
getInstance().headers = headers | ||
// Access the row model | ||
@@ -292,5 +227,5 @@ const [rows, flatRows] = React.useMemo(() => { | ||
row.values = {} | ||
flatColumns.forEach(column => { | ||
row.values[column.id] = column.accessor | ||
? column.accessor(originalRow, i, { subRows, depth, data }) | ||
flatColumns.forEach(({ id, accessor }) => { | ||
row.values[id] = accessor | ||
? accessor(originalRow, i, { subRows, depth, data }) | ||
: undefined | ||
@@ -311,2 +246,69 @@ }) | ||
// Snapshot hook and disallow more from being added | ||
const flatColumnsHooks = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'flatColumns' | ||
) | ||
// Snapshot hook and disallow more from being added | ||
const flatColumnsDepsHooks = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'flatColumnsDeps' | ||
) | ||
// Get the flat list of all columns AFTER the rows | ||
// have been access, and allow hooks to decorate | ||
// those columns (and trigger this memoization via deps) | ||
flatColumns = React.useMemo( | ||
() => reduceHooks(flatColumnsHooks(), flatColumns, getInstance()), | ||
[ | ||
flatColumns, | ||
flatColumnsHooks, | ||
getInstance, | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
...reduceHooks(flatColumnsDepsHooks(), [], getInstance()), | ||
] | ||
) | ||
getInstance().flatColumns = flatColumns | ||
// Snapshot hook and disallow more from being added | ||
const getHeaderGroups = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'headerGroups' | ||
) | ||
// Snapshot hook and disallow more from being added | ||
const getHeaderGroupsDeps = useConsumeHookGetter( | ||
getInstance().hooks, | ||
'headerGroupsDeps' | ||
) | ||
// Make the headerGroups | ||
const headerGroups = React.useMemo( | ||
() => | ||
reduceHooks( | ||
getHeaderGroups(), | ||
makeHeaderGroups(flatColumns, defaultColumn), | ||
getInstance() | ||
), | ||
[ | ||
defaultColumn, | ||
flatColumns, | ||
getHeaderGroups, | ||
getInstance, | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
...reduceHooks(getHeaderGroupsDeps(), [], getInstance()), | ||
] | ||
) | ||
getInstance().headerGroups = headerGroups | ||
const headers = React.useMemo( | ||
() => (headerGroups.length ? headerGroups[0].headers : []), | ||
[headerGroups] | ||
) | ||
getInstance().headers = headers | ||
// Provide a flat header list for utilities | ||
@@ -351,33 +353,23 @@ getInstance().flatHeaders = headerGroups.reduce( | ||
// prop getter properties here. | ||
getInstance().flatHeaders.forEach(column => { | ||
// Give columns/headers rendering power | ||
column.render = (type, userProps = {}) => { | ||
const Comp = typeof type === 'string' ? column[type] : type | ||
;[...getInstance().flatHeaders, ...getInstance().flatColumns].forEach( | ||
column => { | ||
// Give columns/headers rendering power | ||
column.render = makeRenderer(getInstance(), column) | ||
if (typeof Comp === 'undefined') { | ||
throw new Error(renderErr) | ||
} | ||
// Give columns/headers a default getHeaderProps | ||
column.getHeaderProps = makePropGetter( | ||
getHeaderPropsHooks(), | ||
getInstance(), | ||
column | ||
) | ||
return flexRender(Comp, { | ||
...getInstance(), | ||
column, | ||
...userProps, | ||
}) | ||
// Give columns/headers a default getFooterProps | ||
column.getFooterProps = makePropGetter( | ||
getFooterPropsHooks(), | ||
getInstance(), | ||
column | ||
) | ||
} | ||
) | ||
// Give columns/headers a default getHeaderProps | ||
column.getHeaderProps = makePropGetter( | ||
getHeaderPropsHooks(), | ||
getInstance(), | ||
column | ||
) | ||
// Give columns/headers a default getFooterProps | ||
column.getFooterProps = makePropGetter( | ||
getFooterPropsHooks(), | ||
getInstance(), | ||
column | ||
) | ||
}) | ||
// Snapshot hook and disallow more from being added | ||
@@ -469,2 +461,5 @@ const getHeaderGroupPropsHooks = useConsumeHookGetter( | ||
// Snapshot hook and disallow more from being added | ||
const cellsHooks = useConsumeHookGetter(getInstance().hooks, 'cells') | ||
getInstance().prepareRow = React.useCallback( | ||
@@ -475,42 +470,38 @@ row => { | ||
// Build the visible cells for each row | ||
row.cells = getInstance() | ||
.flatColumns.filter(d => d.isVisible) | ||
.map(column => { | ||
const cell = { | ||
column, | ||
row, | ||
value: row.values[column.id], | ||
} | ||
row.allCells = flatColumns.map(column => { | ||
const cell = { | ||
column, | ||
row, | ||
value: row.values[column.id], | ||
} | ||
// Give each cell a getCellProps base | ||
cell.getCellProps = makePropGetter( | ||
getCellPropsHooks(), | ||
getInstance(), | ||
cell | ||
) | ||
// Give each cell a getCellProps base | ||
cell.getCellProps = makePropGetter( | ||
getCellPropsHooks(), | ||
getInstance(), | ||
cell | ||
) | ||
// Give each cell a renderer function (supports multiple renderers) | ||
cell.render = (type, userProps = {}) => { | ||
const Comp = typeof type === 'string' ? column[type] : type | ||
// Give each cell a renderer function (supports multiple renderers) | ||
cell.render = makeRenderer(getInstance(), column, { | ||
row, | ||
cell, | ||
}) | ||
if (typeof Comp === 'undefined') { | ||
throw new Error(renderErr) | ||
} | ||
return cell | ||
}) | ||
return flexRender(Comp, { | ||
...getInstance(), | ||
column, | ||
row, | ||
cell, | ||
...userProps, | ||
}) | ||
} | ||
row.cells = reduceHooks(cellsHooks(), row.allCells, getInstance()) | ||
return cell | ||
}) | ||
// need to apply any row specific hooks (useExpanded requires this) | ||
loopHooks(getPrepareRowHooks(), row, getInstance()) | ||
}, | ||
[getCellPropsHooks, getInstance, getPrepareRowHooks, getRowPropsHooks] | ||
[ | ||
getRowPropsHooks, | ||
getInstance, | ||
flatColumns, | ||
cellsHooks, | ||
getPrepareRowHooks, | ||
getCellPropsHooks, | ||
] | ||
) | ||
@@ -546,3 +537,3 @@ | ||
loopHooks(getUseFinalInstanceHooks(), [], getInstance()) | ||
loopHooks(getUseFinalInstanceHooks(), getInstance()) | ||
@@ -549,0 +540,0 @@ return getInstance() |
@@ -0,3 +1,5 @@ | ||
const defaultCells = cell => cell.filter(d => d.column.isVisible) | ||
const defaultGetHeaderProps = (props, instance, column) => ({ | ||
key: ['header', column.id].join('_'), | ||
key: `header_${column.id}`, | ||
colSpan: column.totalVisibleHeaderCount, | ||
@@ -8,3 +10,3 @@ ...props, | ||
const defaultGetFooterProps = (props, instance, column) => ({ | ||
key: ['footer', column.id].join('_'), | ||
key: `footer_${column.id}`, | ||
colSpan: column.totalVisibleHeaderCount, | ||
@@ -15,3 +17,3 @@ ...props, | ||
const defaultGetHeaderGroupProps = (props, instance, headerGroup, index) => ({ | ||
key: ['header', index].join('_'), | ||
key: `headerGroup_${index}`, | ||
...props, | ||
@@ -21,3 +23,3 @@ }) | ||
const defaultGetFooterGroupProps = (props, instance, headerGroup, index) => ({ | ||
key: ['footer', index].join('_'), | ||
key: `footerGroup_${index}`, | ||
...props, | ||
@@ -27,3 +29,3 @@ }) | ||
const defaultGetRowProps = (props, instance, row) => ({ | ||
key: ['row', row.id].join('_'), | ||
key: `row_${row.id}`, | ||
...props, | ||
@@ -34,3 +36,3 @@ }) | ||
...props, | ||
key: ['cell', cell.row.id, cell.column.id].join('_'), | ||
key: `cell_${cell.row.id}_${cell.column.id}`, | ||
}) | ||
@@ -51,2 +53,3 @@ | ||
useRows: [], | ||
cells: [defaultCells], | ||
prepareRow: [], | ||
@@ -53,0 +56,0 @@ getTableProps: [], |
@@ -67,3 +67,3 @@ import React from 'react' | ||
<pre> | ||
<code>{JSON.stringify({ expanded }, null, 2)}</code> | ||
<code>{JSON.stringify({ expanded: expanded }, null, 2)}</code> | ||
</pre> | ||
@@ -70,0 +70,0 @@ <table {...getTableProps()}> |
@@ -85,3 +85,32 @@ import React from 'react' | ||
useRowSelect, | ||
useExpanded | ||
useExpanded, | ||
hooks => { | ||
hooks.flatColumns.push(columns => [ | ||
// Let's make a column for selection | ||
{ | ||
id: 'selection', | ||
// The header can use the table's getToggleAllRowsSelectedProps method | ||
// to render a checkbox | ||
Header: ({ getToggleAllRowsSelectedProps }) => ( | ||
<div> | ||
<label> | ||
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />{' '} | ||
Select All | ||
</label> | ||
</div> | ||
), | ||
// The cell can use the individual row's getToggleRowSelectedProps method | ||
// to the render a checkbox | ||
Cell: ({ row }) => ( | ||
<div> | ||
<label> | ||
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />{' '} | ||
Select Row | ||
</label> | ||
</div> | ||
), | ||
}, | ||
...columns, | ||
]) | ||
} | ||
) | ||
@@ -117,10 +146,6 @@ | ||
</table> | ||
<p>Selected Rows: {selectedRowIds.size}</p> | ||
<p>Selected Rows: {Object.keys(selectedRowIds).length}</p> | ||
<pre> | ||
<code> | ||
{JSON.stringify( | ||
{ selectedRowIds: [...selectedRowIds.values()] }, | ||
null, | ||
2 | ||
)} | ||
{JSON.stringify({ selectedRowIds: selectedRowIds }, null, 2)} | ||
</code> | ||
@@ -148,27 +173,3 @@ </pre> | ||
() => [ | ||
// Let's make a column for selection | ||
{ | ||
id: 'selection', | ||
// The header can use the table's getToggleAllRowsSelectedProps method | ||
// to render a checkbox | ||
Header: ({ getToggleAllRowsSelectedProps }) => ( | ||
<div> | ||
<label> | ||
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />{' '} | ||
Select All | ||
</label> | ||
</div> | ||
), | ||
// The cell can use the individual row's getToggleRowSelectedProps method | ||
// to the render a checkbox | ||
Cell: ({ row }) => ( | ||
<div> | ||
<label> | ||
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />{' '} | ||
Select Row | ||
</label> | ||
</div> | ||
), | ||
}, | ||
{ | ||
id: 'selectedStatus', | ||
@@ -175,0 +176,0 @@ Cell: ({ row }) => ( |
@@ -1,2 +0,3 @@ | ||
// Calculating column/cells widths | ||
import { ensurePluginOrder } from '../utils' | ||
const cellStyles = { | ||
@@ -11,2 +12,3 @@ position: 'absolute', | ||
hooks.getHeaderGroupProps.push(getRowStyles) | ||
hooks.useInstance.push(useInstance) | ||
@@ -47,1 +49,7 @@ hooks.getHeaderProps.push((props, instance, header) => [ | ||
] | ||
function useInstance({ plugins }) { | ||
ensurePluginOrder(plugins, [], useAbsoluteLayout.pluginName, [ | ||
'useResizeColumns', | ||
]) | ||
} |
@@ -10,6 +10,8 @@ import React from 'react' | ||
} from '../utils' | ||
import { useConsumeHookGetter } from '../publicUtils' | ||
import { useConsumeHookGetter, functionalUpdate } from '../publicUtils' | ||
// Actions | ||
actions.toggleExpandedById = 'toggleExpandedById' | ||
actions.toggleExpanded = 'toggleExpanded' | ||
actions.toggleAllExpanded = 'toggleAllExpanded' | ||
actions.setExpanded = 'setExpanded' | ||
actions.resetExpanded = 'resetExpanded' | ||
@@ -43,3 +45,3 @@ | ||
return { | ||
expanded: [], | ||
expanded: {}, | ||
...state, | ||
@@ -52,24 +54,37 @@ } | ||
...state, | ||
expanded: [], | ||
expanded: {}, | ||
} | ||
} | ||
if (action.type === actions.toggleExpandedById) { | ||
const { id, expanded } = action | ||
const exists = state.expanded.includes(id) | ||
const shouldExist = typeof expanded !== 'undefined' ? expanded : !exists | ||
let newExpanded = new Set(state.expanded) | ||
if (action.type === actions.setExpanded) { | ||
return { | ||
...state, | ||
expanded: functionalUpdate(action.expanded, state.expanded), | ||
} | ||
} | ||
if (action.type === actions.toggleExpanded) { | ||
const { id, expanded: setExpanded } = action | ||
const exists = state.expanded[id] | ||
const shouldExist = | ||
typeof setExpanded !== 'undefined' ? setExpanded : !exists | ||
if (!exists && shouldExist) { | ||
newExpanded.add(id) | ||
return { | ||
...state, | ||
expanded: { | ||
...state.expanded, | ||
[id]: true, | ||
}, | ||
} | ||
} else if (exists && !shouldExist) { | ||
newExpanded.delete(id) | ||
const { [id]: _, ...rest } = state.expanded | ||
return { | ||
...state, | ||
expanded: rest, | ||
} | ||
} else { | ||
return state | ||
} | ||
return { | ||
...state, | ||
expanded: [...newExpanded.values()], | ||
} | ||
} | ||
@@ -100,4 +115,4 @@ } | ||
const toggleExpandedById = (id, expanded) => { | ||
dispatch({ type: actions.toggleExpandedById, id, expanded }) | ||
const toggleExpanded = (id, expanded) => { | ||
dispatch({ type: actions.toggleExpanded, id, expanded }) | ||
} | ||
@@ -114,3 +129,3 @@ | ||
hooks.prepareRow.push(row => { | ||
row.toggleExpanded = set => instance.toggleExpandedById(row.id, set) | ||
row.toggleExpanded = set => instance.toggleExpanded(row.id, set) | ||
@@ -132,9 +147,11 @@ row.getExpandedToggleProps = makePropGetter( | ||
const expandedDepth = findExpandedDepth(expanded) | ||
const expandedDepth = React.useMemo(() => findExpandedDepth(expanded), [ | ||
expanded, | ||
]) | ||
Object.assign(instance, { | ||
toggleExpandedById, | ||
preExpandedRows: rows, | ||
expandedRows, | ||
rows: expandedRows, | ||
toggleExpanded, | ||
expandedDepth, | ||
@@ -147,3 +164,3 @@ }) | ||
expanded.forEach(id => { | ||
Object.keys(expanded).forEach(id => { | ||
const splitId = id.split('.') | ||
@@ -150,0 +167,0 @@ maxDepth = Math.max(maxDepth, splitId.length) |
@@ -25,6 +25,6 @@ import React from 'react' | ||
function reducer(state, action, previousState, instanceRef) { | ||
function reducer(state, action, previousState, instance) { | ||
if (action.type === actions.init) { | ||
return { | ||
filters: {}, | ||
filters: [], | ||
...state, | ||
@@ -37,3 +37,3 @@ } | ||
...state, | ||
filters: {}, | ||
filters: [], | ||
} | ||
@@ -44,3 +44,4 @@ } | ||
const { columnId, filterValue } = action | ||
const { flatColumns, userFilterTypes } = instanceRef.current | ||
const { flatColumns, userFilterTypes } = instance | ||
const column = flatColumns.find(d => d.id === columnId) | ||
@@ -60,11 +61,26 @@ | ||
const newFilter = functionalUpdate(filterValue, state.filters[columnId]) | ||
const previousfilter = state.filters.find(d => d.id === columnId) | ||
const newFilter = functionalUpdate( | ||
filterValue, | ||
previousfilter && previousfilter.value | ||
) | ||
// | ||
if (shouldAutoRemove(filterMethod.autoRemove, newFilter)) { | ||
const { [columnId]: remove, ...newFilters } = state.filters | ||
return { | ||
...state, | ||
filters: state.filters.filter(d => d.id !== columnId), | ||
} | ||
} | ||
if (previousfilter) { | ||
return { | ||
...state, | ||
filters: newFilters, | ||
filters: state.filters.map(d => { | ||
if (d.id === columnId) { | ||
return { id: columnId, value: newFilter } | ||
} | ||
return d | ||
}), | ||
} | ||
@@ -75,6 +91,3 @@ } | ||
...state, | ||
filters: { | ||
...state.filters, | ||
[columnId]: newFilter, | ||
}, | ||
filters: [...state.filters, { id: columnId, value: newFilter }], | ||
} | ||
@@ -85,23 +98,20 @@ } | ||
const { filters } = action | ||
const { flatColumns, filterTypes: userFilterTypes } = instanceRef.current | ||
const newFilters = functionalUpdate(filters, state.filters) | ||
const { flatColumns, filterTypes: userFilterTypes } = instance | ||
// Filter out undefined values | ||
Object.keys(newFilters).forEach(id => { | ||
const newFilter = newFilters[id] | ||
const column = flatColumns.find(d => d.id === id) | ||
const filterMethod = getFilterMethod( | ||
column.filter, | ||
userFilterTypes || {}, | ||
filterTypes | ||
) | ||
if (shouldAutoRemove(filterMethod.autoRemove, newFilter)) { | ||
delete newFilters[id] | ||
} | ||
}) | ||
return { | ||
...state, | ||
filters: newFilters, | ||
// Filter out undefined values | ||
filters: functionalUpdate(filters, state.filters).filter(filter => { | ||
const column = flatColumns.find(d => d.id === filter.id) | ||
const filterMethod = getFilterMethod( | ||
column.filter, | ||
userFilterTypes || {}, | ||
filterTypes | ||
) | ||
if (shouldAutoRemove(filterMethod.autoRemove, filter.value)) { | ||
return false | ||
} | ||
return true | ||
}), | ||
} | ||
@@ -159,3 +169,4 @@ } | ||
// convenience | ||
column.filterValue = filters[id] | ||
const found = filters.find(d => d.id === id) | ||
column.filterValue = found && found.value | ||
}) | ||
@@ -169,3 +180,3 @@ | ||
const { filteredRows, filteredFlatRows } = React.useMemo(() => { | ||
if (manualFilters || !Object.keys(filters).length) { | ||
if (manualFilters || !filters.length) { | ||
return { | ||
@@ -183,4 +194,4 @@ filteredRows: rows, | ||
filteredRows = Object.entries(filters).reduce( | ||
(filteredSoFar, [columnId, filterValue]) => { | ||
filteredRows = filters.reduce( | ||
(filteredSoFar, { id: columnId, value: filterValue }) => { | ||
// Find the filters column | ||
@@ -255,3 +266,3 @@ const column = flatColumns.find(d => d.id === columnId) | ||
const nonFilteredColumns = flatColumns.filter( | ||
column => !Object.keys(filters).includes(column.id) | ||
column => !filters.find(d => d.id === column.id) | ||
) | ||
@@ -276,4 +287,2 @@ | ||
Object.assign(instance, { | ||
setFilter, | ||
setAllFilters, | ||
preFilteredRows: rows, | ||
@@ -285,2 +294,4 @@ preFilteredFlatRows: flatRows, | ||
flatRows: filteredFlatRows, | ||
setFilter, | ||
setAllFilters, | ||
}) | ||
@@ -287,0 +298,0 @@ } |
@@ -91,11 +91,10 @@ import React from 'react' | ||
// If a groupByBoundary column is found, place the groupBy's after it | ||
const groupByBoundaryColumnIndex = | ||
flatColumns.findIndex(column => column.groupByBoundary) + 1 | ||
flatColumns = [...groupByColumns, ...nonGroupByColumns] | ||
return [ | ||
...nonGroupByColumns.slice(0, groupByBoundaryColumnIndex), | ||
...groupByColumns, | ||
...nonGroupByColumns.slice(groupByBoundaryColumnIndex), | ||
] | ||
flatColumns.forEach(column => { | ||
column.isGrouped = groupBy.includes(column.id) | ||
column.groupedIndex = groupBy.indexOf(column.id) | ||
}) | ||
return flatColumns | ||
} | ||
@@ -114,4 +113,2 @@ | ||
manualGroupBy, | ||
defaultCanGroupBy, | ||
disableGroupBy, | ||
aggregations: userAggregations = defaultUserAggregations, | ||
@@ -124,2 +121,4 @@ hooks, | ||
manaulGroupBy, | ||
disableGroupBy, | ||
defaultCanGroupBy, | ||
} = instance | ||
@@ -133,3 +132,2 @@ | ||
const { | ||
id, | ||
accessor, | ||
@@ -139,4 +137,2 @@ defaultGroupBy: defaultColumnGroupBy, | ||
} = column | ||
column.isGrouped = groupBy.includes(id) | ||
column.groupedIndex = groupBy.indexOf(id) | ||
@@ -152,3 +148,3 @@ column.canGroupBy = accessor | ||
if (column.canGroupBy) { | ||
column.toggleGroupBy = () => toggleGroupBy(column.id) | ||
column.toggleGroupBy = () => instance.toggleGroupBy(column.id) | ||
} | ||
@@ -177,3 +173,3 @@ | ||
hooks.prepareRow.push(row => { | ||
row.cells.forEach(cell => { | ||
row.allCells.forEach(cell => { | ||
// Grouped cells are in the groupBy and the pivot cell for the row | ||
@@ -246,6 +242,5 @@ cell.isGrouped = cell.column.isGrouped && cell.column.id === row.groupByID | ||
// Recursively group the data | ||
const groupRecursively = (rows, depth = 0) => { | ||
const groupRecursively = (rows, depth = 0, parentId) => { | ||
// This is the last level, just return the rows | ||
if (depth >= groupBy.length) { | ||
groupedFlatRows = groupedFlatRows.concat(rows) | ||
if (depth === groupBy.length) { | ||
return rows | ||
@@ -262,5 +257,6 @@ } | ||
([groupByVal, subRows], index) => { | ||
const id = `${columnId}:${groupByVal}` | ||
let id = `${columnId}:${groupByVal}` | ||
id = parentId ? `${parentId}>${id}` : id | ||
subRows = groupRecursively(subRows, depth + 1) | ||
subRows = groupRecursively(subRows, depth + 1, id) | ||
@@ -271,3 +267,3 @@ const values = aggregateRowsToValues(subRows, depth < groupBy.length) | ||
id, | ||
isAggregated: true, | ||
isGrouped: true, | ||
groupByID: columnId, | ||
@@ -281,3 +277,3 @@ groupByVal, | ||
groupedFlatRows.push(row) | ||
groupedFlatRows.push(row, ...subRows) | ||
@@ -314,9 +310,10 @@ return row | ||
Object.assign(instance, { | ||
preGroupedRows: rows, | ||
preGroupedFlatRow: flatRows, | ||
groupedRows, | ||
groupedFlatRows, | ||
toggleGroupBy, | ||
rows: groupedRows, | ||
flatRows: groupedFlatRows, | ||
preGroupedRows: rows, | ||
toggleGroupBy, | ||
}) | ||
} |
@@ -28,3 +28,3 @@ import React from 'react' | ||
function reducer(state, action, previousState, instanceRef) { | ||
function reducer(state, action, previousState, instance) { | ||
if (action.type === actions.init) { | ||
@@ -46,3 +46,3 @@ return { | ||
if (action.type === actions.gotoPage) { | ||
const { pageCount } = instanceRef.current | ||
const { pageCount } = instance | ||
const newPageIndex = functionalUpdate(action.pageIndex, state.pageIndex) | ||
@@ -49,0 +49,0 @@ |
@@ -20,2 +20,7 @@ import { | ||
hooks.getResizerProps = [defaultGetResizerProps] | ||
hooks.getHeaderProps.push({ | ||
style: { | ||
position: 'relative', | ||
}, | ||
}) | ||
hooks.stateReducers.push(reducer) | ||
@@ -192,12 +197,5 @@ hooks.useInstanceBeforeDimensions.push(useInstanceBeforeDimensions) | ||
disableResizing, | ||
hooks: { getHeaderProps }, | ||
state: { columnResizing }, | ||
} = instance | ||
getHeaderProps.push({ | ||
style: { | ||
position: 'relative', | ||
}, | ||
}) | ||
const getInstance = useGetLatest(instance) | ||
@@ -204,0 +202,0 @@ |
@@ -67,3 +67,4 @@ import React from 'react' | ||
indeterminate: Boolean( | ||
!instance.isAllRowsSelected && instance.state.selectedRowIds.size | ||
!instance.isAllRowsSelected && | ||
Object.keys(instance.state.selectedRowIds).length | ||
), | ||
@@ -73,6 +74,6 @@ }, | ||
function reducer(state, action, previousState, instanceRef) { | ||
function reducer(state, action, previousState, instance) { | ||
if (action.type === actions.init) { | ||
return { | ||
selectedRowIds: new Set(), | ||
selectedRowIds: {}, | ||
...state, | ||
@@ -85,3 +86,3 @@ } | ||
...state, | ||
selectedRowIds: new Set(), | ||
selectedRowIds: {}, | ||
} | ||
@@ -92,3 +93,3 @@ } | ||
const { selected } = action | ||
const { isAllRowsSelected, flatRowsById } = instanceRef.current | ||
const { isAllRowsSelected, flatRowsById } = instance | ||
@@ -98,5 +99,18 @@ const selectAll = | ||
if (selectAll) { | ||
const selectedRowIds = {} | ||
Object.keys(flatRowsById).forEach(rowId => { | ||
selectedRowIds[rowId] = true | ||
}) | ||
return { | ||
...state, | ||
selectedRowIds, | ||
} | ||
} | ||
return { | ||
...state, | ||
selectedRowIds: selectAll ? new Set(flatRowsById.keys()) : new Set(), | ||
selectedRowIds: {}, | ||
} | ||
@@ -107,3 +121,3 @@ } | ||
const { id, selected } = action | ||
const { flatGroupedRowsById } = instanceRef.current | ||
const { flatGroupedRowsById } = instance | ||
@@ -113,5 +127,5 @@ // Join the ids of deep rows | ||
// in a flat object | ||
const row = flatGroupedRowsById.get(id) | ||
const row = flatGroupedRowsById[id] | ||
const isSelected = row.isSelected | ||
const shouldExist = typeof set !== 'undefined' ? selected : !isSelected | ||
const shouldExist = typeof selected !== 'undefined' ? selected : !isSelected | ||
@@ -122,12 +136,12 @@ if (isSelected === shouldExist) { | ||
let newSelectedRowPaths = new Set(state.selectedRowIds) | ||
let newSelectedRowPaths = { ...state.selectedRowIds } | ||
const handleRowById = id => { | ||
const row = flatGroupedRowsById.get(id) | ||
const row = flatGroupedRowsById[id] | ||
if (!row.isAggregated) { | ||
if (!row.isGrouped) { | ||
if (!isSelected && shouldExist) { | ||
newSelectedRowPaths.add(id) | ||
newSelectedRowPaths[id] = true | ||
} else if (isSelected && !shouldExist) { | ||
newSelectedRowPaths.delete(id) | ||
delete newSelectedRowPaths[id] | ||
} | ||
@@ -193,19 +207,21 @@ } | ||
const [flatRowsById, flatGroupedRowsById] = React.useMemo(() => { | ||
const map = new Map() | ||
const groupedMap = new Map() | ||
const all = {} | ||
const grouped = {} | ||
flatRows.forEach(row => { | ||
if (!row.isAggregated) { | ||
map.set(row.id, row) | ||
if (!row.isGrouped) { | ||
all[row.id] = row | ||
} | ||
groupedMap.set(row.id, row) | ||
grouped[row.id] = row | ||
}) | ||
return [map, groupedMap] | ||
return [all, grouped] | ||
}, [flatRows]) | ||
let isAllRowsSelected = Boolean(flatRowsById.size && selectedRowIds.size) | ||
let isAllRowsSelected = Boolean( | ||
Object.keys(flatRowsById).length && Object.keys(selectedRowIds).length | ||
) | ||
if (isAllRowsSelected) { | ||
if ([...flatRowsById.keys()].some(d => !selectedRowIds.has(d))) { | ||
if (Object.keys(flatRowsById).some(id => !selectedRowIds[id])) { | ||
isAllRowsSelected = false | ||
@@ -267,7 +283,7 @@ } | ||
function getRowIsSelected(row, selectedRowIds) { | ||
if (selectedRowIds.has(row.id)) { | ||
if (selectedRowIds[row.id]) { | ||
return true | ||
} | ||
if (row.isAggregated || (row.subRows && row.subRows.length)) { | ||
if (row.subRows && row.subRows.length) { | ||
let allChildrenSelected = true | ||
@@ -274,0 +290,0 @@ let someSelected = false |
@@ -58,3 +58,3 @@ import React from 'react' | ||
// Reducer | ||
function reducer(state, action, previousState, instanceRef) { | ||
function reducer(state, action, previousState, instance) { | ||
if (action.type === actions.init) { | ||
@@ -93,3 +93,3 @@ return { | ||
maxMultiSortColCount = Number.MAX_SAFE_INTEGER, | ||
} = instanceRef.current | ||
} = instance | ||
@@ -340,7 +340,7 @@ const { sortBy } = state | ||
Object.assign(instance, { | ||
toggleSortBy, | ||
preSortedRows: rows, | ||
sortedRows, | ||
rows: sortedRows, | ||
toggleSortBy, | ||
}) | ||
} |
import React from 'react' | ||
let renderErr = 'Renderer Error' | ||
export const actions = { | ||
@@ -8,3 +10,3 @@ init: 'init', | ||
export const defaultColumn = { | ||
Cell: ({ cell: { value = '' } }) => String(value), | ||
Cell: ({ cell: { value = '' } }) => value, | ||
width: 150, | ||
@@ -47,9 +49,16 @@ minWidth: 0, | ||
...rest, | ||
style: { | ||
...(props.style || {}), | ||
...(style || {}), | ||
}, | ||
className: [props.className, className].filter(Boolean).join(' '), | ||
} | ||
if (style) { | ||
props.style = props.style | ||
? { ...(props.style || {}), ...(style || {}) } | ||
: style | ||
} | ||
if (className) { | ||
props.className = props.className | ||
? props.className + ' ' + className | ||
: className | ||
} | ||
if (props.className === '') { | ||
@@ -225,1 +234,47 @@ delete props.className | ||
} | ||
export function makeRenderer(instance, column, meta = {}) { | ||
return (type, userProps = {}) => { | ||
const Comp = typeof type === 'string' ? column[type] : type | ||
if (typeof Comp === 'undefined') { | ||
throw new Error(renderErr) | ||
} | ||
return flexRender(Comp, { ...instance, column, ...meta, ...userProps }) | ||
} | ||
} | ||
export function flexRender(Comp, props) { | ||
return isReactComponent(Comp) ? <Comp {...props} /> : Comp | ||
} | ||
function isClassComponent(component) { | ||
return ( | ||
typeof component === 'function' && | ||
!!(() => { | ||
let proto = Object.getPrototypeOf(component) | ||
return proto.prototype && proto.prototype.isReactComponent | ||
})() | ||
) | ||
} | ||
function isFunctionComponent(component) { | ||
return typeof component === 'function' | ||
} | ||
function isExoticComponent(component) { | ||
return ( | ||
typeof component === 'object' && | ||
typeof component.$$typeof === 'symbol' && | ||
['react.memo', 'react.forward_ref'].includes(component.$$typeof.description) | ||
) | ||
} | ||
function isReactComponent(component) { | ||
return ( | ||
isClassComponent(component) || | ||
isFunctionComponent(component) || | ||
isExoticComponent(component) | ||
) | ||
} |
import React from 'react' | ||
// Token pagination behaves a bit differently from | ||
// Token pagination behaves a bit different from | ||
// index based pagination. This hook aids in that process. | ||
@@ -5,0 +5,0 @@ |
@@ -222,24 +222,2 @@ import React from 'react' | ||
export function flexRender(Comp, props) { | ||
return isReactComponent(Comp) ? <Comp {...props} /> : Comp | ||
} | ||
function isClassComponent(component) { | ||
return ( | ||
typeof component === 'function' && | ||
!!(() => { | ||
let proto = Object.getPrototypeOf(component) | ||
return proto.prototype && proto.prototype.isReactComponent | ||
})() | ||
) | ||
} | ||
function isFunctionComponent(component) { | ||
return typeof component === 'function' | ||
} | ||
function isReactComponent(component) { | ||
return isClassComponent(component) || isFunctionComponent(component) | ||
} | ||
export function isFunction(a) { | ||
@@ -277,4 +255,3 @@ if (typeof a === 'function') { | ||
row.isExpanded = | ||
(row.original && row.original[manualExpandedKey]) || | ||
expanded.includes(row.id) | ||
(row.original && row.original[manualExpandedKey]) || expanded[row.id] | ||
@@ -281,0 +258,0 @@ row.canExpand = row.subRows && !!row.subRows.length |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
761934
10205
214