Compare commits

...
4 changed files with 89 additions and 117 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "react-table", "name": "react-table",
"version": "6.9.0", "version": "6.9.2",
"description": "A fast, lightweight, opinionated table and datagrid built on React", "description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT", "license": "MIT",
"homepage": "https://github.com/react-tools/react-table#readme", "homepage": "https://github.com/react-tools/react-table#readme",
+17 -20
View File
@@ -124,7 +124,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
PadRowComponent, PadRowComponent,
// Data model // Data model
resolvedData, resolvedData,
visibleColumns, allVisibleColumns,
headerGroups, headerGroups,
hasHeaderGroups, hasHeaderGroups,
// Sorted Data // Sorted Data
@@ -139,8 +139,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const minRows = this.getMinRows() const minRows = this.getMinRows()
const padRows = _.range(Math.max(minRows - pageRows.length, 0)) const padRows = _.range(Math.max(minRows - pageRows.length, 0))
const hasColumnFooter = visibleColumns.some(d => d.Footer) const hasColumnFooter = allVisibleColumns.some(d => d.Footer)
const hasFilters = filterable || visibleColumns.some(d => d.filterable) const hasFilters = filterable || allVisibleColumns.some(d => d.filterable)
const recurseRowsViewIndex = (rows, path = [], index = -1) => [ const recurseRowsViewIndex = (rows, path = [], index = -1) => [
rows.map((row, i) => { rows.map((row, i) => {
@@ -167,7 +167,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const canNext = page + 1 < pages const canNext = page + 1 < pages
const rowMinWidth = _.sum( const rowMinWidth = _.sum(
visibleColumns.map(d => { allVisibleColumns.map(d => {
const resizedColumn = resized.find(x => x.id === d.id) || {} const resizedColumn = resized.find(x => x.id === d.id) || {}
return _.getFirstDefined(resizedColumn.value, d.width, d.minWidth) return _.getFirstDefined(resizedColumn.value, d.width, d.minWidth)
}) })
@@ -198,16 +198,14 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const makeHeaderGroup = (column, i) => { const makeHeaderGroup = (column, i) => {
const resizedValue = col => (resized.find(x => x.id === col.id) || {}).value const resizedValue = col => (resized.find(x => x.id === col.id) || {}).value
const leafColumns = _.leaves(column, 'columns')
const flex = _.sum( const flex = _.sum(
leafColumns.map(col => (col.width || resizedValue(col) ? 0 : col.minWidth)) column.columns.map(col => (col.width || resizedValue(col) ? 0 : col.minWidth))
) )
const width = _.sum( const width = _.sum(
leafColumns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.minWidth)) column.columns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.minWidth))
) )
const maxWidth = _.sum( const maxWidth = _.sum(
leafColumns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.maxWidth)) column.columns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.maxWidth))
) )
const theadGroupThProps = _.splitProps( const theadGroupThProps = _.splitProps(
@@ -258,12 +256,11 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
) )
} }
const makeHeaderGroups = (row, i) => { const makeHeaderGroups = () => {
const theadGroupProps = _.splitProps(getTheadGroupProps(finalState, undefined, row, this)) const theadGroupProps = _.splitProps(getTheadGroupProps(finalState, undefined, undefined, this))
const theadGroupTrProps = _.splitProps(getTheadGroupTrProps(finalState, undefined, row, this)) const theadGroupTrProps = _.splitProps(getTheadGroupTrProps(finalState, undefined, undefined, this))
return ( return (
<TheadComponent <TheadComponent
key={`${i}-${row.id}`}
className={classnames('-headerGroups', theadGroupProps.className)} className={classnames('-headerGroups', theadGroupProps.className)}
style={{ style={{
...theadGroupProps.style, ...theadGroupProps.style,
@@ -276,7 +273,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={theadGroupTrProps.style} style={theadGroupTrProps.style}
{...theadGroupTrProps.rest} {...theadGroupTrProps.rest}
> >
{row.map(makeHeaderGroup)} {headerGroups.map(makeHeaderGroup)}
</TrComponent> </TrComponent>
</TheadComponent> </TheadComponent>
) )
@@ -367,7 +364,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={theadTrProps.style} style={theadTrProps.style}
{...theadTrProps.rest} {...theadTrProps.rest}
> >
{visibleColumns.map(makeHeader)} {allVisibleColumns.map(makeHeader)}
</TrComponent> </TrComponent>
</TheadComponent> </TheadComponent>
) )
@@ -455,7 +452,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={theadFilterTrProps.style} style={theadFilterTrProps.style}
{...theadFilterTrProps.rest} {...theadFilterTrProps.rest}
> >
{visibleColumns.map(makeFilter)} {allVisibleColumns.map(makeFilter)}
</TrComponent> </TrComponent>
</TheadComponent> </TheadComponent>
) )
@@ -485,7 +482,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={trProps.style} style={trProps.style}
{...trProps.rest} {...trProps.rest}
> >
{visibleColumns.map((column, i2) => { {allVisibleColumns.map((column, i2) => {
const resizedCol = resized.find(x => x.id === column.id) || {} const resizedCol = resized.find(x => x.id === column.id) || {}
const show = typeof column.show === 'function' ? column.show() : column.show const show = typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth) const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
@@ -723,7 +720,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
)} )}
style={trProps.style || {}} style={trProps.style || {}}
> >
{visibleColumns.map(makePadColumn)} {allVisibleColumns.map(makePadColumn)}
</TrComponent> </TrComponent>
</TrGroupComponent> </TrGroupComponent>
) )
@@ -793,7 +790,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={tFootTrProps.style} style={tFootTrProps.style}
{...tFootTrProps.rest} {...tFootTrProps.rest}
> >
{visibleColumns.map(makeColumnFooter)} {allVisibleColumns.map(makeColumnFooter)}
</TrComponent> </TrComponent>
</TfootComponent> </TfootComponent>
) )
@@ -836,7 +833,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={tableProps.style} style={tableProps.style}
{...tableProps.rest} {...tableProps.rest}
> >
{hasHeaderGroups ? headerGroups.map(makeHeaderGroups) : null} {hasHeaderGroups ? makeHeaderGroups() : null}
{makeHeaders()} {makeHeaders()}
{hasFilters ? makeFilters() : null} {hasFilters ? makeFilters() : null}
<TbodyComponent <TbodyComponent
+71 -76
View File
@@ -31,17 +31,27 @@ export default Base =>
} = newState } = newState
// Determine if there are Header Groups // Determine if there are Header Groups
const hasHeaderGroups = columns.some(column => column.columns) let hasHeaderGroups = false
columns.forEach(column => {
if (column.columns) {
hasHeaderGroups = true
}
})
// Find the expander column which could be deep in tree of columns let columnsWithExpander = [...columns]
const allColumns = _.iterTree(columns, 'columns')
const expanderColumn = _.getFirstDefined(allColumns)
let expanderColumn = columns.find(
col => col.expander || (col.columns && col.columns.some(col2 => col2.expander))
)
if (expanderColumn && !expanderColumn.expander) {
expanderColumn = expanderColumn.columns.find(col => col.expander)
}
// If we have SubComponent's we need to make sure we have an expander column // If we have SubComponent's we need to make sure we have an expander column
const hasSubComponentAndNoExpanderColumn = SubComponent && !expanderColumn if (SubComponent && !expanderColumn) {
const columnsWithExpander = hasSubComponentAndNoExpanderColumn expanderColumn = { expander: true }
? [{ expander: true }, ...columns] columnsWithExpander = [expanderColumn, ...columnsWithExpander]
: [...columns] }
const makeDecoratedColumn = (column, parentColumn) => { const makeDecoratedColumn = (column, parentColumn) => {
let dcol let dcol
@@ -53,7 +63,6 @@ export default Base =>
} }
} else { } else {
dcol = { dcol = {
...this.props.column,
...this.props.column, ...this.props.column,
...column, ...column,
} }
@@ -95,31 +104,40 @@ export default Base =>
const allDecoratedColumns = [] const allDecoratedColumns = []
// Decorate the columns // Decorate the columns
const decorateAndAddToAll = (columns, parentColumn) => columns.map(column => { const decorateAndAddToAll = (column, parentColumn) => {
const decoratedColumn = makeDecoratedColumn(column, parentColumn) const decoratedColumn = makeDecoratedColumn(column, parentColumn)
if (column.columns) {
decoratedColumn.columns = decorateAndAddToAll(column.columns, column)
}
allDecoratedColumns.push(decoratedColumn) allDecoratedColumns.push(decoratedColumn)
return decoratedColumn return decoratedColumn
}
const decoratedColumns = columnsWithExpander.map(column => {
if (column.columns) {
return {
...column,
columns: column.columns.map(d => decorateAndAddToAll(d, column)),
}
}
return decorateAndAddToAll(column)
}) })
const decoratedColumns = decorateAndAddToAll(columnsWithExpander) // Build the visible columns, headers and flat column list
const mapVisibleColumns = columns => columns.map(column => { let visibleColumns = decoratedColumns.slice()
let allVisibleColumns = []
visibleColumns = visibleColumns.map(column => {
if (column.columns) { if (column.columns) {
const visibleSubColumns = column.columns.filter( const visibleSubColumns = column.columns.filter(
d => (pivotBy.indexOf(d.id) > -1 ? false : _.getFirstDefined(d.show, true)) d => (pivotBy.indexOf(d.id) > -1 ? false : _.getFirstDefined(d.show, true))
) )
return { return {
...column, ...column,
columns: mapVisibleColumns(visibleSubColumns), columns: visibleSubColumns,
} }
} }
return column return column
}) })
const filterVisibleColumns = columns => columns.filter( visibleColumns = visibleColumns.filter(
column => column =>
column.columns column.columns
? column.columns.length ? column.columns.length
@@ -128,12 +146,8 @@ export default Base =>
: _.getFirstDefined(column.show, true) : _.getFirstDefined(column.show, true)
) )
// Build the full array of visible columns - this is an array that contains all columns that
// are not hidden via pivoting
const allVisibleColumns = filterVisibleColumns(mapVisibleColumns(decoratedColumns.slice()))
// Find any custom pivot location // Find any custom pivot location
const pivotIndex = allVisibleColumns.findIndex(col => col.pivot) const pivotIndex = visibleColumns.findIndex(col => col.pivot)
// Handle Pivot Columns // Handle Pivot Columns
if (pivotBy.length) { if (pivotBy.length) {
@@ -166,66 +180,46 @@ export default Base =>
// Place the pivotColumns back into the visibleColumns // Place the pivotColumns back into the visibleColumns
if (pivotIndex >= 0) { if (pivotIndex >= 0) {
pivotColumnGroup = { pivotColumnGroup = {
...allVisibleColumns[pivotIndex], ...visibleColumns[pivotIndex],
...pivotColumnGroup, ...pivotColumnGroup,
} }
allVisibleColumns.splice(pivotIndex, 1, pivotColumnGroup) visibleColumns.splice(pivotIndex, 1, pivotColumnGroup)
} else { } else {
allVisibleColumns.unshift(pivotColumnGroup) visibleColumns.unshift(pivotColumnGroup)
} }
} }
// Build Visible Columns and Header Groups // Build Header Groups
const allColumnHeaders = [] const headerGroups = []
let currentSpan = []
const addHeader = column => { // A convenience function to add a header and reset the currentSpan
let level = 0 const addHeader = (columns, column) => {
headerGroups.push({
...this.props.column,
...column,
columns,
})
currentSpan = []
}
// If this column has children, push them first and add this column to the next level // Build flat list of allVisibleColumns and HeaderGroups
visibleColumns.forEach(column => {
if (column.columns) { if (column.columns) {
const childLevels = column.columns.map(addHeader) allVisibleColumns = allVisibleColumns.concat(column.columns)
level = Math.max(...childLevels) + 1 if (currentSpan.length > 0) {
} addHeader(currentSpan)
// Add spans above columns without parents (orphans) to fill the space above them
if (allColumnHeaders.length <= level) allColumnHeaders.push([])
if (level > 0) {
// The spans need to contain the shifted headers as children. This finds all of the
// columns in the lower level between the first child of this column and the last child
// of the preceding column (if there is one)
const lowerLevel = allColumnHeaders[level - 1]
const precedingColumn = _.last(allColumnHeaders[level])
const indexOfFirstChildInLowerLevel = lowerLevel.indexOf(column.columns[0])
const indexAfterLastChildInPrecedingColumn = precedingColumn
? lowerLevel.indexOf(_.last(precedingColumn.columns)) + 1
: 0
// If there are ophans, add a span above them
const orphans = lowerLevel.slice(
indexAfterLastChildInPrecedingColumn,
indexOfFirstChildInLowerLevel
)
if (orphans.length) {
allColumnHeaders[level].push({
...this.props.column,
columns: orphans,
})
} }
addHeader(column.columns, column)
return
} }
allVisibleColumns.push(column)
allColumnHeaders[level].push(column) currentSpan.push(column)
})
return level if (hasHeaderGroups && currentSpan.length > 0) {
addHeader(currentSpan)
} }
allVisibleColumns.forEach(addHeader)
// visibleColumns is an array containing column definitions for the bottom row of TH elements
const visibleColumns = allColumnHeaders.shift()
const headerGroups = allColumnHeaders.reverse()
// Access the data // Access the data
const accessRow = (d, i, level = 0) => { const accessRow = (d, i, level = 0) => {
const row = { const row = {
@@ -255,7 +249,7 @@ export default Base =>
resolvedData = resolvedData.map((d, i) => accessRow(d, i)) resolvedData = resolvedData.map((d, i) => accessRow(d, i))
// TODO: Make it possible to fabricate nested rows without pivoting // TODO: Make it possible to fabricate nested rows without pivoting
const aggregatingColumns = visibleColumns.filter(d => !d.expander && d.aggregate) const aggregatingColumns = allVisibleColumns.filter(d => !d.expander && d.aggregate)
// If pivoting, recursively group the data // If pivoting, recursively group the data
const aggregate = rows => { const aggregate = rows => {
@@ -299,7 +293,7 @@ export default Base =>
return { return {
...newState, ...newState,
resolvedData, resolvedData,
visibleColumns, allVisibleColumns,
headerGroups, headerGroups,
allDecoratedColumns, allDecoratedColumns,
hasHeaderGroups, hasHeaderGroups,
@@ -313,6 +307,7 @@ export default Base =>
filtered, filtered,
defaultFilterMethod, defaultFilterMethod,
resolvedData, resolvedData,
allVisibleColumns,
allDecoratedColumns, allDecoratedColumns,
} = resolvedState } = resolvedState
@@ -327,7 +322,7 @@ export default Base =>
sortedData: manual sortedData: manual
? resolvedData ? resolvedData
: this.sortData( : this.sortData(
this.filterData(resolvedData, filtered, defaultFilterMethod, allDecoratedColumns), this.filterData(resolvedData, filtered, defaultFilterMethod, allVisibleColumns),
sorted, sorted,
sortMethodsByColumnID sortMethodsByColumnID
), ),
@@ -354,12 +349,12 @@ export default Base =>
return _.getFirstDefined(this.state[key], this.props[key]) return _.getFirstDefined(this.state[key], this.props[key])
} }
filterData (data, filtered, defaultFilterMethod, visibleColumns) { filterData (data, filtered, defaultFilterMethod, allVisibleColumns) {
let filteredData = data let filteredData = data
if (filtered.length) { if (filtered.length) {
filteredData = filtered.reduce((filteredSoFar, nextFilter) => { filteredData = filtered.reduce((filteredSoFar, nextFilter) => {
const column = visibleColumns.find(x => x.id === nextFilter.id) const column = allVisibleColumns.find(x => x.id === nextFilter.id)
// Don't filter hidden columns or columns that have had their filters disabled // Don't filter hidden columns or columns that have had their filters disabled
if (!column || column.filterable === false) { if (!column || column.filterable === false) {
@@ -388,7 +383,7 @@ export default Base =>
row[this.props.subRowsKey], row[this.props.subRowsKey],
filtered, filtered,
defaultFilterMethod, defaultFilterMethod,
visibleColumns allVisibleColumns
), ),
} }
}) })
-20
View File
@@ -10,8 +10,6 @@ export default {
range, range,
remove, remove,
clone, clone,
leaves,
iterTree,
getFirstDefined, getFirstDefined,
sum, sum,
makeTemplateComponent, makeTemplateComponent,
@@ -110,24 +108,6 @@ function clone (a) {
} }
} }
function leaves (root, childProperty) {
if (Object.prototype.hasOwnProperty.call(root, childProperty)) {
const children = root[childProperty].map(child => leaves(child, childProperty))
return [].concat(...children)
}
return [root]
}
function iterTree (root, childProperty) {
if (Object.prototype.hasOwnProperty.call(root, childProperty)) {
const children = root[childProperty].map(child => leaves(child, childProperty))
return [].concat(root, ...children)
}
return [root]
}
function getFirstDefined (...args) { function getFirstDefined (...args) {
for (let i = 0; i < args.length; i += 1) { for (let i = 0; i < args.length; i += 1) {
if (typeof args[i] !== 'undefined') { if (typeof args[i] !== 'undefined') {