Skip to content

Commit

Permalink
fix: better naming, fix header regen, getSubRows, getRowPathID
Browse files Browse the repository at this point in the history
  • Loading branch information
tannerlinsley committed Aug 26, 2019
1 parent f40b8f5 commit 3b42c72
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 227 deletions.
40 changes: 32 additions & 8 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ The following options are supported via the main options object passed to `useTa
- Defaults to `initialState`
- This key is used to look for the initial state of a row when initializing the `rowState` for a`data` array.
- If the value located at `row[initialRowStateKey]` is falsey, `{}` will be used instead.
- `getSubRows: Function(row, relativeIndex) => Rows[]`
- Optional
- Must be **memoized**
- Defaults to `(row) => row.subRows || []`
- Use this function to change how React Table detects subrows. You could even use this function to generate sub rows if you want.
- By default, it will attempt to return the `subRows` property on the row, or an empty array if that is not found.
- `getRowPathID: Function(row, relativeIndex) => string`
- Optional
- Must be **memoized**
- Defaults to `(row, relativeIndex) => relativeIndex`
- Use this function to change how React Table constructs each row's underlying `path` property.
- You may want to change this function if
- By default, it will attempt to return the `subRows` property on the row, or an empty array if that is not found.
- `debug: Bool`
- Optional
- A flag to turn on debug mode.
Expand Down Expand Up @@ -143,17 +156,24 @@ The following options are supported on any column object you can pass to `column

The following properties are available on the table instance returned from `useTable`

- `headers[] Array<Column>`
- A **nested** array of final column objects, similar in structure to the original columns configuration option.
- See [Column Properties](#column-properties) for more information
- `columns: Array<Column>`
- A **flat** array of all final column objects computed from the original columns configuration option.
- A **nested** array of final column objects, **similar in structure to the original columns configuration option**.
- See [Column Properties](#column-properties) for more information
- `flatColumns: Array<Column>`
- A **flat** array of all final column objects.
- See [Column Properties](#column-properties) for more information
- `headerGroups: Array<HeaderGroup>`
- An array of normalized header groups, each containing a flattened array of final column objects for that row.
- **Some of these headers may be materialized as placeholders**
- See [Header Group Properties](#headergroup-properties) for more information
- `headers: Array<Column>`
- An **nested** array of final header objects, **similar in structure to the original columns configuration option, but rebuilt for ordering**
- Each contains the headers that are displayed underneath it.
- **Some of these headers may be materialized as placeholders**
- See [Column Properties](#column-properties) for more information
- `flatHeaders[] Array<Column>`
- A **flat** array of final header objects found in each header group. Columns may be duplicated (if columns are not adjacent)
- A **flat** array of final header objects found in each header group.
- **Some of these headers may be materialized as placeholders**
- See [Column Properties](#column-properties) for more information
- `rows: Array<Row>`
- An array of **materialized row objects** from the original `data` array and `columns` passed into the table options
Expand Down Expand Up @@ -182,7 +202,7 @@ The following properties are available on the table instance returned from `useT
- Pass it a valid `rowPath` array, `columnID` and `updater`. The `updater` may be a value or function, similar to `React.useState`'s usage.
- If `updater` is a function, it will be passed the previous value

### `HeaderGroup` Properties
### HeaderGroup Properties

The following additional properties are available on every `headerGroup` object returned by the table instance.

Expand Down Expand Up @@ -477,7 +497,11 @@ function Table({ columns, data }) {
<span>
{/* Add a sort direction indicator */}
<span>
{column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : ''}
{column.isSorted
? column.isSortedDesc
? ' 🔽'
: ' 🔼'
: ''}
</span>
{/* Add a sort index indicator */}
<span>({column.isSorted ? column.sortedIndex + 1 : ''})</span>
Expand Down Expand Up @@ -921,7 +945,7 @@ The following options are supported via the main options object passed to `useTa
- A `pathIndex` can be set as the key and its value set to `true` to expand that row's subRows into view. For example, if `{ '3': true }` was passed as the `expanded` state, the **4th row in the original data array** would be expanded.
- For nested expansion, you may **use another object** instead of a Boolean to expand sub rows. For example, if `{ '3': { '5' : true }}` was passed as the `expanded` state, then the **6th subRow of the 4th row and the 4th row of the original data array** would be expanded.
- This information is stored in state since the table is allowed to manipulate the filter through user interaction.
- `subRowsKey: String`
- `getSubRows: Function(row, relativeIndex) => Rows[]`
- Optional
- See the [useTable hook](#table-options) for more details
- `manualExpandedKey: String`
Expand Down
4 changes: 2 additions & 2 deletions examples/sub-components/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function Table({ columns: userColumns, data, renderRowSubComponent }) {
headerGroups,
rows,
prepareRow,
columns,
flatColumns,
state: [{ expanded }],
} = useTable(
{
Expand Down Expand Up @@ -87,7 +87,7 @@ function Table({ columns: userColumns, data, renderRowSubComponent }) {
*/}
{row.isExpanded ? (
<tr>
<td colSpan={columns.length}>
<td colSpan={flatColumns.length}>
{/*
Inside it, call our renderRowSubComponent function. In reality,
you coul pass whatever you want as props to
Expand Down
Binary file modified media/src/logo.sketch
Binary file not shown.
152 changes: 76 additions & 76 deletions src/hooks/useTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,19 @@ import {
flexRender,
decorateColumnTree,
makeHeaderGroups,
findMaxDepth,
flattenBy,
determineColumnVisibility,
determineHeaderVisibility,
} from '../utils'

import { useTableState } from './useTableState'

const propTypes = {
// General
data: PropTypes.array.isRequired,
columns: PropTypes.arrayOf(
PropTypes.shape({
Cell: PropTypes.any,
Header: PropTypes.any,
})
).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
defaultColumn: PropTypes.object,
subRowsKey: PropTypes.string,
getSubRows: PropTypes.func,
getRowPathID: PropTypes.func,
debug: PropTypes.bool,
}

Expand All @@ -34,6 +29,9 @@ const renderErr =

const defaultColumnInstance = {}

const defaultGetSubRows = (row, index) => row.subRows || []
const defaultGetRowPathID = (row, index) => index

export const useTable = (props, ...plugins) => {
// Validate props
PropTypes.checkPropTypes(propTypes, props, 'property', 'useTable')
Expand All @@ -44,7 +42,8 @@ export const useTable = (props, ...plugins) => {
state: userState,
columns: userColumns,
defaultColumn = defaultColumnInstance,
subRowsKey = 'subRows',
getSubRows = defaultGetSubRows,
getRowPathID = defaultGetRowPathID,
debug,
} = props

Expand Down Expand Up @@ -89,22 +88,20 @@ export const useTable = (props, ...plugins) => {
console.timeEnd('plugins')

// Decorate All the columns
let headers = React.useMemo(
let columns = React.useMemo(
() => decorateColumnTree(userColumns, defaultColumn),
[defaultColumn, userColumns]
)

// Get the flat list of all columns
let columns = React.useMemo(() => flattenBy(headers, 'columns'), [headers])

// Allow hooks to decorate columns (and trigger this memoization via deps)
columns = React.useMemo(() => {
// Get the flat list of all columns andllow hooks to decorate
// those columns (and trigger this memoization via deps)
let flatColumns = React.useMemo(() => {
if (process.env.NODE_ENV === 'development' && debug)
console.time('hooks.columnsBeforeHeaderGroups')

let newColumns = applyHooks(
instanceRef.current.hooks.columnsBeforeHeaderGroups,
columns,
flattenBy(columns, 'columns'),
instanceRef.current
)

Expand All @@ -124,12 +121,15 @@ export const useTable = (props, ...plugins) => {

// Make the headerGroups
const headerGroups = React.useMemo(
() => makeHeaderGroups(columns, findMaxDepth(headers), defaultColumn),
[columns, defaultColumn, headers]
() => makeHeaderGroups(flatColumns, columns, defaultColumn),
[columns, defaultColumn, flatColumns]
)

const headers = React.useMemo(() => headerGroups[0].headers, [headerGroups])

Object.assign(instanceRef.current, {
columns,
flatColumns,
headerGroups,
headers,
})
Expand All @@ -147,18 +147,20 @@ export const useTable = (props, ...plugins) => {
// Keep the original reference around
const original = originalRow

const rowID = getRowPathID(originalRow, i)

// Make the new path for the row
const path = [...parentPath, i]
const path = [...parentPath, rowID]

flatRows++
rowPaths.push(path.join('.'))

// Process any subRows
const subRows = originalRow[subRowsKey]
? originalRow[subRowsKey].map((d, i) =>
accessRow(d, i, depth + 1, path)
)
: []
let subRows = getSubRows(originalRow, i)

if (subRows) {
subRows = subRows.map((d, i) => accessRow(d, i, depth + 1, path))
}

const row = {
original,
Expand All @@ -183,7 +185,7 @@ export const useTable = (props, ...plugins) => {

// Create the cells and values
row.values = {}
columns.forEach(column => {
flatColumns.forEach(column => {
row.values[column.id] = column.accessor
? column.accessor(originalRow, i, { subRows, depth, data })
: undefined
Expand All @@ -197,14 +199,14 @@ export const useTable = (props, ...plugins) => {
if (process.env.NODE_ENV === 'development' && debug)
console.timeEnd('getAccessedRows')
return [accessedData, rowPaths, flatRows]
}, [debug, data, columns, subRowsKey])
}, [debug, data, getRowPathID, getSubRows, flatColumns])

instanceRef.current.rows = rows
instanceRef.current.rowPaths = rowPaths
instanceRef.current.flatRows = flatRows

// Determine column visibility
determineColumnVisibility(instanceRef.current)
determineHeaderVisibility(instanceRef.current)

// Provide a flat header list for utilities
instanceRef.current.flatHeaders = headerGroups.reduce(
Expand Down Expand Up @@ -258,15 +260,15 @@ export const useTable = (props, ...plugins) => {
instanceRef.current.headerGroups.forEach((headerGroup, i) => {
// Filter out any headers and headerGroups that don't have visible columns
headerGroup.headers = headerGroup.headers.filter(header => {
const recurse = columns =>
columns.filter(column => {
if (column.columns) {
return recurse(column.columns)
const recurse = headers =>
headers.filter(header => {
if (header.headers) {
return recurse(header.headers)
}
return column.isVisible
return header.isVisible
}).length
if (header.columns) {
return recurse(header.columns)
if (header.headers) {
return recurse(header.headers)
}
return header.isVisible
})
Expand Down Expand Up @@ -316,53 +318,51 @@ export const useTable = (props, ...plugins) => {
props
)

const visibleColumns = instanceRef.current.columns.filter(
column => column.isVisible
)
// Build the visible cells for each row
row.cells = instanceRef.current.flatColumns
.filter(d => d.isVisible)
.map(column => {
const cell = {
column,
row,
value: row.values[column.id],
}

// Build the cells for each row
row.cells = visibleColumns.map(column => {
const cell = {
column,
row,
value: row.values[column.id],
}
// Give each cell a getCellProps base
cell.getCellProps = props => {
const columnPathStr = [...row.path, column.id].join('_')
return mergeProps(
{
key: ['cell', columnPathStr].join('_'),
},
applyPropHooks(
instanceRef.current.hooks.getCellProps,
cell,
instanceRef.current
),
props
)
}

// Give each cell a getCellProps base
cell.getCellProps = props => {
const columnPathStr = [...row.path, column.id].join('_')
return mergeProps(
{
key: ['cell', columnPathStr].join('_'),
},
applyPropHooks(
instanceRef.current.hooks.getCellProps,
cell,
instanceRef.current
),
props
)
}
// 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 = (type, userProps = {}) => {
const Comp = typeof type === 'string' ? column[type] : type
if (typeof Comp === 'undefined') {
throw new Error(renderErr)
}

if (typeof Comp === 'undefined') {
throw new Error(renderErr)
return flexRender(Comp, {
...instanceRef.current,
column,
row,
cell,
...userProps,
})
}

return flexRender(Comp, {
...instanceRef.current,
column,
row,
cell,
...userProps,
})
}

return cell
})
return cell
})

// need to apply any row specific hooks (useExpanded requires this)
applyHooks(instanceRef.current.hooks.prepareRow, row, instanceRef.current)
Expand Down
Loading

0 comments on commit 3b42c72

Please sign in to comment.