import { createSelector } from 'reselect' import type { GridRowId } from '../../types' import type { GridState } from '../reducer' import type { StoreSimpleSelectors } from '../selectors' import type { SelectColumnSpanByRowId, SelectRowIds } from './row' import { BORDERS } from '../../constants' import type { GridRangeIds } from '../../utils/range' import { getIdsFromRange } from '../../utils/range' const emptyRowIds = new Set() const emptyColumnIds = new Set() export const emptyIds: GridRangeIds = { rowIds: emptyRowIds, columnIds: emptyColumnIds, firstRowId: null, firstColumnId: null, lastRowId: null, lastColumnId: null, } export default function generateSelectors( selectors: Pick< StoreSimpleSelectors, | 'selectRangeSelection' | 'selectRangeSelectionPreview' | 'selectColumnIdsWithHidden' | 'selectHiddenIds' >, selectRowIds: SelectRowIds, selectColumnSpanByRowId: SelectColumnSpanByRowId ) { const selectColumnIds = createSelector( [selectors.selectColumnIdsWithHidden, selectors.selectHiddenIds], (ids, hiddenIds) => ids.filter((id) => !hiddenIds.includes(id)) ) const selectRangeSelectionDetails = createSelector( [ selectors.selectRangeSelection, selectors.selectRangeSelectionPreview, selectRowIds, selectColumnIds, ], (rangeSelection, rangeSelectionPreview, flatIds, columnIds) => { const range = rangeSelectionPreview ?? rangeSelection if (!range) { return emptyIds } return getIdsFromRange(range, flatIds, columnIds) } ) const selectRangeIds = createSelector( [selectRangeSelectionDetails], ({ rowIds, columnIds }) => ({ rowIds: Array.from(rowIds), columnIds: Array.from(columnIds), }) ) const selectIsInRangeSelection = ( state: GridState, columnId: string, rowId: GridRowId ) => { const { rowIds, columnIds } = selectRangeSelectionDetails(state) return rowIds.has(rowId) && columnIds.has(columnId) } const selectCellRangeBorders = ( state: GridState, columnId: string, rowId: GridRowId ) => { const { firstColumnId, lastRowId, firstRowId, lastColumnId, rowIds, columnIds, } = selectRangeSelectionDetails(state) if (!rowIds.has(rowId) || !columnIds.has(columnId)) { return 0 } const colSpans = selectColumnSpanByRowId(state, rowId) const positionedIds = colSpans ? ([...colSpans.values()].find((c) => c.positionColumnIds?.includes(columnId) )?.positionColumnIds ?? [columnId]) : [columnId] const leftBorder = positionedIds.at(0) === firstColumnId const rightBorder = positionedIds.at(-1) === lastColumnId const topBorder = rowId === firstRowId const bottomBorder = rowId === lastRowId if (firstColumnId === lastColumnId && firstRowId === lastRowId) { return 0 } let borders = 0 if (leftBorder) { borders |= BORDERS.LEFT } if (rightBorder) { borders |= BORDERS.RIGHT } if (topBorder) { borders |= BORDERS.TOP } if (bottomBorder) { borders |= BORDERS.BOTTOM } return borders } return { selectIsInRangeSelection, selectCellRangeBorders, selectRangeIds, } } export type SelectIsInRangeSelection = ReturnType< typeof generateSelectors >['selectIsInRangeSelection'] export type SelectCellRangeBorders = ReturnType< typeof generateSelectors >['selectCellRangeBorders'] export type SelectRangeIds = ReturnType< typeof generateSelectors >['selectRangeIds']