import throttle from 'lodash.throttle' import type { GridColumnSort } from '../types' import type { ApiSection } from './types' type SortDirections = 'asc' | 'desc' | 'unset' export type GridColumnApi = { toggleSort: (id: string, replaceSort?: boolean) => void sortColumn: ( id: string, direction: SortDirections, replaceSort?: boolean ) => void resizeColumn: (id: string, value: number) => void reorderColumns: (ids: string[]) => void updateColumnVisibility: (id: string, visible: boolean) => void showMenu: (coordinates: { top: number; left: number }) => void hideMenu: () => void } const MAX_COLUMN_SORT = 9 export const createColumnApi: ApiSection = (store, events) => { const api: GridColumnApi = { toggleSort(columnId, replaceSort = true) { const state = store.getState() const isMultiSorting = store.selectors.selectIsMultiColumnSorting(state) const sort = store.selectors.selectColumnSort(state, columnId) const defaultSort = store.selectors.selectDefaultSort(state) || [] /** * If descending is the default sort direction, we need to toggle and not unset on single sort **/ const shouldProceedToAscending = defaultSort.find( (v) => v.columnId === columnId && v.direction === 'desc' ) && defaultSort.length === 1 && !isMultiSorting let newDirection: SortDirections = sort?.direction === 'asc' ? 'desc' : sort?.direction === 'desc' && !shouldProceedToAscending ? 'unset' : 'asc' if (isMultiSorting && replaceSort) { newDirection = 'asc' } api.sortColumn(columnId, newDirection, replaceSort) }, sortColumn(columnId, direction, replaceSort = true) { const state = store.getState() const defaultSort = store.selectors.selectDefaultSort(state) const isMultiSortEnabled = store.selectors.selectIsMultiColumnSortingEnabled(state) if (replaceSort || !isMultiSortEnabled) { if (direction === 'unset') { events.emit('onSortChange', defaultSort || []) } else { events.emit('onSortChange', [{ columnId, direction }]) } } else { const existingSort = store.selectors.selectSort(state) let newSort: GridColumnSort[] | undefined = undefined if (existingSort.some((es) => es.columnId === columnId)) { newSort = existingSort .map((es) => { if (es.columnId === columnId) { if (direction === 'unset') { return null } return { columnId, direction, } } return es }) .filter(Boolean) as GridColumnSort[] } else if ( existingSort.length < MAX_COLUMN_SORT && direction !== 'unset' ) { newSort = [...existingSort, { columnId, direction }] } if (newSort) { if (newSort.length === 0) { events.emit('onSortChange', defaultSort || []) } else { events.emit('onSortChange', newSort) } } } }, reorderColumns(ids) { store.dispatch({ type: 'reorderColumns', payload: ids, }) }, resizeColumn: throttle((id, width) => { store.dispatch({ type: 'resizeColumn', payload: { id, width: width, }, }) }, 10), updateColumnVisibility(id, visible) { store.dispatch({ type: 'updateColumnVisibility', payload: { id, visible, }, }) }, showMenu(coordinates) { const enabled = store.selectors.selectColumnMenuEnabled( store.getState() ) if (enabled) { store.dispatch({ type: 'showColumnMenu', payload: { coordinates }, }) } }, hideMenu() { store.dispatch({ type: 'hideColumnMenu', payload: undefined, }) }, } return api }