Skip to content

Commit

Permalink
Merge pull request #308 from qoretechnologies/foxhoundn/enhancement-a…
Browse files Browse the repository at this point in the history
…dd-paging-307

Tables now support paging. Added shadow to pinned columns.
  • Loading branch information
Foxhoundn authored Jul 13, 2023
2 parents 0258ce9 + ae16d5f commit a75d2ea
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 50 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@qoretechnologies/reqore",
"version": "0.35.2",
"version": "0.35.3",
"description": "ReQore is a highly theme-able and modular UI library for React",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
47 changes: 41 additions & 6 deletions src/components/Collection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import ReqoreInput, { IReqoreInputProps } from '../Input';
import ReqoreMessage from '../Message';
import { IReqorePanelAction, IReqorePanelProps, ReqorePanel, TReqorePanelActions } from '../Panel';
import { ReqoreVerticalSpacer } from '../Spacer';
import { sortTableData } from '../Table/helpers';
import { getZoomActions, sizeToZoom, sortTableData, zoomToSize } from '../Table/helpers';
import { IReqoreCollectionItemProps, ReqoreCollectionItem } from './item';

export interface IReqoreCollectionProps extends IReqorePanelProps, IReqoreColumnsProps {
Expand All @@ -29,9 +29,14 @@ export interface IReqoreCollectionProps extends IReqorePanelProps, IReqoreColumn
height?: string;
fill?: boolean;
maxItemHeight?: number;
filterable?: boolean;

defaultQuery?: string;
defaultZoom?: 0 | 0.5 | 1 | 1.5 | 2;

filterable?: boolean;
sortable?: boolean;
zoomable?: boolean;

showAs?: 'list' | 'grid';
showSelectedFirst?: boolean;
selectedIcon?: IReqoreIconName;
Expand Down Expand Up @@ -67,6 +72,14 @@ export const StyledCollectionWrapper = styled(StyledColumns)`
position: relative;
`;

export const zoomToWidth = {
0: '200px',
0.5: '300px',
1: '400px',
1.5: '500px',
2: '600px',
};

export const ReqoreCollection = ({
items,
stacked,
Expand All @@ -76,6 +89,8 @@ export const ReqoreCollection = ({
filterable,
inputInTitle = true,
sortable,
zoomable,
defaultZoom,
showSelectedFirst,
inputProps,
sortButtonProps,
Expand Down Expand Up @@ -116,6 +131,7 @@ export const ReqoreCollection = ({
const [sort, setSort] = useState<'asc' | 'desc'>('asc');
const [contentRef, setContentRef] = useState<HTMLDivElement>(undefined);
const isMobile = useReqoreProperty('isMobile');
const [zoom, setZoom] = useState<number>(defaultZoom || sizeToZoom.normal);
const { query, setQuery, preQuery, setPreQuery } = useQueryWithDelay(
defaultQuery,
searchDelay,
Expand Down Expand Up @@ -197,6 +213,13 @@ export const ReqoreCollection = ({
],
};

if (zoomable) {
actions.push({
fluid: false,
group: getZoomActions('reqore-collection', zoom, setZoom),
});
}

if (sortable) {
toolbarGroup.group.push({
icon: sort === 'desc' ? 'SortDesc' : 'SortAsc',
Expand Down Expand Up @@ -233,7 +256,19 @@ export const ReqoreCollection = ({
}

return [...actions, toolbarGroup];
}, [filterable, preQuery, query, rest.actions, _showAs, sort, sortable, filteredItems, isMobile]);
}, [
filterable,
preQuery,
query,
rest.actions,
_showAs,
sort,
sortable,
filteredItems,
isMobile,
zoom,
zoomable,
]);

const renderContent = useCallback(() => {
return contentRenderer(
Expand Down Expand Up @@ -261,13 +296,13 @@ export const ReqoreCollection = ({
ref={setContentRef}
height={height}
alignItems={alignItems}
minColumnWidth={minColumnWidth}
minColumnWidth={minColumnWidth || zoomToWidth[zoom]}
maxColumnWidth={maxColumnWidth}
className='reqore-collection-content'
>
{finalItems?.map((item, index) => (
<ReqoreCollectionItem
size={rest.size}
size={zoomToSize[zoom]}
responsiveTitle={false}
{...item}
icon={item.icon || (item.selected ? selectedIcon : undefined)}
Expand Down Expand Up @@ -313,8 +348,8 @@ export const ReqoreCollection = ({
rest,
rounded,
selectedIcon,
size,
stacked,
zoom,
]);

return (
Expand Down
13 changes: 9 additions & 4 deletions src/components/Table/body.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef } from 'react';
import { forwardRef, useMemo } from 'react';
import { useMount } from 'react-use';
import { FixedSizeList as List } from 'react-window';
import styled from 'styled-components';
Expand All @@ -7,7 +7,6 @@ import { useCombinedRefs } from '../../hooks/useCombinedRefs';
import ReqoreTableRow, { IReqoreTableRowOptions } from './row';

export interface IReqoreTableSectionBodyProps extends IReqoreTableRowOptions {
rowHeight?: number;
height: number;
refs: {
left: React.RefObject<HTMLDivElement>;
Expand All @@ -30,7 +29,6 @@ const ReqoreTableBody = forwardRef<HTMLDivElement, IReqoreTableSectionBodyProps>
{
data,
height,
rowHeight,
size = 'normal',
refs,
type,
Expand Down Expand Up @@ -70,11 +68,18 @@ const ReqoreTableBody = forwardRef<HTMLDivElement, IReqoreTableSectionBodyProps>
});
});

const rowHeight = useMemo(
() => (rest.flat ? TABLE_SIZE_TO_PX[size] : TABLE_SIZE_TO_PX[size] + 1),
[size, rest.flat]
);

return (
<StyledList
outerRef={targetRef}
itemCount={data.length}
height={height}
// If the defined height is less than the count of items' height
// use that height instead
height={height > data.length * rowHeight ? data.length * rowHeight : height}
className='reqore-table-body'
itemSize={rest.flat ? TABLE_SIZE_TO_PX[size] : TABLE_SIZE_TO_PX[size] + 1}
itemData={{
Expand Down
102 changes: 66 additions & 36 deletions src/components/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { size as count, isArray } from 'lodash';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { useMeasure, useUpdateEffect } from 'react-use';
import styled, { css } from 'styled-components';
import { ReqoreMessage, ReqorePanel, ReqoreVerticalSpacer } from '../..';
import { ReqoreMessage, ReqorePaginationContainer, ReqorePanel, ReqoreVerticalSpacer } from '../..';
import { TReqorePaginationType, getPagingObjectFromType } from '../../constants/paging';
import { TABLE_SIZE_TO_PX, TSizes } from '../../constants/sizes';
import { IReqoreTheme, TReqoreIntent } from '../../constants/theme';
import { useQueryWithDelay } from '../../hooks/useQueryWithDelay';
Expand Down Expand Up @@ -96,6 +97,8 @@ export interface IReqoreTableProps extends IReqorePanelProps {
height?: number;
wrapperSize?: TSizes;

paging?: TReqorePaginationType<IReqoreTableRowData>;

sort?: IReqoreTableSort;
onSortChange?: (sort?: IReqoreTableSort) => void;

Expand Down Expand Up @@ -141,16 +144,18 @@ export interface IReqoreTableSort {

const StyledTableWrapper = styled.div`
overflow: hidden;
display: flex;
flex-flow: column;
${({ isPinned }) =>
isPinned
? css`
flex-shrink: 0;
z-index: 1;
box-shadow: 1px -1px 20px -2px rgba(0, 0, 0, 0.8);
`
: css`
width: 100%;
display: flex;
flex-flow: column;
flex: 1;
`};
`;
Expand Down Expand Up @@ -192,6 +197,7 @@ const ReqoreTable = ({
rowComponent,
bodyCellComponent,
onSelectClick,
paging,
...rest
}: IReqoreTableProps) => {
const leftTableRef = useRef<HTMLDivElement>(undefined);
Expand Down Expand Up @@ -468,6 +474,23 @@ const ReqoreTable = ({
return _columnsList;
}, [finalColumns]);

const handleScrollToTop = () => {
mainTableRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
});
leftTableRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
});
rightTableRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
});

setIsScrolled(false);
};

const tableActions = useMemo<IReqorePanelAction[]>(() => {
const finalActions: IReqorePanelAction[] = [...actions];

Expand Down Expand Up @@ -515,22 +538,7 @@ const ReqoreTable = ({
tooltip: 'Scroll to top',
className: 'reqore-table-columns-scroll-top',
responsive: true,
onClick: () => {
mainTableRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
});
leftTableRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
});
rightTableRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
});

setIsScrolled(false);
},
onClick: handleScrollToTop,
});
}

Expand Down Expand Up @@ -598,7 +606,7 @@ const ReqoreTable = ({
[finalColumns]
);

const renderTable = (type: 'left' | 'main' | 'right' = 'main') => {
const renderTable = (type: 'left' | 'main' | 'right' = 'main', items: IReqoreTableRowData[]) => {
const tableColumns = columnsByType[type];
const isPinned = type === 'left' || type === 'right';

Expand All @@ -617,19 +625,19 @@ const ReqoreTable = ({
onSortChange={handleSortChange}
heightAsGroup={hasGroupedColumns(finalColumns)}
sortData={_sort}
hasVerticalScroll={count(transformedData) * TABLE_SIZE_TO_PX[size] > height}
hasVerticalScroll={count(items) * TABLE_SIZE_TO_PX[size] > height}
onColumnsUpdate={handleColumnsUpdate}
onFilterChange={(dataId: string, value: any) => {
handleColumnsUpdate(dataId, 'filter', value);
}}
component={headerCellComponent}
/>
{count(transformedData) === 0 ? null : (
{count(items) === 0 ? null : (
<ReqoreTableBody
ref={refs[type]}
refs={refs}
type={type}
data={transformedData}
data={items}
columns={tableColumns}
height={fill ? sizes.height : height}
selectable={selectable}
Expand All @@ -649,6 +657,8 @@ const ReqoreTable = ({
);
};

const pagingOptions = useMemo(() => getPagingObjectFromType(paging), [paging]);

return (
<ReqorePanel
transparent
Expand All @@ -665,19 +675,39 @@ const ReqoreTable = ({
getContentRef={wrapperRef}
badge={badge}
>
<StyledTablesWrapper className='reqore-table-wrapper'>
{renderTable('left')}
{renderTable()}
{renderTable('right')}
</StyledTablesWrapper>
{count(transformedData) === 0 ? (
<>
<ReqoreVerticalSpacer height={10} />
<ReqoreMessage flat size={size} icon='Search2Line'>
{emptyMessage}
</ReqoreMessage>
</>
) : null}
<ReqorePaginationContainer<IReqoreTableRowData>
items={transformedData}
type={
paging
? {
...pagingOptions,
onPageChange: () => {
if (!pagingOptions.infinite) {
handleScrollToTop();
}
},
}
: undefined
}
>
{(pagedData) => (
<>
<StyledTablesWrapper className='reqore-table-wrapper'>
{renderTable('left', pagedData)}
{renderTable('main', pagedData)}
{renderTable('right', pagedData)}
</StyledTablesWrapper>
{count(pagedData) === 0 ? (
<>
<ReqoreVerticalSpacer height={10} />
<ReqoreMessage flat size={size} icon='Search2Line'>
{emptyMessage}
</ReqoreMessage>
</>
) : null}
</>
)}
</ReqorePaginationContainer>
</ReqorePanel>
);
};
Expand Down
Loading

0 comments on commit a75d2ea

Please sign in to comment.