add collapsible table
This commit is contained in:
parent
e93850484b
commit
ef5b5013c5
91
src/components/CollapsibleTable.tsx
Normal file
91
src/components/CollapsibleTable.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import { Key, useState } from 'react';
|
||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
import { CaretIcon } from '@/icons';
|
||||
|
||||
import { Button } from './Button';
|
||||
|
||||
import {
|
||||
Table,
|
||||
type ElementProps as TableElementProps,
|
||||
type StyleProps as TableStyleProps,
|
||||
} from './Table';
|
||||
|
||||
type CollapsibleTableAdditionalProps = {
|
||||
initialNumRowsToShow: number;
|
||||
};
|
||||
|
||||
type CollapsibleTableProps<
|
||||
TableRowData extends object,
|
||||
TableRowKey extends Key
|
||||
> = TableElementProps<TableRowData, TableRowKey> &
|
||||
TableStyleProps &
|
||||
CollapsibleTableAdditionalProps;
|
||||
|
||||
export const CollapsibleTable = <TableRowData extends object, TableRowKey extends Key>({
|
||||
data = [],
|
||||
initialNumRowsToShow,
|
||||
|
||||
className,
|
||||
...tableProps
|
||||
}: CollapsibleTableProps<TableRowData, TableRowKey>) => {
|
||||
const [numRowsToShow, setNumRowsToShow] = useState(initialNumRowsToShow);
|
||||
const stringGetter = useStringGetter();
|
||||
const showViewMoreButton = numRowsToShow !== undefined && numRowsToShow < data.length;
|
||||
|
||||
return (
|
||||
<Styled.Container>
|
||||
<Styled.Table
|
||||
{...tableProps}
|
||||
data={data}
|
||||
numRowsToShow={numRowsToShow}
|
||||
showViewMoreButton={showViewMoreButton}
|
||||
className={className}
|
||||
/>
|
||||
{showViewMoreButton && (
|
||||
<Styled.ViewMoreButton
|
||||
onClick={() => setNumRowsToShow(data.length)}
|
||||
slotRight={<CaretIcon />}
|
||||
>
|
||||
{stringGetter({ key: STRING_KEYS.VIEW_MORE })}
|
||||
</Styled.ViewMoreButton>
|
||||
)}
|
||||
</Styled.Container>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Container = styled.div`
|
||||
display: grid;
|
||||
grid-template-areas: 'table' 'viewmore';
|
||||
grid-template-rows: auto 1fr;
|
||||
`;
|
||||
|
||||
Styled.Table = styled(Table)<{ showViewMoreButton?: boolean }>`
|
||||
grid-area: table;
|
||||
|
||||
${({ showViewMoreButton }) =>
|
||||
showViewMoreButton &&
|
||||
css`
|
||||
table tbody tr:last-of-type {
|
||||
box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color);
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
Styled.ViewMoreButton = styled(Button)`
|
||||
--button-backgroundColor: var(--color-layer-2);
|
||||
--button-textColor: var(--color-text-1);
|
||||
|
||||
width: 100%;
|
||||
grid-area: viewmore;
|
||||
|
||||
svg {
|
||||
width: 0.675rem;
|
||||
margin-left: 0.5ch;
|
||||
}
|
||||
`;
|
||||
@ -11,6 +11,5 @@ export const DetachedScrollableSection = styled.section`
|
||||
|
||||
export const AttachedExpandingSection = styled.section`
|
||||
${layoutMixins.contentSectionAttached}
|
||||
${layoutMixins.expandingColumnWithHeader}
|
||||
gap: var(--border-width);
|
||||
`;
|
||||
|
||||
@ -36,8 +36,6 @@ import { useAsyncList } from 'react-stately';
|
||||
import { useBreakpoints } from '@/hooks';
|
||||
import { MediaQueryKeys } from '@/hooks/useBreakpoints';
|
||||
|
||||
import { Checkbox } from '@/components/Checkbox';
|
||||
|
||||
import { breakpoints } from '@/styles';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
@ -80,7 +78,7 @@ export type ColumnDef<TableRowData extends object> = {
|
||||
width?: ColumnSize;
|
||||
};
|
||||
|
||||
type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
|
||||
export type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
|
||||
label?: string;
|
||||
columns: ColumnDef<TableRowData>[];
|
||||
data: TableRowData[];
|
||||
@ -92,11 +90,12 @@ type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey ext
|
||||
selectionBehavior?: 'replace' | 'toggle';
|
||||
onRowAction?: (key: TableRowKey, row: TableRowData) => void;
|
||||
slotEmpty?: React.ReactNode;
|
||||
numRowsToShow?: number;
|
||||
// collection: TableCollection<string>;
|
||||
// children: React.ReactNode;
|
||||
};
|
||||
|
||||
type StyleProps = {
|
||||
export type StyleProps = {
|
||||
hideHeader?: boolean;
|
||||
withGradientCardRows?: boolean;
|
||||
withFocusStickyRows?: boolean;
|
||||
@ -121,6 +120,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
||||
selectionMode = 'single',
|
||||
selectionBehavior = 'toggle',
|
||||
slotEmpty,
|
||||
numRowsToShow = data.length,
|
||||
// shouldRowRender,
|
||||
|
||||
// collection,
|
||||
@ -233,7 +233,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
||||
)}
|
||||
</TableHeader>
|
||||
|
||||
<TableBody items={list.items}>
|
||||
<TableBody items={list.items.slice(0, numRowsToShow)}>
|
||||
{(item) => (
|
||||
<Row key={getRowKey(item)}>
|
||||
{(columnKey) => (
|
||||
@ -337,6 +337,7 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
|
||||
<TableBodyRowGroup
|
||||
withGradientCardRows={props.withGradientCardRows}
|
||||
withInnerBorders={props.withInnerBorders}
|
||||
withOuterBorder={props.withOuterBorder}
|
||||
>
|
||||
{/* {Array.from(collection.getChildren!(collection.body.key), (row) => */}
|
||||
{[...collection.body.childNodes].map((row) =>
|
||||
@ -415,6 +416,7 @@ const TableBodyRowGroup = ({
|
||||
children,
|
||||
withGradientCardRows,
|
||||
withInnerBorders,
|
||||
withOuterBorder,
|
||||
}: { children: React.ReactNode } & StyleProps) => {
|
||||
const { rowGroupProps } = useTableRowGroup();
|
||||
|
||||
@ -423,6 +425,7 @@ const TableBodyRowGroup = ({
|
||||
{...rowGroupProps}
|
||||
withGradientCardRows={withGradientCardRows}
|
||||
withInnerBorders={withInnerBorders}
|
||||
withOuterBorder={withOuterBorder}
|
||||
>
|
||||
{children}
|
||||
</Styled.Tbody>
|
||||
@ -660,7 +663,7 @@ Styled.Empty = styled.div<{ withOuterBorder: boolean }>`
|
||||
|
||||
justify-items: center;
|
||||
align-content: center;
|
||||
padding: 2rem;
|
||||
padding: 4rem;
|
||||
gap: 0.75em;
|
||||
|
||||
color: var(--color-text-0);
|
||||
@ -868,6 +871,18 @@ Styled.Tbody = styled.tbody<StyleProps>`
|
||||
--stickyArea2-paddingLeft: var(--border-width);
|
||||
--stickyArea2-paddingRight: var(--border-width);
|
||||
|
||||
tr:first-of-type {
|
||||
box-shadow: 0 calc(var(--border-width)) 0 0 var(--border-color);
|
||||
}
|
||||
`}
|
||||
|
||||
${({ withOuterBorder }) =>
|
||||
withOuterBorder &&
|
||||
css`
|
||||
tr:last-of-type:not(:only-of-type) {
|
||||
box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color);
|
||||
}
|
||||
|
||||
tr:first-of-type {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@ -36,8 +36,6 @@ import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
import { getHydratedTradingData } from '@/lib/orders';
|
||||
import { tableMixins } from '@/styles/tableMixins';
|
||||
import { breakpoints } from '@/styles';
|
||||
|
||||
const MOBILE_FILLS_PER_PAGE = 50;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user