Add snap to table scrolls

This commit is contained in:
IRBorisov 2024-05-02 21:19:23 +03:00
parent ff48364536
commit 91c5993b10
14 changed files with 37 additions and 24 deletions

View File

@ -94,7 +94,7 @@ function ConstituentaMultiPicker({ id, schema, prefixID, rows, selected, setSele
noFooter noFooter
rows={rows} rows={rows}
contentHeight='1.3rem' contentHeight='1.3rem'
className={clsx('overflow-y-auto', 'border', 'text-sm', 'select-none')} className={clsx('cc-scroll-y', 'border', 'text-sm', 'select-none')}
data={schema?.items ?? []} data={schema?.items ?? []}
columns={columns} columns={columns}
headPosition='0rem' headPosition='0rem'

View File

@ -101,7 +101,7 @@ function ConstituentaPicker({
dense dense
noHeader noHeader
noFooter noFooter
className='overflow-y-auto text-sm select-none' className='text-sm select-none cc-scroll-y'
data={filteredData} data={filteredData}
columns={columns} columns={columns}
conditionalRowStyles={conditionalRowStyles} conditionalRowStyles={conditionalRowStyles}

View File

@ -98,7 +98,7 @@ function SchemaPicker({ id, initialFilter = '', rows = 4, value, onSelectValue }
dense dense
noHeader noHeader
noFooter noFooter
className='overflow-y-auto text-sm select-none' className='text-sm select-none cc-scroll-y'
data={items} data={items}
columns={columns} columns={columns}
conditionalRowStyles={conditionalRowStyles} conditionalRowStyles={conditionalRowStyles}

View File

@ -155,6 +155,7 @@ function DataTable<TData extends RowData>({
<TableBody <TableBody
table={tableImpl} table={tableImpl}
dense={dense} dense={dense}
noHeader={noHeader}
conditionalRowStyles={conditionalRowStyles} conditionalRowStyles={conditionalRowStyles}
enableRowSelection={enableRowSelection} enableRowSelection={enableRowSelection}
lastSelected={lastSelected} lastSelected={lastSelected}

View File

@ -1,4 +1,5 @@
import { Cell, flexRender, Row, Table } from '@tanstack/react-table'; import { Cell, flexRender, Row, Table } from '@tanstack/react-table';
import clsx from 'clsx';
import { CProps } from '@/components/props'; import { CProps } from '@/components/props';
@ -8,6 +9,7 @@ import SelectRow from './SelectRow';
interface TableBodyProps<TData> { interface TableBodyProps<TData> {
table: Table<TData>; table: Table<TData>;
dense?: boolean; dense?: boolean;
noHeader?: boolean;
enableRowSelection?: boolean; enableRowSelection?: boolean;
conditionalRowStyles?: IConditionalStyle<TData>[]; conditionalRowStyles?: IConditionalStyle<TData>[];
@ -21,6 +23,7 @@ interface TableBodyProps<TData> {
function TableBody<TData>({ function TableBody<TData>({
table, table,
dense, dense,
noHeader,
enableRowSelection, enableRowSelection,
conditionalRowStyles, conditionalRowStyles,
lastSelected, lastSelected,
@ -67,14 +70,16 @@ function TableBody<TData>({
{table.getRowModel().rows.map((row: Row<TData>, index) => ( {table.getRowModel().rows.map((row: Row<TData>, index) => (
<tr <tr
key={row.id} key={row.id}
className={ className={clsx(
'cc-table-row',
!noHeader && 'scroll-mt-[calc(2px+2rem)]',
row.getIsSelected() row.getIsSelected()
? 'clr-selected clr-hover' ? 'clr-selected clr-hover'
: index % 2 === 0 : index % 2 === 0
? 'clr-controls clr-hover' ? 'clr-controls clr-hover'
: 'clr-app clr-hover' : 'clr-app clr-hover'
} )}
style={conditionalRowStyles && getRowStyles(row)} style={{ ...(conditionalRowStyles ? getRowStyles(row) : []) }}
> >
{enableRowSelection ? ( {enableRowSelection ? (
<td key={`select-${row.id}`} className='pl-3 pr-1 align-middle border-y'> <td key={`select-${row.id}`} className='pl-3 pr-1 align-middle border-y'>

View File

@ -152,7 +152,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
noHeader noHeader
className={clsx( className={clsx(
'max-h-[5.8rem] min-h-[5.8rem]', // prettier: split lines 'max-h-[5.8rem] min-h-[5.8rem]', // prettier: split lines
'overflow-y-auto', 'cc-scroll-y',
'text-sm', 'text-sm',
'border', 'border',
'select-none' 'select-none'

View File

@ -92,10 +92,10 @@ function VersionsTable({ processing, items, onDelete, selected, onSelect }: Vers
<DataTable <DataTable
dense dense
noFooter noFooter
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'overflow-y-auto')} headPosition='0'
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'cc-scroll-y')}
data={items} data={items}
columns={columns} columns={columns}
headPosition='0'
onRowClicked={rowData => onSelect(rowData.id)} onRowClicked={rowData => onSelect(rowData.id)}
conditionalRowStyles={conditionalRowStyles} conditionalRowStyles={conditionalRowStyles}
/> />

View File

@ -37,7 +37,6 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
() => [ () => [
columnHelper.accessor('text', { columnHelper.accessor('text', {
id: 'text', id: 'text',
header: 'Текст',
size: 350, size: 350,
minSize: 500, minSize: 500,
maxSize: 500, maxSize: 500,
@ -45,7 +44,6 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
}), }),
columnHelper.accessor('grams', { columnHelper.accessor('grams', {
id: 'grams', id: 'grams',
header: 'Граммемы',
maxSize: 150, maxSize: 150,
cell: props => <WordFormBadge keyPrefix={props.cell.id} form={props.row.original} /> cell: props => <WordFormBadge keyPrefix={props.cell.id} form={props.row.original} />
}), }),
@ -74,7 +72,8 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
<DataTable <DataTable
dense dense
noFooter noFooter
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'text-sm', 'overflow-y-auto')} noHeader
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'text-sm', 'cc-scroll-y')}
data={forms} data={forms}
columns={columns} columns={columns}
headPosition='0' headPosition='0'

View File

@ -7,7 +7,6 @@ import DataLoader from '@/components/wrap/DataLoader';
import { useAuth } from '@/context/AuthContext'; import { useAuth } from '@/context/AuthContext';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import { useConceptNavigation } from '@/context/NavigationContext'; import { useConceptNavigation } from '@/context/NavigationContext';
import { useConceptOptions } from '@/context/OptionsContext';
import useLocalStorage from '@/hooks/useLocalStorage'; import useLocalStorage from '@/hooks/useLocalStorage';
import useQueryStrings from '@/hooks/useQueryStrings'; import useQueryStrings from '@/hooks/useQueryStrings';
import { ILibraryItem } from '@/models/library'; import { ILibraryItem } from '@/models/library';
@ -26,7 +25,6 @@ function LibraryPage() {
const { user } = useAuth(); const { user } = useAuth();
const library = useLibrary(); const library = useLibrary();
const { setShowScroll } = useConceptOptions();
const [filter, setFilter] = useState<ILibraryFilter>({}); const [filter, setFilter] = useState<ILibraryFilter>({});
const [items, setItems] = useState<ILibraryItem[]>([]); const [items, setItems] = useState<ILibraryItem[]>([]);
@ -47,11 +45,6 @@ function LibraryPage() {
setFilter(filterFromStrategy(queryFilter)); setFilter(filterFromStrategy(queryFilter));
}, [user, router, setQuery, setFilter, setStrategy, strategy, queryFilter]); }, [user, router, setQuery, setFilter, setStrategy, strategy, queryFilter]);
useLayoutEffect(() => {
setShowScroll(true);
return () => setShowScroll(false);
}, [setShowScroll]);
useLayoutEffect(() => { useLayoutEffect(() => {
setItems(library.applyFilter(filter)); setItems(library.applyFilter(filter));
}, [library, filter, filter.query]); }, [library, filter, filter.query]);

View File

@ -11,6 +11,7 @@ import DataTable, { createColumnHelper, VisibilityState } from '@/components/ui/
import FlexColumn from '@/components/ui/FlexColumn'; import FlexColumn from '@/components/ui/FlexColumn';
import TextURL from '@/components/ui/TextURL'; import TextURL from '@/components/ui/TextURL';
import { useConceptNavigation } from '@/context/NavigationContext'; import { useConceptNavigation } from '@/context/NavigationContext';
import { useConceptOptions } from '@/context/OptionsContext';
import { useUsers } from '@/context/UsersContext'; import { useUsers } from '@/context/UsersContext';
import useLocalStorage from '@/hooks/useLocalStorage'; import useLocalStorage from '@/hooks/useLocalStorage';
import useWindowSize from '@/hooks/useWindowSize'; import useWindowSize from '@/hooks/useWindowSize';
@ -31,6 +32,7 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
const router = useConceptNavigation(); const router = useConceptNavigation();
const intl = useIntl(); const intl = useIntl();
const { getUserLabel } = useUsers(); const { getUserLabel } = useUsers();
const { calculateHeight } = useConceptOptions();
const [itemsPerPage, setItemsPerPage] = useLocalStorage<number>(storage.libraryPagination, 50); const [itemsPerPage, setItemsPerPage] = useLocalStorage<number>(storage.libraryPagination, 50);
function handleOpenItem(item: ILibraryItem, event: CProps.EventMouse) { function handleOpenItem(item: ILibraryItem, event: CProps.EventMouse) {
@ -109,6 +111,8 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
[intl, getUserLabel, windowSize] [intl, getUserLabel, windowSize]
); );
const tableHeight = useMemo(() => calculateHeight('2.2rem'), [calculateHeight]);
return ( return (
<> <>
<div className='sticky top-[2.3rem]'> <div className='sticky top-[2.3rem]'>
@ -127,8 +131,9 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
id='library_data' id='library_data'
columns={columns} columns={columns}
data={items} data={items}
headPosition='2.2rem' headPosition='0'
className='text-xs sm:text-sm' className='text-xs sm:text-sm cc-scroll-y'
style={{ maxHeight: tableHeight }}
noDataComponent={ noDataComponent={
<FlexColumn className='p-3 items-center min-h-[6rem]'> <FlexColumn className='p-3 items-center min-h-[6rem]'>
<p>Список схем пуст</p> <p>Список схем пуст</p>

View File

@ -121,7 +121,7 @@ function RSTable({ items, maxHeight, enableSelection, selected, setSelected, onE
<DataTable <DataTable
dense dense
noFooter noFooter
className={clsx('min-h-[16rem]', 'overflow-y-auto', 'text-sm', 'select-none')} className={clsx('min-h-[16rem]', 'cc-scroll-y', 'text-sm', 'select-none')}
style={{ maxHeight: maxHeight }} style={{ maxHeight: maxHeight }}
data={items ?? []} data={items ?? []}
columns={columns} columns={columns}

View File

@ -129,7 +129,7 @@ function ConstituentsTable({ items, activeID, onOpenEdit, maxHeight, denseThresh
<DataTable <DataTable
dense dense
noFooter noFooter
className='overflow-y-auto text-sm select-none overscroll-none' className='text-sm select-none cc-scroll-y overscroll-none'
style={{ maxHeight: maxHeight }} style={{ maxHeight: maxHeight }}
data={items} data={items}
columns={columns} columns={columns}

View File

@ -65,7 +65,7 @@ function ViewSubscriptions({ items }: ViewSubscriptionsProps) {
<DataTable <DataTable
dense dense
noFooter noFooter
className='max-h-[23.8rem] overflow-y-auto text-sm border' className='max-h-[23.8rem] cc-scroll-y text-sm border'
columns={columns} columns={columns}
data={items} data={items}
headPosition='0' headPosition='0'

View File

@ -216,6 +216,16 @@
@apply flex gap-1; @apply flex gap-1;
} }
.cc-table-row {
scroll-snap-align: start;
scroll-snap-stop: always;
}
.cc-scroll-y {
overflow-y: auto;
scroll-snap-type: y mandatory;
}
.cc-blur { .cc-blur {
backdrop-filter: blur(3px); backdrop-filter: blur(3px);
} }