@coveord/plasma-mantine
Version:
A Plasma flavoured Mantine theme
266 lines (265 loc) • 8.45 kB
JavaScript
import { useDidUpdate } from '@mantine/hooks';
import defaultsDeep from 'lodash.defaultsdeep';
import { useCallback, useMemo, useState } from 'react';
import { useUrlSyncedState } from './use-url-synced-state';
const defaultOptions = {
enableRowSelection: true,
enableMultiRowSelection: false,
forceSelection: false,
syncWithUrl: false
};
const defaultState = {
pagination: {
pageIndex: 0,
pageSize: 50
},
totalEntries: null,
sorting: [],
globalFilter: '',
predicates: {},
layout: null,
dateRange: [
null,
null
],
rowSelection: {},
columnVisibility: {}
};
const serialization = (input)=>Object.freeze(input);
const PAGINATION_SERIALIZATION = serialization({
serializer: ({ pageIndex, pageSize })=>[
[
'page',
(pageIndex + 1).toString()
],
[
'pageSize',
pageSize.toString()
]
],
deserializer: (params, initialState)=>defaultsDeep({
pageIndex: params.get('page') ? Math.max(1, parseInt(params.get('page'), 10)) - 1 : undefined,
pageSize: params.get('pageSize') ? parseInt(params.get('pageSize'), 10) : undefined
}, initialState)
});
const SORTING_SERIALIZATION = serialization({
serializer: (sorting)=>[
[
'sortBy',
sorting.map(({ id, desc })=>`${id}.${desc ? 'desc' : 'asc'}`).join(',')
]
],
deserializer: (params, initialState)=>{
if (!params.has('sortBy')) {
return initialState;
}
const sorts = params.get('sortBy')?.split(',') ?? [];
return sorts.map((sort)=>{
const [id, order] = sort.split('.');
return {
id,
desc: order === 'desc'
};
});
}
});
const GLOBAL_FILTER_SERIALIZATION = serialization({
serializer: (filter)=>[
[
'filter',
filter
]
],
deserializer: (params, initialState)=>params.get('filter') ?? initialState
});
const PREDICATES_SERIALIZATION = serialization({
serializer: (predicates)=>Object.entries(predicates),
deserializer: (params, initialState)=>Object.keys(initialState).reduce((acc, predicateKey)=>{
acc[predicateKey] = params.get(predicateKey) ?? initialState[predicateKey];
return acc;
}, {})
});
const LAYOUT_SERIALIZATION = serialization({
serializer: (_layout)=>[
[
'layout',
_layout
]
],
deserializer: (params, initialState)=>params.get('layout') ?? initialState
});
const DATE_RANGE_SERIALIZATION = serialization({
serializer: ([from, to])=>[
[
'from',
from?.toISOString() ?? '',
true
],
[
'to',
to?.toISOString() ?? '',
true
]
],
deserializer: (params, initial)=>[
params.get('from') ? new Date(params.get('from')) : initial[0],
params.get('to') ? new Date(params.get('to')) : initial[1]
]
});
const COLUMN_VISIBILITY_SERIALIZATION = serialization({
serializer: (columns)=>[
[
'show',
Object.entries(columns).filter(([, visible])=>visible === true).map(([columnName])=>columnName).join(',')
],
[
'hide',
Object.entries(columns).filter(([, visible])=>visible === false).map(([columnName])=>columnName).join(',')
]
],
deserializer: (params, initial)=>{
if (!params.has('show') && !params.has('hide')) {
return initial;
}
const visible = params.get('show')?.split(',') ?? [];
const invisible = params.get('hide')?.split(',') ?? [];
const columns = {};
visible.forEach((column)=>{
columns[column] = true;
});
invisible.forEach((column)=>{
columns[column] = false;
});
return columns;
}
});
export const useTable = (userOptions = {})=>{
const options = defaultsDeep({}, userOptions, defaultOptions);
const initialState = defaultsDeep({}, options.initialState, defaultState);
/**
* The `useUrlSyncedState` hook defaults to synchronize, but the table wants to default to not synchronize,
* so always pass the sync option as a resolved boolean value.
*/ const sync = !!options.syncWithUrl;
// (Optionally) synced with url
const [pagination, setPagination] = useUrlSyncedState({
...PAGINATION_SERIALIZATION,
initialState: initialState.pagination,
sync
});
const [sorting, setSorting] = useUrlSyncedState({
...SORTING_SERIALIZATION,
initialState: initialState.sorting,
sync
});
const [globalFilter, setGlobalFilter] = useUrlSyncedState({
...GLOBAL_FILTER_SERIALIZATION,
initialState: initialState.globalFilter,
sync
});
const [predicates, setPredicates] = useUrlSyncedState({
...PREDICATES_SERIALIZATION,
initialState: initialState.predicates,
sync
});
const [layout, setLayout] = useUrlSyncedState({
...LAYOUT_SERIALIZATION,
initialState: initialState.layout,
sync
});
const [dateRange, setDateRange] = useUrlSyncedState({
...DATE_RANGE_SERIALIZATION,
initialState: initialState.dateRange,
sync
});
const [columnVisibility, setColumnVisibility] = useUrlSyncedState({
...COLUMN_VISIBILITY_SERIALIZATION,
initialState: initialState.columnVisibility,
sync
});
// unsynced
const [totalEntries, _setTotalEntries] = useState(initialState.totalEntries);
const [unfilteredTotalEntries, setUnfilteredTotalEntries] = useState(initialState.totalEntries);
const [expanded, setExpanded] = useState(initialState.expanded);
const [rowSelection, setRowSelection] = useState(initialState.rowSelection);
const isFiltered = !!globalFilter || Object.keys(predicates).some((predicate)=>!!predicates[predicate]) || !!dateRange?.[0] || !!dateRange?.[1];
const isVacant = unfilteredTotalEntries === 0;
const setTotalEntries = useCallback((updater)=>{
_setTotalEntries((old)=>{
const newTotalEntries = updater instanceof Function ? updater(old) : updater;
if (!isFiltered) {
setUnfilteredTotalEntries(newTotalEntries);
}
return newTotalEntries;
});
}, [
isFiltered
]);
const clearFilters = useCallback(()=>{
setPredicates(initialState.predicates);
setGlobalFilter('');
}, []);
const clearRowSelection = useCallback(()=>{
setRowSelection({});
}, []);
const getSelectedRows = useCallback(()=>Object.values(rowSelection), [
rowSelection
]);
const getSelectedRow = ()=>getSelectedRows()[0] ?? null;
useDidUpdate(()=>{
if (!options.enableMultiRowSelection) {
clearRowSelection();
}
}, [
globalFilter,
pagination,
sorting,
dateRange,
predicates
]);
const state = useMemo(()=>({
pagination,
totalEntries,
sorting,
globalFilter,
expanded,
predicates,
layout,
dateRange,
rowSelection,
columnVisibility
}), [
pagination,
totalEntries,
sorting,
globalFilter,
expanded,
predicates,
layout,
dateRange,
rowSelection,
columnVisibility
]);
return {
state,
setPagination,
setTotalEntries,
setSorting,
setGlobalFilter,
setExpanded,
setPredicates,
setLayout,
setDateRange,
setRowSelection,
setColumnVisibility,
isFiltered,
isVacant,
clearFilters,
clearRowSelection,
getSelectedRows,
getSelectedRow,
rowSelectionEnabled: options.enableRowSelection,
rowSelectionForced: options.forceSelection,
multiRowSelectionEnabled: options.enableMultiRowSelection
};
};
//# sourceMappingURL=use-table.js.map