diff --git a/docs/api.md b/docs/api.md index e1e12da..6e9ff38 100644 --- a/docs/api.md +++ b/docs/api.md @@ -688,7 +688,7 @@ The following properties are available on every `Column` object returned by the - `canGroupBy: Boolean` - If `true`, this column is able to be grouped. - This is resolved from the column having a valid accessor / data model, and not being manually disabled via other `useGroupBy` related options -- `grouped: Boolean` +- `isGrouped: Boolean` - If `true`, this column is currently being grouped - `groupedIndex: Int` - If this column is currently being grouped, this integer is the index of this column's ID in the table state's `groupBy` array. @@ -719,17 +719,19 @@ The following properties are available on every `Row` object returned by the tab - `path: Array` - Similar to normal `Row` objects, materialized grouping rows also have a path array. The keys inside it though are not integers like nested normal rows though. Since they are not rows that can be traced back to an original data row, they are given a unique path based on their `groupByVal` - If a row is a grouping row, it will have a path like `['Single']` or `['Complicated', 'Anderson']`, where `Single`, `Complicated`, and `Anderson` would all be derived from their row's `groupByVal`. +- `isAggregated: Bool` + - Will be `true` if the row is an aggregated row ### Cell Properties The following additional properties are available on every `Cell` object returned in an array of `cells` on every row object. -- `grouped: Bool` +- `isGrouped: Bool` - If `true`, this cell is a grouped cell, meaning it contains a grouping value and should usually display and expander. -- `repeatedValue: Bool` +- `isRepeatedValue: Bool` - If `true`, this cell is a repeated value cell, meaning it contains a value that is already being displayed elsewhere (usually by a parent row's cell). - Most of the time, this cell is not required to be displayed and can safely be hidden during rendering -- `aggregated: Bool` +- `isAggregated: Bool` - If `true`, this cell's value has been aggregated and should probably be rendered with the `Aggregated` cell renderer. ### Example @@ -918,10 +920,6 @@ The following options are supported via the main options object passed to `useTa - `subRowsKey: String` - Optional - See the [useTable hook](#table-options) for more details -- `nestExpandedRows: Bool` - - Optional - - Defaults to `false` - - If set to `false`, expanded rows will not be paginated. Thus, any expanded subrows would potentially increase the size of any given page by the amount of total expanded subrows on the page. - `manualExpandedKey: String` - Optional - Defaults to `expanded` @@ -1098,13 +1096,17 @@ The following options are supported via the main options object passed to `useTa - Defaults to `false` - Normally, any changes detected to `rows`, `state.filters`, `state.groupBy`, or `state.sortBy` will trigger the `pageIndex` to be reset to `0` - If set to `true`, the `pageIndex` will not be automatically set to `0` when these dependencies change. +- `paginateExpandedRows: Bool` + - Optional + - Only applies when using the `useExpanded` plugin hook simultaneously + - Defaults to `true` + - If set to `true`, expanded rows are paginated along with normal rows. This results in stable page sizes across every page. + - If set to `false`, expanded rows will be spliced in after pagination. This means that the total number of rows in a page can potentially be larger than the page size, depending on how many subrows are expanded. ### Instance Properties The following values are provided to the table `instance`: -- `pages: Array` - - An array of every generated `page`, each containing its respective rows. - `page: Array` - An array of rows for the **current** page, determined by the current `pageIndex` value. - `pageCount: Int` @@ -1119,7 +1121,7 @@ The following values are provided to the table `instance`: - If there are pages and the current `pageIndex` is less than `pageCount`, this will be `true` - `gotoPage: Function(pageIndex)` - This function, when called with a valid `pageIndex`, will set `pageIndex` to that value. - - If the passed index is outside of the valid `pageIndex` range, then this function will do nothing. + - If the aginateassed index is outside of the valid `pageIndex` range, then this function will do nothing. - `previousPage: Function` - This function decreases `state.pageIndex` by one. - If there are no pages or `canPreviousPage` is false, this function will do nothing. @@ -1335,7 +1337,7 @@ The following options are supported via the main options object passed to `useTa - If a row's path key (eg. a row path of `[1, 3, 2]` would have a path key of `1.3.2`) is found in this array, it will have a selected state. - `manualRowSelectedKey: String` - Optional - - Defaults to `selected` + - Defaults to `isSelected` - If this key is found on the **original** data row, and it is true, this row will be manually selected ### Instance Properties @@ -1359,6 +1361,16 @@ The following values are provided to the table `instance`: - Will be `true` if all rows are selected. - If at least one row is not selected, will be `false` +### Row Properties + +The following additional properties are available on every **prepared** `row` object returned by the table instance. + +- `isSelected: Bool` + - Will be `true` if the row is currently selected +- `toggleRowSelected: Function(?set)` + - Use this function to toggle this row's selected state. + - Optionally pass `true` or `false` to set it to that state + ### Example ```js @@ -1609,12 +1621,9 @@ export default function MyTable({ manualPageIndex }) { const state = useTableState(initialState, overrides) // You can use effects to observe changes to the state - React.useEffect( - () => { - console.log('Page Size Changed!', initialState.pageSize) - }, - [initialState.pageSize] - ) + React.useEffect(() => { + console.log('Page Size Changed!', initialState.pageSize) + }, [initialState.pageSize]) const { rows } = useTable({ state, diff --git a/examples/editable-data/src/App.js b/examples/editable-data/src/App.js index 2083dd4..805c577 100644 --- a/examples/editable-data/src/App.js +++ b/examples/editable-data/src/App.js @@ -46,20 +46,28 @@ const Styles = styled.div` // Create an editable cell renderer const EditableCell = ({ - value: initialValue, + cell: { value: initialValue }, row: { index }, column: { id }, updateMyData, // This is a custom function that we supplied to our table instance }) => { // We need to keep and update the state of the cell normally const [value, setValue] = React.useState(initialValue) + const onChange = e => { setValue(e.target.value) } + // We'll only update the external data when the input is blurred const onBlur = () => { updateMyData(index, id, value) } + + // If the initialValue is changed externall, sync it up with our state + React.useEffect(() => { + setValue(initialValue) + }, [initialValue]) + return } @@ -221,6 +229,7 @@ function App() { ) const [data, setData] = React.useState(() => makeData(20)) + const [originalData] = React.useState(data) // We need to keep the table from resetting the pageIndex when we // Update data. So we can keep track of that flag with a ref. @@ -232,8 +241,8 @@ function App() { const updateMyData = (rowIndex, columnID, value) => { // We also turn on the flag to not reset the page skipPageResetRef.current = true - setData(old => { - return old.filter((row, index) => { + setData(old => + old.map((row, index) => { if (index === rowIndex) { return { ...old[rowIndex], @@ -242,22 +251,19 @@ function App() { } return row }) - }) + ) } // After data chagnes, we turn the flag back off // so that if data actually changes when we're not // editing it, the page is reset - React.useEffect( - () => { - skipPageResetRef.current = false - }, - [data] - ) + React.useEffect(() => { + skipPageResetRef.current = false + }, [data]) // Let's add a data resetter/randomizer to help // illustrate that flow... - const resetData = () => setData(makeData(20)) + const resetData = () => setData(originalData) return ( diff --git a/examples/grouping/src/App.js b/examples/grouping/src/App.js index 6693f30..3fcca6e 100644 --- a/examples/grouping/src/App.js +++ b/examples/grouping/src/App.js @@ -68,7 +68,7 @@ function Table({ columns, data }) { {column.canGroupBy ? ( // If the column can be grouped, let's add a toggle - {column.grouped ? '🛑 ' : '👊 '} + {column.isGrouped ? '🛑 ' : '👊 '} ) : null} {column.render('Header')} @@ -90,16 +90,16 @@ function Table({ columns, data }) { // from the useGroupBy hook {...cell.getCellProps()} style={{ - background: cell.grouped + background: cell.isGrouped ? '#0aff0082' - : cell.aggregated + : cell.isAggregated ? '#ffa50078' - : cell.repeatedValue + : cell.isRepeatedValue ? '#ff000042' : 'white', }} > - {cell.grouped ? ( + {cell.isGrouped ? ( // If it's a grouped cell, add an expander and row count <> @@ -107,11 +107,11 @@ function Table({ columns, data }) { {' '} {cell.render('Cell')} ({row.subRows.length}) - ) : cell.aggregated ? ( + ) : cell.isAggregated ? ( // If the cell is aggregated, use the Aggregated // renderer for cell cell.render('Aggregated') - ) : cell.repeatedValue ? null : ( // For cells with repeated values, render null + ) : cell.isRepeatedValue ? null : ( // For cells with repeated values, render null // Otherwise, just render the regular cell cell.render('Cell') )} @@ -196,7 +196,7 @@ function App() { // then sum any of those counts if they are // aggregated further aggregate: ['sum', 'count'], - Aggregated: ({ value }) => `${value} Names`, + Aggregated: ({ cell: { value } }) => `${value} Names`, }, { Header: 'Last Name', @@ -206,7 +206,7 @@ function App() { // being aggregated, then sum those counts if // they are aggregated further aggregate: ['sum', 'uniqueCount'], - Aggregated: ({ value }) => `${value} Unique Names`, + Aggregated: ({ cell: { value } }) => `${value} Unique Names`, }, ], }, @@ -218,14 +218,14 @@ function App() { accessor: 'age', // Aggregate the average age of visitors aggregate: 'average', - Aggregated: ({ value }) => `${value} (avg)`, + Aggregated: ({ cell: { value } }) => `${value} (avg)`, }, { Header: 'Visits', accessor: 'visits', // Aggregate the sum of all visits aggregate: 'sum', - Aggregated: ({ value }) => `${value} (total)`, + Aggregated: ({ cell: { value } }) => `${value} (total)`, }, { Header: 'Status', @@ -236,7 +236,7 @@ function App() { accessor: 'progress', // Use our custom roundedMedian aggregator aggregate: roundedMedian, - Aggregated: ({ value }) => `${value} (med)`, + Aggregated: ({ cell: { value } }) => `${value} (med)`, }, ], }, diff --git a/examples/kitchen-sink/src/makeData.js b/examples/kitchen-sink/src/makeData.js index fab0b34..142557e 100644 --- a/examples/kitchen-sink/src/makeData.js +++ b/examples/kitchen-sink/src/makeData.js @@ -10,12 +10,8 @@ const range = len => { const newPerson = () => { const statusChance = Math.random() - - let firstName = namor.generate({ words: 1, numbers: 0 }) - firstName = firstName.slice(0, 1) + '.' + firstName.slice(1, firstName.length) - return { - firstName, + firstName: namor.generate({ words: 1, numbers: 0 }), lastName: namor.generate({ words: 1, numbers: 0 }), age: Math.floor(Math.random() * 30), visits: Math.floor(Math.random() * 100), diff --git a/examples/sorting/README.md b/examples/sorting/README.md index 4c66366..748287f 100644 --- a/examples/sorting/README.md +++ b/examples/sorting/README.md @@ -37,7 +37,7 @@ function MyTable() { + {column.render('Header')} + -+ {column.sorted ? (column.sortedDesc ? ' 🔽' : ' 🔼') : ''} ++ {column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : ''} + ))} diff --git a/examples/sorting/src/App.js b/examples/sorting/src/App.js index 13ec4bd..0419154 100644 --- a/examples/sorting/src/App.js +++ b/examples/sorting/src/App.js @@ -65,7 +65,11 @@ function Table({ columns, data }) { {column.render('Header')} {/* Add a sort direction indicator */} - {column.sorted ? (column.sortedDesc ? ' 🔽' : ' 🔼') : ''} + {column.isSorted + ? column.isSortedDesc + ? ' 🔽' + : ' 🔼' + : ''} ))} diff --git a/src/plugin-hooks/tests/useGroupBy.test.js b/src/plugin-hooks/tests/useGroupBy.test.js index 1043b1e..a4aee74 100644 --- a/src/plugin-hooks/tests/useGroupBy.test.js +++ b/src/plugin-hooks/tests/useGroupBy.test.js @@ -73,7 +73,7 @@ function Table({ columns, data }) { {column.canGroupBy ? ( // If the column can be grouped, let's add a toggle - {column.grouped ? '🛑' : '👊'} + {column.isGrouped ? '🛑' : '👊'} ) : null} {column.render('Header')} @@ -90,7 +90,7 @@ function Table({ columns, data }) { {row.cells.map(cell => { return ( - {cell.grouped ? ( + {cell.isGrouped ? ( <> {cell.render('Cell')} ({row.subRows.length}) - ) : cell.aggregated ? ( + ) : cell.isAggregated ? ( cell.render('Aggregated') - ) : cell.repeatedValue ? null : ( + ) : cell.isRepeatedValue ? null : ( cell.render('Cell') )} diff --git a/src/plugin-hooks/tests/useRowSelect.test.js b/src/plugin-hooks/tests/useRowSelect.test.js index 4e8ce39..376a41e 100644 --- a/src/plugin-hooks/tests/useRowSelect.test.js +++ b/src/plugin-hooks/tests/useRowSelect.test.js @@ -120,7 +120,7 @@ function App() { { id: 'selectedStatus', Cell: ({ row }) => ( -
{row.selected ? 'Selected' : 'Not Selected'}
+
{row.isSelected ? 'Selected' : 'Not Selected'}
), }, { diff --git a/src/plugin-hooks/tests/useSortBy.test.js b/src/plugin-hooks/tests/useSortBy.test.js index 2e4cc2d..75e0c92 100644 --- a/src/plugin-hooks/tests/useSortBy.test.js +++ b/src/plugin-hooks/tests/useSortBy.test.js @@ -56,7 +56,7 @@ function Table({ columns, data }) { {column.render('Header')} {/* Add a sort direction indicator */} - {column.sorted ? (column.sortedDesc ? ' 🔽' : ' 🔼') : ''} + {column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : ''} ))} diff --git a/src/plugin-hooks/useExpanded.js b/src/plugin-hooks/useExpanded.js index b71a5ce..0bc2b52 100755 --- a/src/plugin-hooks/useExpanded.js +++ b/src/plugin-hooks/useExpanded.js @@ -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) diff --git a/src/plugin-hooks/useGroupBy.js b/src/plugin-hooks/useGroupBy.js index cbfd2f2..3e0d374 100755 --- a/src/plugin-hooks/useGroupBy.js +++ b/src/plugin-hooks/useGroupBy.js @@ -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, diff --git a/src/plugin-hooks/usePagination.js b/src/plugin-hooks/usePagination.js index b3810ca..73676b5 100755 --- a/src/plugin-hooks/usePagination.js +++ b/src/plugin-hooks/usePagination.js @@ -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, diff --git a/src/plugin-hooks/useRowSelect.js b/src/plugin-hooks/useRowSelect.js index 5b6cf8e..f594f97 100644 --- a/src/plugin-hooks/useRowSelect.js +++ b/src/plugin-hooks/useRowSelect.js @@ -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( diff --git a/src/plugin-hooks/useSortBy.js b/src/plugin-hooks/useSortBy.js index e602a80..ae0dcb9 100755 --- a/src/plugin-hooks/useSortBy.js +++ b/src/plugin-hooks/useSortBy.js @@ -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(() => { diff --git a/src/utils.js b/src/utils.js index cb61c3d..0870e6e 100755 --- a/src/utils.js +++ b/src/utils.js @@ -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 = []) {