feat-dev(wip): files table view (#2100)
This commit is contained in:
204
packages/web/src/javascripts/Components/Table/useTable.tsx
Normal file
204
packages/web/src/javascripts/Components/Table/useTable.tsx
Normal file
@@ -0,0 +1,204 @@
|
||||
import { MouseEventHandler, ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useApplication } from '../ApplicationProvider'
|
||||
import { Table, TableColumn, TableRow, TableSortBy } from './CommonTypes'
|
||||
|
||||
type TableSortOptions =
|
||||
| {
|
||||
sortBy: TableSortBy
|
||||
sortReversed: boolean
|
||||
onSortChange: (sortBy: TableSortBy, reversed: boolean) => void
|
||||
}
|
||||
| {
|
||||
sortBy?: never
|
||||
sortReversed?: never
|
||||
onSortChange?: never
|
||||
}
|
||||
|
||||
type TableSelectionOptions =
|
||||
| {
|
||||
enableRowSelection: boolean
|
||||
enableMultipleRowSelection?: boolean
|
||||
selectedRowIds?: string[]
|
||||
onRowSelectionChange?: (rowIds: string[]) => void
|
||||
selectionActions?: (selected: string[]) => ReactNode
|
||||
showSelectionActions?: boolean
|
||||
}
|
||||
| {
|
||||
enableRowSelection?: never
|
||||
enableMultipleRowSelection?: never
|
||||
selectedRowIds?: never
|
||||
onRowSelectionChange?: never
|
||||
selectionActions?: never
|
||||
showSelectionActions?: never
|
||||
}
|
||||
|
||||
type TableRowOptions<Data> = {
|
||||
getRowId?: (data: Data) => string
|
||||
onRowDoubleClick?: (data: Data) => void
|
||||
onRowContextMenu?: (x: number, y: number, data: Data) => void
|
||||
rowActions?: (data: Data) => ReactNode
|
||||
}
|
||||
|
||||
export type UseTableOptions<Data> = {
|
||||
data: Data[]
|
||||
columns: TableColumn<Data>[]
|
||||
} & TableRowOptions<Data> &
|
||||
TableSortOptions &
|
||||
TableSelectionOptions
|
||||
|
||||
export function useTable<Data>({
|
||||
data,
|
||||
columns,
|
||||
sortBy,
|
||||
sortReversed,
|
||||
onSortChange,
|
||||
getRowId,
|
||||
enableRowSelection,
|
||||
enableMultipleRowSelection,
|
||||
selectedRowIds,
|
||||
onRowSelectionChange,
|
||||
onRowDoubleClick,
|
||||
onRowContextMenu,
|
||||
rowActions,
|
||||
selectionActions,
|
||||
showSelectionActions,
|
||||
}: UseTableOptions<Data>): Table<Data> {
|
||||
const application = useApplication()
|
||||
const [selectedRows, setSelectedRows] = useState<string[]>(selectedRowIds || [])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedRowIds) {
|
||||
setSelectedRows(selectedRowIds)
|
||||
}
|
||||
}, [selectedRowIds])
|
||||
|
||||
useEffect(() => {
|
||||
if (onRowSelectionChange) {
|
||||
onRowSelectionChange(selectedRows)
|
||||
}
|
||||
}, [selectedRows, onRowSelectionChange])
|
||||
|
||||
const headers = useMemo(
|
||||
() =>
|
||||
columns.map((column) => {
|
||||
return {
|
||||
name: column.name,
|
||||
isSorting: sortBy && sortBy === column.sortBy,
|
||||
sortBy: column.sortBy,
|
||||
sortReversed: sortReversed,
|
||||
onSortChange: () => {
|
||||
if (!onSortChange || !column.sortBy) {
|
||||
return
|
||||
}
|
||||
onSortChange(column.sortBy, sortBy === column.sortBy ? !sortReversed : false)
|
||||
},
|
||||
}
|
||||
}),
|
||||
[columns, onSortChange, sortBy, sortReversed],
|
||||
)
|
||||
|
||||
const rows: TableRow<Data>[] = useMemo(
|
||||
() =>
|
||||
data.map((rowData, index) => {
|
||||
const cells = columns.map((column) => {
|
||||
return column.cell(rowData)
|
||||
})
|
||||
const id = getRowId ? getRowId(rowData) : index.toString()
|
||||
const row: TableRow<Data> = {
|
||||
id,
|
||||
isSelected: enableRowSelection ? selectedRows.includes(id) : false,
|
||||
cells,
|
||||
rowData,
|
||||
rowActions: rowActions ? rowActions(rowData) : undefined,
|
||||
}
|
||||
return row
|
||||
}),
|
||||
[columns, data, enableRowSelection, getRowId, rowActions, selectedRows],
|
||||
)
|
||||
|
||||
const handleRowClick = useCallback(
|
||||
(id: string) => {
|
||||
const handler: MouseEventHandler<HTMLTableRowElement> = (event) => {
|
||||
if (!enableRowSelection) {
|
||||
return
|
||||
}
|
||||
const isCmdOrCtrlPressed = application.keyboardService.isMac ? event.metaKey : event.ctrlKey
|
||||
if (isCmdOrCtrlPressed && enableMultipleRowSelection) {
|
||||
setSelectedRows((prev) => (prev.includes(id) ? prev.filter((rowId) => rowId !== id) : [...prev, id]))
|
||||
} else if (event.shiftKey && enableMultipleRowSelection) {
|
||||
const lastSelectedIndex = rows.findIndex((row) => row.id === selectedRows[selectedRows.length - 1])
|
||||
const currentIndex = rows.findIndex((row) => row.id === id)
|
||||
const start = Math.min(lastSelectedIndex, currentIndex)
|
||||
const end = Math.max(lastSelectedIndex, currentIndex)
|
||||
const newSelectedRows = rows.slice(start, end + 1).map((row) => row.id)
|
||||
setSelectedRows(newSelectedRows)
|
||||
} else {
|
||||
setSelectedRows([id])
|
||||
}
|
||||
}
|
||||
return handler
|
||||
},
|
||||
[application.keyboardService.isMac, enableMultipleRowSelection, enableRowSelection, rows, selectedRows],
|
||||
)
|
||||
|
||||
const handleRowDoubleClick = useCallback(
|
||||
(id: string) => {
|
||||
const handler: MouseEventHandler<HTMLTableRowElement> = () => {
|
||||
if (!onRowDoubleClick) {
|
||||
return
|
||||
}
|
||||
const rowData = rows.find((row) => row.id === id)?.rowData
|
||||
if (rowData) {
|
||||
onRowDoubleClick(rowData)
|
||||
}
|
||||
}
|
||||
return handler
|
||||
},
|
||||
[onRowDoubleClick, rows],
|
||||
)
|
||||
|
||||
const handleRowContextMenu = useCallback(
|
||||
(id: string) => {
|
||||
const handler: MouseEventHandler<HTMLTableRowElement> = (event) => {
|
||||
if (!onRowContextMenu) {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
const rowData = rows.find((row) => row.id === id)?.rowData
|
||||
if (rowData) {
|
||||
setSelectedRows([id])
|
||||
onRowContextMenu(event.clientX, event.clientY, rowData)
|
||||
}
|
||||
}
|
||||
return handler
|
||||
},
|
||||
[onRowContextMenu, rows],
|
||||
)
|
||||
|
||||
const table: Table<Data> = useMemo(
|
||||
() => ({
|
||||
headers,
|
||||
rows,
|
||||
handleRowClick,
|
||||
handleRowDoubleClick,
|
||||
handleRowContextMenu,
|
||||
selectedRows,
|
||||
canSelectRows: enableRowSelection || false,
|
||||
selectionActions: selectionActions ? selectionActions(selectedRows) : undefined,
|
||||
showSelectionActions: showSelectionActions || false,
|
||||
}),
|
||||
[
|
||||
enableRowSelection,
|
||||
handleRowClick,
|
||||
handleRowContextMenu,
|
||||
handleRowDoubleClick,
|
||||
headers,
|
||||
rows,
|
||||
selectedRows,
|
||||
selectionActions,
|
||||
showSelectionActions,
|
||||
],
|
||||
)
|
||||
|
||||
return table
|
||||
}
|
||||
Reference in New Issue
Block a user