|
1 | | -import type { ComponentProps, KeyboardEvent, MouseEvent } from 'react' |
| 1 | +import type { ComponentProps } from 'react' |
2 | 2 | import type { TableCellProps, TableHeaderCellProps } from '~/components/table' |
3 | 3 | import { cn } from '@conar/ui/lib/utils' |
4 | 4 | import { RiCheckLine, RiSubtractLine } from '@remixicon/react' |
5 | 5 | import { useStore } from '@tanstack/react-store' |
6 | | -import { useRef } from 'react' |
7 | | -import { useTableContext } from '~/components/table' |
| 6 | +import { useShiftSelectionClick, useTableContext } from '~/components/table' |
8 | 7 | import { usePageStoreContext } from '../../-store' |
9 | 8 |
|
10 | 9 | function IndeterminateCheckbox({ |
@@ -97,65 +96,40 @@ export function SelectionCell({ rowIndex, columnIndex, className, style, keys }: |
97 | 96 | }) { |
98 | 97 | const store = usePageStoreContext() |
99 | 98 | const rows = useTableContext(state => state.rows) |
100 | | - const shiftKeyRef = useRef(false) |
101 | 99 | const isSelected = useStore(store, state => state.selected.some(row => keys.every(key => row[key] === rows[rowIndex]![key]))) |
| 100 | + const [currentSelected, lastClickedIndex] = useStore(store, state => [ |
| 101 | + state.selected, |
| 102 | + state.lastClickedIndex, |
| 103 | + ]) |
102 | 104 |
|
103 | | - const handleMouseDown = (event: MouseEvent<HTMLInputElement>) => { |
104 | | - shiftKeyRef.current = event.shiftKey |
105 | | - } |
106 | | - |
107 | | - const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => { |
108 | | - if (event.key === ' ' || event.key === 'Enter') { |
109 | | - shiftKeyRef.current = event.shiftKey |
110 | | - } |
111 | | - } |
112 | | - |
113 | | - const handleChange = () => { |
114 | | - const lastIndex = store.state.lastClickedIndex |
115 | | - const isShiftHeld = shiftKeyRef.current |
116 | | - |
117 | | - if (isShiftHeld && lastIndex !== null && lastIndex !== rowIndex) { |
118 | | - const start = Math.min(lastIndex, rowIndex) |
119 | | - const end = Math.max(lastIndex, rowIndex) |
| 105 | + const rowKey = keys.reduce<Record<string, string>>( |
| 106 | + (acc, key) => ({ ...acc, [key]: rows[rowIndex]![key] as string }), |
| 107 | + {}, |
| 108 | + ) |
120 | 109 |
|
| 110 | + const { handleMouseDown, handleKeyDown, handleChange } = useShiftSelectionClick({ |
| 111 | + rowKey, |
| 112 | + rowIndex, |
| 113 | + currentSelected, |
| 114 | + lastClickedIndex, |
| 115 | + getRangeKeys: (start, end) => { |
121 | 116 | const rangeRows = rows.slice(start, end + 1) |
122 | | - const rangeKeys = rangeRows.map(row => |
123 | | - keys.reduce<Record<string, string>>((acc, key) => ({ ...acc, [key]: row[key] as string }), {}), |
| 117 | + return rangeRows.map(row => |
| 118 | + keys.reduce<Record<string, string>>( |
| 119 | + (acc, key) => ({ ...acc, [key]: row[key] as string }), |
| 120 | + {}, |
| 121 | + ), |
124 | 122 | ) |
125 | | - |
| 123 | + }, |
| 124 | + onSelectionChange: (selected, selectionState, newLastClickedIndex) => { |
126 | 125 | store.setState(state => ({ |
127 | 126 | ...state, |
128 | | - selected: rangeKeys, |
129 | | - selectionState: { |
130 | | - anchorIndex: lastIndex, |
131 | | - focusIndex: rowIndex, |
132 | | - lastExpandDirection: rowIndex > lastIndex ? 'down' : 'up', |
133 | | - }, |
| 127 | + selected, |
| 128 | + selectionState, |
| 129 | + lastClickedIndex: newLastClickedIndex, |
134 | 130 | } satisfies typeof state)) |
135 | | - } |
136 | | - else { |
137 | | - if (isSelected) { |
138 | | - store.setState(state => ({ |
139 | | - ...state, |
140 | | - selected: store.state.selected.filter(row => !keys.every(key => row[key] === rows[rowIndex]![key])), |
141 | | - selectionState: { anchorIndex: null, focusIndex: null, lastExpandDirection: null }, |
142 | | - } satisfies typeof state)) |
143 | | - } |
144 | | - else { |
145 | | - store.setState(state => ({ |
146 | | - ...state, |
147 | | - selected: [...state.selected, keys.reduce((acc, key) => ({ ...acc, [key]: rows[rowIndex]![key] }), {})], |
148 | | - selectionState: { anchorIndex: rowIndex, focusIndex: rowIndex, lastExpandDirection: null }, |
149 | | - } satisfies typeof state)) |
150 | | - } |
151 | | - } |
152 | | - |
153 | | - store.setState(state => ({ |
154 | | - ...state, |
155 | | - lastClickedIndex: rowIndex, |
156 | | - } satisfies typeof state)) |
157 | | - shiftKeyRef.current = false |
158 | | - } |
| 131 | + }, |
| 132 | + }) |
159 | 133 |
|
160 | 134 | return ( |
161 | 135 | <div |
|
0 commit comments