react-table
Version:
Hooks for building lightweight, fast and extendable datagrids for React
219 lines (181 loc) • 5.22 kB
JavaScript
import React from 'react'
import {
actions,
functionalUpdate,
useGetLatest,
makePropGetter,
useMountedLayoutEffect,
} from '../publicUtils'
actions.resetHiddenColumns = 'resetHiddenColumns'
actions.toggleHideColumn = 'toggleHideColumn'
actions.setHiddenColumns = 'setHiddenColumns'
actions.toggleHideAllColumns = 'toggleHideAllColumns'
export const useColumnVisibility = hooks => {
hooks.getToggleHiddenProps = [defaultGetToggleHiddenProps]
hooks.getToggleHideAllColumnsProps = [defaultGetToggleHideAllColumnsProps]
hooks.stateReducers.push(reducer)
hooks.useInstanceBeforeDimensions.push(useInstanceBeforeDimensions)
hooks.headerGroupsDeps.push((deps, { instance }) => [
...deps,
instance.state.hiddenColumns,
])
hooks.useInstance.push(useInstance)
}
useColumnVisibility.pluginName = 'useColumnVisibility'
const defaultGetToggleHiddenProps = (props, { column }) => [
props,
{
onChange: e => {
column.toggleHidden(!e.target.checked)
},
style: {
cursor: 'pointer',
},
checked: column.isVisible,
title: 'Toggle Column Visible',
},
]
const defaultGetToggleHideAllColumnsProps = (props, { instance }) => [
props,
{
onChange: e => {
instance.toggleHideAllColumns(!e.target.checked)
},
style: {
cursor: 'pointer',
},
checked: !instance.allColumnsHidden && !instance.state.hiddenColumns.length,
title: 'Toggle All Columns Hidden',
indeterminate:
!instance.allColumnsHidden && instance.state.hiddenColumns.length,
},
]
function reducer(state, action, previousState, instance) {
if (action.type === actions.init) {
return {
hiddenColumns: [],
...state,
}
}
if (action.type === actions.resetHiddenColumns) {
return {
...state,
hiddenColumns: instance.initialState.hiddenColumns || [],
}
}
if (action.type === actions.toggleHideColumn) {
const should =
typeof action.value !== 'undefined'
? action.value
: !state.hiddenColumns.includes(action.columnId)
const hiddenColumns = should
? [...state.hiddenColumns, action.columnId]
: state.hiddenColumns.filter(d => d !== action.columnId)
return {
...state,
hiddenColumns,
}
}
if (action.type === actions.setHiddenColumns) {
return {
...state,
hiddenColumns: functionalUpdate(action.value, state.hiddenColumns),
}
}
if (action.type === actions.toggleHideAllColumns) {
const shouldAll =
typeof action.value !== 'undefined'
? action.value
: !state.hiddenColumns.length
return {
...state,
hiddenColumns: shouldAll ? instance.allColumns.map(d => d.id) : [],
}
}
}
function useInstanceBeforeDimensions(instance) {
const {
headers,
state: { hiddenColumns },
} = instance
const isMountedRef = React.useRef(false)
if (!isMountedRef.current) {
}
const handleColumn = (column, parentVisible) => {
column.isVisible = parentVisible && !hiddenColumns.includes(column.id)
let totalVisibleHeaderCount = 0
if (column.headers && column.headers.length) {
column.headers.forEach(
subColumn =>
(totalVisibleHeaderCount += handleColumn(subColumn, column.isVisible))
)
} else {
totalVisibleHeaderCount = column.isVisible ? 1 : 0
}
column.totalVisibleHeaderCount = totalVisibleHeaderCount
return totalVisibleHeaderCount
}
let totalVisibleHeaderCount = 0
headers.forEach(
subHeader => (totalVisibleHeaderCount += handleColumn(subHeader, true))
)
}
function useInstance(instance) {
const {
columns,
flatHeaders,
dispatch,
allColumns,
getHooks,
state: { hiddenColumns },
autoResetHiddenColumns = true,
} = instance
const getInstance = useGetLatest(instance)
const allColumnsHidden = allColumns.length === hiddenColumns.length
const toggleHideColumn = React.useCallback(
(columnId, value) =>
dispatch({ type: actions.toggleHideColumn, columnId, value }),
[dispatch]
)
const setHiddenColumns = React.useCallback(
value => dispatch({ type: actions.setHiddenColumns, value }),
[dispatch]
)
const toggleHideAllColumns = React.useCallback(
value => dispatch({ type: actions.toggleHideAllColumns, value }),
[dispatch]
)
const getToggleHideAllColumnsProps = makePropGetter(
getHooks().getToggleHideAllColumnsProps,
{ instance: getInstance() }
)
flatHeaders.forEach(column => {
column.toggleHidden = value => {
dispatch({
type: actions.toggleHideColumn,
columnId: column.id,
value,
})
}
column.getToggleHiddenProps = makePropGetter(
getHooks().getToggleHiddenProps,
{
instance: getInstance(),
column,
}
)
})
const getAutoResetHiddenColumns = useGetLatest(autoResetHiddenColumns)
useMountedLayoutEffect(() => {
if (getAutoResetHiddenColumns()) {
dispatch({ type: actions.resetHiddenColumns })
}
}, [dispatch, columns])
Object.assign(instance, {
allColumnsHidden,
toggleHideColumn,
setHiddenColumns,
toggleHideAllColumns,
getToggleHideAllColumnsProps,
})
}