diff --git a/docs/api.md b/docs/api.md index 890de34..f6aec1c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -940,12 +940,12 @@ function App() { The following options are supported via the main options object passed to `useTable(options)` -- `state[0].expanded: Object<[pathIndex]: Boolean | ExpandedStateObject>` +- `state[0].expanded: Array` - Optional - Must be **memoized** - - An nested object of expanded paths. - - 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. + - An array of expanded path keys. + - If a row's path key (`row.path.join('.')`) is present in this array, that row will have an expanded state. For example, if `['3']` was passed as the `expanded` state, the **4th row in the original data array** would be expanded. + - For nested expansion, you may **join the row path with a `.`** to expand sub rows. For example, if `['3', '3.5']` was passed as the `expanded` state, then the **6th subRow of the 4th row and also 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. - `getSubRows: Function(row, relativeIndex) => Rows[]` - Optional diff --git a/examples/expanding/src/App.js b/examples/expanding/src/App.js index ccd2ebf..e7492c8 100644 --- a/examples/expanding/src/App.js +++ b/examples/expanding/src/App.js @@ -50,9 +50,6 @@ function Table({ columns: userColumns, data }) { return ( <> -
-        {JSON.stringify({ expanded }, null, 2)}
-      
{headerGroups.map(headerGroup => ( @@ -80,6 +77,9 @@ function Table({ columns: userColumns, data }) {

Showing the first 20 results of {rows.length} rows
+
+        {JSON.stringify({ expanded }, null, 2)}
+      
) } diff --git a/src/plugin-hooks/tests/__snapshots__/useExpanded.test.js.snap b/src/plugin-hooks/tests/__snapshots__/useExpanded.test.js.snap index a83e7e2..caffb80 100644 --- a/src/plugin-hooks/tests/__snapshots__/useExpanded.test.js.snap +++ b/src/plugin-hooks/tests/__snapshots__/useExpanded.test.js.snap @@ -10,10 +10,10 @@ Snapshot Diff:
       
         {
--   "expanded": {}
-+   "expanded": {
-+     "0": true
-+   }
+-   "expanded": []
++   "expanded": [
++     "0"
++   ]
   }
       
     
@@ -220,22 +220,21 @@ Snapshot Diff: - First value + Second value -@@ -1,11 +1,13 @@ +@@ -1,11 +1,12 @@
       
         {
-    "expanded": {
--     "0": true
-+     "0": {
-+       "0": true
-+     }
-    }
+    "expanded": [
+-     "0"
++     "0",
++     "0.0"
+    ]
   }
       
     
@@ -281,15 +280,16 @@ Snapshot Diff: + > +
+ > + ++ > 👉 { - "expanded": { - "0": { -- "0": true -+ "0": { -+ "0": true -+ } - } - } + "expanded": [ + "0", +- "0.0" ++ "0.0", ++ "0.0.0" + ] } -@@ -172,10 +174,53 @@ + @@ -497,15 +496,16 @@ Snapshot Diff: + > +
+ > + ++ > 👉 { - "expanded": { - "0": { - "0": { -- "0": true -+ "0": { -+ "0": true -+ } - } - } - } + "expanded": [ + "0", + "0.0", +- "0.0.0" ++ "0.0.0", ++ "0.0.0.0" + ] } -@@ -218,11 +220,11 @@ + + -@@ -250,10 +252,30 @@ +@@ -248,10 +249,30 @@
`; + +exports[`renders an expandable table 5`] = ` +Snapshot Diff: +- First value ++ Second value + +@@ -1,15 +1,10 @@ + +
+      
+        {
+-   "expanded": [
+-     "0",
+-     "0.0",
+-     "0.0.0",
+-     "0.0.0.0"
+-   ]
++   "expanded": []
+  }
+      
+    
+ + +- 👇 +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- + + +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- + + +`; diff --git a/src/plugin-hooks/tests/useExpanded.test.js b/src/plugin-hooks/tests/useExpanded.test.js index 24af0a0..0f0bd8c 100644 --- a/src/plugin-hooks/tests/useExpanded.test.js +++ b/src/plugin-hooks/tests/useExpanded.test.js @@ -178,29 +178,37 @@ test('renders an expandable table', () => { let expandButtons = getAllByText('👉') - const beforeGrouping = asFragment() + const before = asFragment() fireEvent.click(expandButtons[0]) - const afterGrouping1 = asFragment() + const after1 = asFragment() expandButtons = getAllByText('👉') fireEvent.click(expandButtons[0]) - const afterGrouping2 = asFragment() + const after2 = asFragment() expandButtons = getAllByText('👉') fireEvent.click(expandButtons[0]) - const afterGrouping3 = asFragment() + const after3 = asFragment() expandButtons = getAllByText('👉') fireEvent.click(expandButtons[0]) - const afterGrouping4 = asFragment() + const after4 = asFragment() - expect(beforeGrouping).toMatchDiffSnapshot(afterGrouping1) - expect(afterGrouping1).toMatchDiffSnapshot(afterGrouping2) - expect(afterGrouping2).toMatchDiffSnapshot(afterGrouping3) - expect(afterGrouping3).toMatchDiffSnapshot(afterGrouping4) + expandButtons = getAllByText('👇') + expandButtons.reverse().forEach(button => { + fireEvent.click(button) + }) + + const after5 = asFragment() + + expect(before).toMatchDiffSnapshot(after1) + expect(after1).toMatchDiffSnapshot(after2) + expect(after2).toMatchDiffSnapshot(after3) + expect(after3).toMatchDiffSnapshot(after4) + expect(after4).toMatchDiffSnapshot(after5) }) diff --git a/src/plugin-hooks/useExpanded.js b/src/plugin-hooks/useExpanded.js index 0bc2b52..cfec82c 100755 --- a/src/plugin-hooks/useExpanded.js +++ b/src/plugin-hooks/useExpanded.js @@ -1,17 +1,11 @@ import { useMemo } from 'react' import PropTypes from 'prop-types' -import { - getBy, - getFirstDefined, - setBy, - mergeProps, - applyPropHooks, -} from '../utils' +import { mergeProps, applyPropHooks } from '../utils' import { addActions, actions } from '../actions' import { defaultState } from '../hooks/useTableState' -defaultState.expanded = {} +defaultState.expanded = [] addActions('toggleExpanded', 'useExpanded') @@ -40,13 +34,24 @@ function useMain(instance) { } = instance const toggleExpandedByPath = (path, set) => { + const key = path.join('.') + return setState(old => { - const { expanded } = old - const existing = getBy(expanded, path) - set = getFirstDefined(set, existing ? undefined : true) + const exists = old.expanded.includes(key) + const shouldExist = typeof set !== 'undefined' ? set : !exists + let newExpanded = new Set(old.expanded) + + if (!exists && shouldExist) { + newExpanded.add(key) + } else if (exists && !shouldExist) { + newExpanded.delete(key) + } else { + return old + } + return { ...old, - expanded: setBy(expanded, path, set), + expanded: [...newExpanded.values()], } }, actions.toggleExpanded) } @@ -81,9 +86,10 @@ function useMain(instance) { // Here we do some mutation, but it's the last stage in the // immutable process so this is safe const handleRow = row => { + const key = row.path.join('.') row.isExpanded = (row.original && row.original[manualExpandedKey]) || - getBy(expanded, row.path) + expanded.includes(key) expandedRows.push(row) @@ -116,11 +122,13 @@ function useMain(instance) { } } -function findExpandedDepth(obj, depth = 1) { - return Object.values(obj).reduce((prev, curr) => { - if (typeof curr === 'object') { - return Math.max(prev, findExpandedDepth(curr, depth + 1)) - } - return depth - }, 0) +function findExpandedDepth(expanded) { + let maxDepth = 0 + + expanded.forEach(key => { + const path = key.split('.') + maxDepth = Math.max(maxDepth, path.length) + }) + + return maxDepth } diff --git a/src/utils.js b/src/utils.js index ae6c3b3..77ace2a 100755 --- a/src/utils.js +++ b/src/utils.js @@ -232,22 +232,6 @@ 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] - const subValue = - depth === path.length - 1 ? value : recurse(target, depth + 1) - return { - ...obj, - [key]: subValue, - } - } - - return recurse(obj) -} - export function getElementDimensions(element) { const rect = element.getBoundingClientRect() const style = window.getComputedStyle(element)
+- tanner +- +- linsley +- +- 29 +- +- 100 +- +- In Relationship +- +- 50 +-
+- +- 👇 +- +- +- tanner +- +- linsley +- +- 29 +- +- 100 +- +- In Relationship +- +- 50 +-
+- +- 👇 +- +- +- tanner +- +- linsley +- +- 29 +- +- 100 +- +- In Relationship +- +- 50 +-
+- +- 👇 ++ 👉 + + +@@ -249,417 +115,10 @@ + + 50 +-
+-
+-             
+-               {
+-   "values": {
+-     "firstName": "tanner",
+-     "lastName": "linsley",
+-     "age": 29,
+-     "visits": 100,
+-     "status": "In Relationship",
+-     "progress": 50
+-   }
+- }
+-             
+-           
+-
+- +- 👉 +- +- +- derek +- +- perkins +- +- 40 +- +- 40 +- +- Single +- +- 80 +-
+- +- 👉 +- +- +- joe +- +- bergevin +- +- 45 +- +- 20 +- +- Complicated +- +- 10 +-
+- +- 👉 +- +- +- jaylen +- +- linsley +- +- 26 +- +- 99 +- +- In Relationship +- +- 70 +-
+- +- 👉 +- +- +- derek +- +- perkins +- +- 40 +- +- 40 +- +- Single +- +- 80 +-
+- +- 👉 +- +- +- joe +- +- bergevin +- +- 45 +- +- 20 +- +- Complicated +- +- 10 +-
+- +- 👉 +- +- +- jaylen +- +- linsley +- +- 26 +- +- 99 +- +- In Relationship +- +- 70 +-
+- +- 👉 +- +- +- derek +- +- perkins +- +- 40 +- +- 40 +- +- Single +- +- 80 +-
+- +- 👉 +- +- +- joe +- +- bergevin +- +- 45 +- +- 20 +- +- Complicated +- +- 10 +-
+- +- 👉 +- +- +- jaylen +- +- linsley +- +- 26 +- +- 99 +- +- In Relationship +- +- 70 +