← All changes
|
js/components/common/ListTable/ListTable.tsx
+95
-33
4.0.0-beta.1
→
trunk
View file →
| @@ -27,15 +27,15 @@ | ||
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | export interface ListTableNavProps<K extends Key, A extends string> { |
| 30 | 30 | actions?: ListTableAction<A>[] |
| 31 | - doAction: (action: A, selected: Set<K>) => Promise<void> | |
| 31 | + doAction?: (action: A, selected: Set<K>) => Promise<void> | |
| 32 | 32 | disabled?: boolean |
| 33 | 33 | extraTableNav?: (which: 'top' | 'bottom') => ReactNode |
| 34 | + endTableNav?: (which: 'top' | 'bottom') => ReactNode | |
| 34 | 35 | } |
| 35 | 36 | |
| 36 | 37 | export interface ListTableRowsProps<T, K extends Key> { |
| 37 | - items: T[] | |
| 38 | 38 | getKey: (item: T) => K |
| 39 | 39 | columns: ListTableColumn<T>[] |
| 40 | 40 | noItems?: ReactNode |
| 41 | 41 | rowClassName?: (item: T) => string |
| @@ -42,9 +42,9 @@ | ||
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | export interface ListTablePaginationProps { |
| 45 | 45 | totalPages?: number |
| 46 | - useQueryVars?: boolean | |
| 46 | + pageSearchParam?: string | |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | export interface ListTableBorderProps { |
| 50 | 50 | fixed?: boolean |
| @@ -51,15 +51,9 @@ | ||
| 51 | 51 | striped?: boolean |
| 52 | 52 | className?: string |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | -export type ListTableProps<T, K extends Key, A extends string> = | |
| 56 | - ListTableBorderProps & | |
| 57 | - ListTableNavProps<K, A> & | |
| 58 | - ListTablePaginationProps & | |
| 59 | - ListTableRowsProps<T, K> | |
| 60 | - | |
| 61 | -const sortItems = <T, >( | |
| 55 | +export const sortTableItems = <T, >( | |
| 62 | 56 | items: T[], |
| 63 | 57 | sortColumn: ListTableColumn<T> | undefined, |
| 64 | 58 | sortDirection: ListTableSortDirection |
| 65 | 59 | ): T[] => |
| @@ -102,9 +96,10 @@ | ||
| 102 | 96 | selected: Set<K> |
| 103 | 97 | ): Set<K> => |
| 104 | 98 | new Set(visibleItems.map(getKey).filter(key => selected.has(key))) |
| 105 | 99 | |
| 106 | -interface TableBorderProps<T, K extends Key> extends ListTableBorderProps, Omit<ColumnHeadingsProps<T, K>, 'which'> { | |
| 100 | +interface TableBorderProps<T, K extends Key> | |
| 101 | + extends ListTableBorderProps, Omit<ColumnHeadingsProps<T, K>, 'which'> { | |
| 107 | 102 | children: ReactNode |
| 108 | 103 | } |
| 109 | 104 | |
| 110 | 105 | const TableBorder = <T, K extends Key>({ |
| @@ -126,48 +121,115 @@ | ||
| 126 | 121 | </tfoot> |
| 127 | 122 | </table> |
| 128 | 123 | ) |
| 129 | 124 | |
| 125 | +export interface ListTableProps<T, K extends Key, A extends string> extends ListTableBorderProps, | |
| 126 | + ListTableNavProps<K, A>, | |
| 127 | + ListTablePaginationProps, | |
| 128 | + ListTableRowsProps<T, K> { | |
| 129 | + items: T[] | |
| 130 | + beforeTable?: ReactNode | |
| 131 | + selectAllControl?: boolean | |
| 132 | + | |
| 133 | + /** Column and direction to sort by before the reader touches a heading. */ | |
| 134 | + initialSort?: { columnId: string, direction: ListTableSortDirection } | |
| 135 | +} | |
| 136 | + | |
| 130 | 137 | export const ListTable = <T, K extends Key, A extends string = never>({ |
| 131 | 138 | items, |
| 132 | 139 | getKey, |
| 140 | + totalPages, | |
| 141 | + pageSearchParam = 'paged', | |
| 142 | + initialSort, | |
| 143 | + ...tableProps | |
| 144 | +}: ListTableProps<T, K, A>) => { | |
| 145 | + const [sortColumn, setSortColumn] = useState<ListTableColumn<T> | undefined>( | |
| 146 | + () => initialSort | |
| 147 | + ? tableProps.columns.find(column => column.id === initialSort.columnId && column.sortedValue) | |
| 148 | + : undefined | |
| 149 | + ) | |
| 150 | + const [currentPage, setCurrentPage] = useState( | |
| 151 | + () => pageSearchParam && Number(fetchQueryParam(pageSearchParam)) || 1 | |
| 152 | + ) | |
| 153 | + const [sortDirection, setSortDirection] = useState<ListTableSortDirection>( | |
| 154 | + () => initialSort?.direction ?? 'asc' | |
| 155 | + ) | |
| 156 | + | |
| 157 | + const visibleItems: T[] = useMemo( | |
| 158 | + () => pageItems(sortTableItems(items, sortColumn, sortDirection), { currentPage, totalPages }), | |
| 159 | + [items, sortColumn, sortDirection, currentPage, totalPages]) | |
| 160 | + | |
| 161 | + return ( | |
| 162 | + <PartialDataListTable | |
| 163 | + getKey={getKey} | |
| 164 | + totalItems={items.length} | |
| 165 | + totalPages={totalPages} | |
| 166 | + visibleItems={visibleItems} | |
| 167 | + pageSearchParam={pageSearchParam} | |
| 168 | + {...{ sortColumn, sortDirection, currentPage, setSortColumn, setSortDirection, setCurrentPage }} | |
| 169 | + {...tableProps} | |
| 170 | + /> | |
| 171 | + ) | |
| 172 | +} | |
| 173 | + | |
| 174 | +export interface PartialDataListTableProps<T, K extends Key, A extends string> | |
| 175 | + extends ListTablePaginationProps, | |
| 176 | + ListTableBorderProps, | |
| 177 | + ListTableRowsProps<T, K>, | |
| 178 | + ListTableNavProps<K, A> { | |
| 179 | + sortColumn: ListTableColumn<T> | undefined | |
| 180 | + totalItems: number | |
| 181 | + currentPage: number | |
| 182 | + visibleItems: T[] | |
| 183 | + beforeTable?: ReactNode | |
| 184 | + selectAllControl?: boolean | |
| 185 | + setSortColumn: (column: ListTableColumn<T> | undefined) => void | |
| 186 | + sortDirection?: ListTableSortDirection | |
| 187 | + setCurrentPage: (page: number) => void | |
| 188 | + setSortDirection: (direction: ListTableSortDirection) => void | |
| 189 | +} | |
| 190 | + | |
| 191 | +export const PartialDataListTable = <T, K extends Key, A extends string>({ | |
| 192 | + getKey, | |
| 193 | + actions, | |
| 133 | 194 | columns, |
| 134 | - actions, | |
| 195 | + noItems, | |
| 135 | 196 | doAction, |
| 197 | + disabled = false, | |
| 198 | + totalItems, | |
| 136 | 199 | totalPages, |
| 200 | + currentPage, | |
| 201 | + beforeTable, | |
| 202 | + endTableNav, | |
| 203 | + rowClassName, | |
| 204 | + visibleItems, | |
| 205 | + sortDirection = 'asc', | |
| 137 | 206 | extraTableNav, |
| 138 | - disabled = false, | |
| 139 | - useQueryVars = true, | |
| 140 | - fixed, | |
| 141 | - striped, | |
| 142 | - className, | |
| 143 | - ...tableRowsProps | |
| 144 | -}: ListTableProps<T, K, A>) => { | |
| 207 | + selectAllControl, | |
| 208 | + setCurrentPage, | |
| 209 | + pageSearchParam, | |
| 210 | + ...tableBorderProps | |
| 211 | +}: PartialDataListTableProps<T, K, A>) => { | |
| 145 | 212 | const [selected, setSelected] = useState(() => new Set<K>()) |
| 146 | - const [sortColumn, setSortColumn] = useState<ListTableColumn<T>>() | |
| 147 | - const [currentPage, setCurrentPage] = useState(() => useQueryVars && Number(fetchQueryParam('paged')) || 1) | |
| 148 | - const [sortDirection, setSortDirection] = useState<ListTableSortDirection>('asc') | |
| 149 | 213 | |
| 150 | - const visibleItems: T[] = useMemo( | |
| 151 | - () => pageItems(sortItems(items, sortColumn, sortDirection), { currentPage, totalPages }), | |
| 152 | - [items, sortColumn, sortDirection, currentPage, totalPages]) | |
| 153 | 214 | return ( |
| 154 | 215 | <TableNavigation |
| 155 | - totalItems={items.length} | |
| 216 | + totalItems={totalItems} | |
| 156 | 217 | selected={getVisibleSelected(visibleItems, getKey, selected)} |
| 157 | - {...{ actions, doAction, extraTableNav, disabled, currentPage, totalPages, useQueryVars, setSelected, setCurrentPage }} | |
| 218 | + selectAllKeys={selectAllControl ? visibleItems.map(getKey) : undefined} | |
| 219 | + {...{ actions, doAction, extraTableNav, endTableNav, disabled, currentPage, totalPages }} | |
| 220 | + {...{ pageSearchParam, setSelected, setCurrentPage }} | |
| 158 | 221 | > |
| 222 | + {beforeTable} | |
| 223 | + | |
| 159 | 224 | <TableBorder |
| 160 | 225 | items={visibleItems} |
| 161 | - fixed={fixed} | |
| 162 | - striped={striped} | |
| 163 | - className={className} | |
| 164 | - {...{ columns, getKey, selected, sortColumn, sortDirection, setSelected, setSortColumn, setSortDirection }} | |
| 226 | + {...tableBorderProps} | |
| 227 | + {...{ getKey, columns, selected, setSelected, sortDirection }} | |
| 165 | 228 | > |
| 166 | 229 | <TableRows |
| 167 | 230 | items={visibleItems} |
| 168 | - {...{ getKey, columns, selected, setSelected }} | |
| 169 | - {...tableRowsProps} | |
| 231 | + {...{ getKey, columns, noItems, rowClassName, selected, setSelected }} | |
| 170 | 232 | /> |
| 171 | 233 | </TableBorder> |
| 172 | 234 | </TableNavigation> |
| 173 | 235 | ) |