fix: fix path getters, better plugin hook integration, renaming things

This commit is contained in:
tannerlinsley
2019-08-19 16:38:42 -06:00
parent 93524d0701
commit f59efde6fe
15 changed files with 208 additions and 112 deletions

View File

@@ -73,7 +73,7 @@ function Table({ columns, data }) {
{column.canGroupBy ? (
// If the column can be grouped, let's add a toggle
<span {...column.getGroupByToggleProps()}>
{column.grouped ? '🛑' : '👊'}
{column.isGrouped ? '🛑' : '👊'}
</span>
) : null}
{column.render('Header')}
@@ -90,7 +90,7 @@ function Table({ columns, data }) {
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>
{cell.grouped ? (
{cell.isGrouped ? (
<>
<span
style={{
@@ -102,9 +102,9 @@ function Table({ columns, data }) {
</span>
{cell.render('Cell')} ({row.subRows.length})
</>
) : cell.aggregated ? (
) : cell.isAggregated ? (
cell.render('Aggregated')
) : cell.repeatedValue ? null : (
) : cell.isRepeatedValue ? null : (
cell.render('Cell')
)}
</td>

View File

@@ -120,7 +120,7 @@ function App() {
{
id: 'selectedStatus',
Cell: ({ row }) => (
<div>{row.selected ? 'Selected' : 'Not Selected'}</div>
<div>{row.isSelected ? 'Selected' : 'Not Selected'}</div>
),
},
{

View File

@@ -56,7 +56,7 @@ function Table({ columns, data }) {
{column.render('Header')}
{/* Add a sort direction indicator */}
<span>
{column.sorted ? (column.sortedDesc ? ' 🔽' : ' 🔼') : ''}
{column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : ''}
</span>
</th>
))}

View File

@@ -17,7 +17,7 @@ addActions('toggleExpanded', 'useExpanded')
const propTypes = {
manualExpandedKey: PropTypes.string,
nestExpandedRows: PropTypes.bool,
paginateExpandedRows: PropTypes.bool,
}
export const useExpanded = hooks => {
@@ -34,16 +34,16 @@ function useMain(instance) {
debug,
rows,
manualExpandedKey = 'expanded',
paginateExpandedRows = true,
hooks,
state: [{ expanded }, setState],
nestExpandedRows,
} = instance
const toggleExpandedByPath = (path, set) => {
return setState(old => {
const { expanded } = old
const existing = getBy(expanded, path)
set = getFirstDefined(set, !existing)
set = getFirstDefined(set, existing ? undefined : true)
return {
...old,
expanded: setBy(expanded, path, set),
@@ -85,13 +85,16 @@ function useMain(instance) {
(row.original && row.original[manualExpandedKey]) ||
getBy(expanded, row.path)
if (!nestExpandedRows || (nestExpandedRows && row.depth === 0)) {
expandedRows.push(row)
}
expandedRows.push(row)
row.canExpand = row.subRows && !!row.subRows.length
if (row.isExpanded && row.subRows && row.subRows.length) {
if (
paginateExpandedRows &&
row.isExpanded &&
row.subRows &&
row.subRows.length
) {
row.subRows.forEach(handleRow)
}
@@ -101,7 +104,7 @@ function useMain(instance) {
rows.forEach(handleRow)
return expandedRows
}, [debug, rows, manualExpandedKey, expanded, nestExpandedRows])
}, [debug, rows, manualExpandedKey, expanded, paginateExpandedRows])
const expandedDepth = findExpandedDepth(expanded)

View File

@@ -9,6 +9,7 @@ import {
applyPropHooks,
defaultGroupByFn,
getFirstDefined,
ensurePluginOrder,
} from '../utils'
defaultState.groupBy = []
@@ -50,9 +51,18 @@ useGroupBy.pluginName = 'useGroupBy'
function columnsBeforeHeaderGroups(columns, { state: [{ groupBy }] }) {
// Sort grouped columns to the start of the column list
// before the headers are built
const groupByColumns = groupBy.map(g => columns.find(col => col.id === g))
const nonGroupByColumns = columns.filter(col => !groupBy.includes(col.id))
// If a groupByBoundary column is found, place the groupBy's after it
const groupByBoundaryColumnIndex =
columns.findIndex(column => column.groupByBoundary) + 1
return [
...groupBy.map(g => columns.find(col => col.id === g)),
...columns.filter(col => !groupBy.includes(col.id)),
...nonGroupByColumns.slice(0, groupByBoundaryColumnIndex),
...groupByColumns,
...nonGroupByColumns.slice(groupByBoundaryColumnIndex),
]
}
@@ -69,12 +79,15 @@ function useMain(instance) {
disableGrouping,
aggregations: userAggregations = {},
hooks,
plugins,
state: [{ groupBy }, setState],
} = instance
ensurePluginOrder(plugins, [], 'useGroupBy', ['useExpanded'])
columns.forEach(column => {
const { id, accessor, disableGrouping: columnDisableGrouping } = column
column.grouped = groupBy.includes(id)
column.isGrouped = groupBy.includes(id)
column.groupedIndex = groupBy.indexOf(id)
column.canGroupBy = accessor
@@ -137,11 +150,12 @@ function useMain(instance) {
hooks.prepareRow.push(row => {
row.cells.forEach(cell => {
// Grouped cells are in the groupBy and the pivot cell for the row
cell.grouped = cell.column.grouped && cell.column.id === row.groupByID
cell.isGrouped = cell.column.isGrouped && cell.column.id === row.groupByID
// Repeated cells are any columns in the groupBy that are not grouped
cell.repeatedValue = !cell.grouped && cell.column.grouped
cell.isRepeatedValue = !cell.isGrouped && cell.column.isGrouped
// Aggregated cells are not grouped, not repeated, but still have subRows
cell.aggregated = !cell.grouped && !cell.repeatedValue && row.canExpand
cell.isAggregated =
!cell.isGrouped && !cell.isRepeatedValue && row.canExpand
})
return row
})
@@ -218,7 +232,7 @@ function useMain(instance) {
// Recurse to sub rows before aggregation
groupedRows = Object.entries(groupedRows).map(
([groupByVal, subRows], index) => {
const path = [...parentPath, groupByVal]
const path = [...parentPath, `${columnID}:${groupByVal}`]
subRows = groupRecursively(subRows, depth + 1, path)
@@ -228,6 +242,7 @@ function useMain(instance) {
)
const row = {
isAggregated: true,
groupByID: columnID,
groupByVal,
values,

View File

@@ -14,6 +14,7 @@ addActions('pageChange', 'pageSizeChange')
const propTypes = {
// General
manualPagination: PropTypes.bool,
paginateExpandedRows: PropTypes.bool,
}
// SSR has issues with useLayoutEffect still, so use useEffect during SSR
@@ -32,28 +33,30 @@ function useMain(instance) {
PropTypes.checkPropTypes(propTypes, instance, 'property', 'usePagination')
const {
data,
rows,
manualPagination,
disablePageResetOnDataChange,
debug,
plugins,
pageCount: userPageCount,
paginateExpandedRows = true,
state: [{ pageSize, pageIndex, filters, groupBy, sortBy }, setState],
} = instance
ensurePluginOrder(
plugins,
['useFilters', 'useGroupBy', 'useSortBy'],
['useFilters', 'useGroupBy', 'useSortBy', 'useExpanded'],
'usePagination',
[]
)
const rowDep = manualPagination || disablePageResetOnDataChange ? null : rows
const rowDep = manualPagination ? null : data
const isPageIndexMountedRef = React.useRef()
useLayoutEffect(() => {
if (isPageIndexMountedRef.current) {
if (isPageIndexMountedRef.current && !disablePageResetOnDataChange) {
setState(
old => ({
...old,
@@ -63,38 +66,51 @@ function useMain(instance) {
)
}
isPageIndexMountedRef.current = true
}, [setState, rowDep, filters, groupBy, sortBy])
}, [setState, rowDep, filters, groupBy, sortBy, disablePageResetOnDataChange])
const pages = React.useMemo(() => {
if (manualPagination) {
return undefined
}
if (process.env.NODE_ENV === 'development' && debug)
console.info('getPages')
// Create a new pages with the first page ready to go.
const pages = rows.length ? [] : [[]]
// Start the pageIndex and currentPage cursors
let cursor = 0
while (cursor < rows.length) {
const end = cursor + pageSize
pages.push(rows.slice(cursor, end))
cursor = end
}
return pages
}, [debug, manualPagination, pageSize, rows])
const pageCount = manualPagination ? userPageCount : pages.length
const pageCount = manualPagination
? userPageCount
: Math.ceil(rows.length / pageSize)
const pageOptions = React.useMemo(
() => (pageCount > 0 ? [...new Array(pageCount)].map((d, i) => i) : []),
[pageCount]
)
const page = manualPagination ? rows : pages[pageIndex]
const page = React.useMemo(() => {
let page
if (manualPagination) {
page = rows
} else {
if (process.env.NODE_ENV === 'development' && debug)
console.info('getPage')
const pageStart = pageSize * pageIndex
const pageEnd = pageStart + pageSize
page = rows.slice(pageStart, pageEnd)
}
if (paginateExpandedRows) {
return page
}
const expandedPage = []
const handleRow = row => {
expandedPage.push(row)
if (row.subRows && row.subRows.length && row.isExpanded) {
row.subRows.forEach(handleRow)
}
}
page.forEach(handleRow)
return expandedPage
}, [debug, manualPagination, pageIndex, pageSize, paginateExpandedRows, rows])
const canPreviousPage = pageIndex > 0
const canNextPage = pageCount === -1 || pageIndex < pageCount - 1
@@ -134,7 +150,6 @@ function useMain(instance) {
return {
...instance,
pages,
pageOptions,
pageCount,
page,

View File

@@ -25,7 +25,7 @@ function useMain(instance) {
const {
hooks,
manualRowSelectedKey = 'selected',
manualRowSelectedKey = 'isSelected',
plugins,
rowPaths,
state: [{ selectedRows }, setState],
@@ -59,7 +59,7 @@ function useMain(instance) {
// in a flat object
const exists = old.selectedRows.includes(key)
const shouldExist = typeof set !== 'undefined' ? set : !exists
let newSelectedRows = new Set(selectedRows)
let newSelectedRows = new Set(old.selectedRows)
if (!exists && shouldExist) {
newSelectedRows.add(key)
@@ -94,10 +94,49 @@ function useMain(instance) {
}
hooks.prepareRow.push(row => {
row.canSelect = !!row.original
// Aggregate rows have entirely different select logic
if (row.isAggregated) {
const subRowPaths = row.subRows.map(row => row.path)
row.isSelected = subRowPaths.every(path =>
selectedRows.includes(path.join('.'))
)
row.toggleRowSelected = set => {
set = typeof set !== 'undefined' ? set : !row.isSelected
console.log(subRowPaths)
subRowPaths.forEach(path => {
toggleRowSelected(path, set)
})
}
row.getToggleRowSelectedProps = props => {
let checked = false
if (row.canSelect) {
row.selected = selectedRows.includes(row.path.join('.'))
if (row.original && row.original[manualRowSelectedKey]) {
checked = true
} else {
checked = row.isSelected
}
return mergeProps(
{
onChange: e => {
row.toggleRowSelected(e.target.checked)
},
style: {
cursor: 'pointer',
},
checked,
title: 'Toggle Row Selected',
},
applyPropHooks(
instance.hooks.getToggleRowSelectedProps,
row,
instance
),
props
)
}
} else {
row.isSelected = selectedRows.includes(row.path.join('.'))
row.toggleRowSelected = set => toggleRowSelected(row.path, set)
row.getToggleRowSelectedProps = props => {
let checked = false
@@ -105,7 +144,7 @@ function useMain(instance) {
if (row.original && row.original[manualRowSelectedKey]) {
checked = true
} else {
checked = selectedRows.includes(row.path.join('.'))
checked = row.isSelected
}
return mergeProps(

View File

@@ -64,7 +64,7 @@ function useMain(instance) {
plugins,
} = instance
ensurePluginOrder(plugins, [], 'useSortBy', ['useFilters'])
ensurePluginOrder(plugins, ['useFilters'], 'useSortBy', [])
// Add custom hooks
hooks.getSortByToggleProps = []
@@ -197,9 +197,10 @@ function useMain(instance) {
)
}
column.sorted = sortBy.find(d => d.id === id)
const columnSort = sortBy.find(d => d.id === id)
column.isSorted = !!columnSort
column.sortedIndex = sortBy.findIndex(d => d.id === id)
column.sortedDesc = column.sorted ? column.sorted.desc : undefined
column.isSortedDesc = column.isSorted ? columnSort.desc : undefined
})
const sortedRows = React.useMemo(() => {

View File

@@ -196,6 +196,7 @@ export function defaultGroupByFn(rows, columnID) {
}
export function setBy(obj = {}, path, value) {
path = makePathArray(path)
const recurse = (obj, depth = 0) => {
const key = path[depth]
const target = typeof obj[key] !== 'object' ? {} : obj[key]
@@ -347,11 +348,18 @@ This usually means you need to need to name your plugin hook by setting the 'plu
//
function makePathArray(obj) {
return flattenDeep(obj)
.join('.')
.replace(/\[/g, '.')
.replace(/\]/g, '')
.split('.')
return (
flattenDeep(obj)
// remove all periods in parts
.map(d => String(d).replace('.', '_'))
// join parts using period
.join('.')
// replace brackets with periods
.replace(/\[/g, '.')
.replace(/\]/g, '')
// split it back out on periods
.split('.')
)
}
function flattenDeep(arr, newArr = []) {