mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
use derived column props, add table header styles
This commit is contained in:
@@ -37,6 +37,10 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-table-pinned-rows-grid-container.with-header {
|
||||||
|
background-color: var(--theme-colors-surface);
|
||||||
|
}
|
||||||
|
|
||||||
.item-table-pinned-columns-grid-container {
|
.item-table-pinned-columns-grid-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
@@ -50,6 +54,10 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-table-pinned-intersection-grid-container.with-header {
|
||||||
|
background-color: var(--theme-colors-surface);
|
||||||
|
}
|
||||||
|
|
||||||
.item-table-pinned-columns-container {
|
.item-table-pinned-columns-container {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|||||||
@@ -21,26 +21,27 @@ import styles from './item-table-list.module.css';
|
|||||||
import { ExpandedListItem } from '/@/renderer/components/item-list/expanded-list-item';
|
import { ExpandedListItem } from '/@/renderer/components/item-list/expanded-list-item';
|
||||||
import { useItemListState } from '/@/renderer/components/item-list/helpers/item-list-state';
|
import { useItemListState } from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
|
import { TableColumn } from '/@/shared/types/types';
|
||||||
|
|
||||||
export interface CellProps {
|
export interface CellProps {
|
||||||
columns: ItemTableListColumn[];
|
columns: ItemTableListColumnConfig[];
|
||||||
data: unknown[];
|
data: unknown[];
|
||||||
|
enableHeader?: boolean;
|
||||||
handleExpand: (e: MouseEvent<HTMLDivElement>, item: unknown, itemType: LibraryItem) => void;
|
handleExpand: (e: MouseEvent<HTMLDivElement>, item: unknown, itemType: LibraryItem) => void;
|
||||||
itemType: LibraryItem;
|
itemType: LibraryItem;
|
||||||
size?: 'compact' | 'default';
|
size?: 'compact' | 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ItemTableListColumn {
|
export interface ItemTableListColumnConfig {
|
||||||
id: string;
|
align: 'center' | 'end' | 'start';
|
||||||
label: string;
|
id: TableColumn;
|
||||||
|
pinned: 'left' | 'right' | null;
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemTableListProps {
|
interface ItemTableListProps {
|
||||||
CellComponent: JSXElementConstructor<CellComponentProps<CellProps>>;
|
CellComponent: JSXElementConstructor<CellComponentProps<CellProps>>;
|
||||||
columnCount: number;
|
columns: ItemTableListColumnConfig[];
|
||||||
columns: ItemTableListColumn[];
|
|
||||||
columnWidth: ((index: number, cellProps: CellProps) => number) | number;
|
|
||||||
data: unknown[];
|
data: unknown[];
|
||||||
enableExpansion?: boolean;
|
enableExpansion?: boolean;
|
||||||
enableHeader?: boolean;
|
enableHeader?: boolean;
|
||||||
@@ -64,8 +65,6 @@ interface ItemTableListProps {
|
|||||||
onScroll?: (event: UIEvent<HTMLDivElement>) => void;
|
onScroll?: (event: UIEvent<HTMLDivElement>) => void;
|
||||||
onScrollEnd?: () => void;
|
onScrollEnd?: () => void;
|
||||||
onStartReached?: (index: number) => void;
|
onStartReached?: (index: number) => void;
|
||||||
pinnedLeftColumnCount: number;
|
|
||||||
pinnedRightColumnCount?: number;
|
|
||||||
ref?: Ref<GridImperativeAPI>;
|
ref?: Ref<GridImperativeAPI>;
|
||||||
rowHeight: ((index: number, cellProps: CellProps) => number) | number;
|
rowHeight: ((index: number, cellProps: CellProps) => number) | number;
|
||||||
size?: 'compact' | 'default';
|
size?: 'compact' | 'default';
|
||||||
@@ -88,9 +87,7 @@ const expandedAnimationVariants: Variants = {
|
|||||||
|
|
||||||
export const ItemTableList = ({
|
export const ItemTableList = ({
|
||||||
CellComponent,
|
CellComponent,
|
||||||
columnCount,
|
|
||||||
columns,
|
columns,
|
||||||
columnWidth,
|
|
||||||
data,
|
data,
|
||||||
enableHeader = true,
|
enableHeader = true,
|
||||||
headerHeight = 40,
|
headerHeight = 40,
|
||||||
@@ -105,17 +102,20 @@ export const ItemTableList = ({
|
|||||||
onScroll,
|
onScroll,
|
||||||
onScrollEnd,
|
onScrollEnd,
|
||||||
onStartReached,
|
onStartReached,
|
||||||
pinnedLeftColumnCount,
|
|
||||||
pinnedRightColumnCount = 0,
|
|
||||||
ref,
|
ref,
|
||||||
rowHeight,
|
rowHeight,
|
||||||
size = 'default',
|
size = 'default',
|
||||||
totalItemCount,
|
totalItemCount,
|
||||||
}: ItemTableListProps) => {
|
}: ItemTableListProps) => {
|
||||||
|
const columnCount = columns.length;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const columnWidth = (index: number, _cellProps: CellProps) => columns[index].width;
|
||||||
|
const pinnedLeftColumnCount = columns.filter((col) => col.pinned === 'left').length;
|
||||||
|
const pinnedRightColumnCount = columns.filter((col) => col.pinned === 'right').length;
|
||||||
|
|
||||||
const pinnedRowCount = enableHeader ? 1 : 0;
|
const pinnedRowCount = enableHeader ? 1 : 0;
|
||||||
const totalRowCount = totalItemCount - (pinnedRowCount ?? 0);
|
const totalRowCount = totalItemCount - pinnedRowCount;
|
||||||
const totalColumnCount =
|
const totalColumnCount = columnCount - pinnedLeftColumnCount - pinnedRightColumnCount;
|
||||||
columnCount - (pinnedLeftColumnCount ?? 0) - (pinnedRightColumnCount ?? 0);
|
|
||||||
const pinnedRowRef = useRef<HTMLDivElement>(null);
|
const pinnedRowRef = useRef<HTMLDivElement>(null);
|
||||||
const rowRef = useRef<HTMLDivElement>(null);
|
const rowRef = useRef<HTMLDivElement>(null);
|
||||||
const pinnedLeftColumnRef = useRef<HTMLDivElement>(null);
|
const pinnedLeftColumnRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -166,7 +166,6 @@ export const ItemTableList = ({
|
|||||||
const pinnedLeft = pinnedLeftColumnRef.current?.childNodes[0] as HTMLDivElement;
|
const pinnedLeft = pinnedLeftColumnRef.current?.childNodes[0] as HTMLDivElement;
|
||||||
const pinnedRight = pinnedRightColumnRef.current?.childNodes[0] as HTMLDivElement;
|
const pinnedRight = pinnedRightColumnRef.current?.childNodes[0] as HTMLDivElement;
|
||||||
|
|
||||||
// At minimum, we need the main row element
|
|
||||||
if (row) {
|
if (row) {
|
||||||
// Ensure all containers have the same height
|
// Ensure all containers have the same height
|
||||||
const syncHeights = () => {
|
const syncHeights = () => {
|
||||||
@@ -465,10 +464,10 @@ export const ItemTableList = ({
|
|||||||
? ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) => {
|
? ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) => {
|
||||||
return onCellsRendered!(
|
return onCellsRendered!(
|
||||||
{
|
{
|
||||||
columnStartIndex: columnStartIndex + (pinnedLeftColumnCount ?? 0),
|
columnStartIndex: columnStartIndex + pinnedLeftColumnCount,
|
||||||
columnStopIndex: columnStopIndex + (pinnedLeftColumnCount ?? 0),
|
columnStopIndex: columnStopIndex + pinnedLeftColumnCount,
|
||||||
rowStartIndex: rowStartIndex + (pinnedRowCount ?? 0),
|
rowStartIndex: rowStartIndex + pinnedRowCount,
|
||||||
rowStopIndex: rowStopIndex + (pinnedRowCount ?? 0),
|
rowStopIndex: rowStopIndex + pinnedRowCount,
|
||||||
},
|
},
|
||||||
cells,
|
cells,
|
||||||
);
|
);
|
||||||
@@ -483,7 +482,7 @@ export const ItemTableList = ({
|
|||||||
return (
|
return (
|
||||||
<CellComponent
|
<CellComponent
|
||||||
{...cellProps}
|
{...cellProps}
|
||||||
columnIndex={cellProps.columnIndex + (pinnedLeftColumnCount ?? 0)}
|
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -492,12 +491,7 @@ export const ItemTableList = ({
|
|||||||
|
|
||||||
const PinnedColumnCell = useCallback(
|
const PinnedColumnCell = useCallback(
|
||||||
(cellProps: CellComponentProps & CellProps) => {
|
(cellProps: CellComponentProps & CellProps) => {
|
||||||
return (
|
return <CellComponent {...cellProps} rowIndex={cellProps.rowIndex + pinnedRowCount} />;
|
||||||
<CellComponent
|
|
||||||
{...cellProps}
|
|
||||||
rowIndex={cellProps.rowIndex + (pinnedRowCount ?? 0)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
[pinnedRowCount, CellComponent],
|
[pinnedRowCount, CellComponent],
|
||||||
);
|
);
|
||||||
@@ -507,10 +501,8 @@ export const ItemTableList = ({
|
|||||||
return (
|
return (
|
||||||
<CellComponent
|
<CellComponent
|
||||||
{...cellProps}
|
{...cellProps}
|
||||||
columnIndex={
|
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount + totalColumnCount}
|
||||||
cellProps.columnIndex + (pinnedLeftColumnCount ?? 0) + totalColumnCount
|
rowIndex={cellProps.rowIndex + pinnedRowCount}
|
||||||
}
|
|
||||||
rowIndex={cellProps.rowIndex + (pinnedRowCount ?? 0)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -522,9 +514,7 @@ export const ItemTableList = ({
|
|||||||
return (
|
return (
|
||||||
<CellComponent
|
<CellComponent
|
||||||
{...cellProps}
|
{...cellProps}
|
||||||
columnIndex={
|
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount + totalColumnCount}
|
||||||
cellProps.columnIndex + (pinnedLeftColumnCount ?? 0) + totalColumnCount
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -536,11 +526,11 @@ export const ItemTableList = ({
|
|||||||
return (
|
return (
|
||||||
<CellComponent
|
<CellComponent
|
||||||
{...cellProps}
|
{...cellProps}
|
||||||
columnIndex={cellProps.columnIndex + (pinnedLeftColumnCount ?? 0)}
|
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount}
|
||||||
// onClick={(e) => {
|
// onClick={(e) => {
|
||||||
// onItemClick?.(cellProps.data[cellProps.rowIndex], cellProps.rowIndex, e);
|
// onItemClick?.(cellProps.data[cellProps.rowIndex], cellProps.rowIndex, e);
|
||||||
// }}
|
// }}
|
||||||
rowIndex={cellProps.rowIndex + (pinnedRowCount ?? 0)}
|
rowIndex={cellProps.rowIndex + pinnedRowCount}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -550,6 +540,7 @@ export const ItemTableList = ({
|
|||||||
const cellProps = {
|
const cellProps = {
|
||||||
columns,
|
columns,
|
||||||
data,
|
data,
|
||||||
|
enableHeader,
|
||||||
handleExpand,
|
handleExpand,
|
||||||
itemType,
|
itemType,
|
||||||
size,
|
size,
|
||||||
@@ -572,25 +563,20 @@ export const ItemTableList = ({
|
|||||||
<div
|
<div
|
||||||
className={styles.itemTablePinnedColumnsGridContainer}
|
className={styles.itemTablePinnedColumnsGridContainer}
|
||||||
style={{
|
style={{
|
||||||
minWidth: `${Array.from(
|
minWidth: `${Array.from({ length: pinnedLeftColumnCount }, () => 0).reduce(
|
||||||
{ length: pinnedLeftColumnCount ?? 0 },
|
(a, _, i) => a + columnWidth(i, cellProps),
|
||||||
() => 0,
|
|
||||||
).reduce(
|
|
||||||
(a, _, i) =>
|
|
||||||
a +
|
|
||||||
(typeof columnWidth === 'number'
|
|
||||||
? columnWidth
|
|
||||||
: columnWidth(i, cellProps)),
|
|
||||||
0,
|
0,
|
||||||
)}px`,
|
)}px`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!!(pinnedLeftColumnCount || pinnedRowCount) && (
|
{!!(pinnedLeftColumnCount || pinnedRowCount) && (
|
||||||
<div
|
<div
|
||||||
className={styles.itemTablePinnedIntersectionGridContainer}
|
className={clsx(styles.itemTablePinnedIntersectionGridContainer, {
|
||||||
|
[styles.withHeader]: enableHeader,
|
||||||
|
})}
|
||||||
style={{
|
style={{
|
||||||
minHeight: `${Array.from(
|
minHeight: `${Array.from(
|
||||||
{ length: pinnedRowCount ?? 0 },
|
{ length: pinnedRowCount },
|
||||||
() => 0,
|
() => 0,
|
||||||
).reduce((a, _, i) => a + getRowHeight(i, cellProps), 0)}px`,
|
).reduce((a, _, i) => a + getRowHeight(i, cellProps), 0)}px`,
|
||||||
}}
|
}}
|
||||||
@@ -620,7 +606,7 @@ export const ItemTableList = ({
|
|||||||
columnWidth={columnWidth}
|
columnWidth={columnWidth}
|
||||||
rowCount={totalRowCount}
|
rowCount={totalRowCount}
|
||||||
rowHeight={(index, cellProps) => {
|
rowHeight={(index, cellProps) => {
|
||||||
return getRowHeight(index + (pinnedRowCount ?? 0), cellProps);
|
return getRowHeight(index + pinnedRowCount, cellProps);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -629,13 +615,15 @@ export const ItemTableList = ({
|
|||||||
<div className={styles.itemTablePinnedRowsContainer}>
|
<div className={styles.itemTablePinnedRowsContainer}>
|
||||||
{!!pinnedRowCount && (
|
{!!pinnedRowCount && (
|
||||||
<div
|
<div
|
||||||
className={styles.itemTablePinnedRowsGridContainer}
|
className={clsx(styles.itemTablePinnedRowsGridContainer, {
|
||||||
|
[styles.withHeader]: enableHeader,
|
||||||
|
})}
|
||||||
ref={pinnedRowRef}
|
ref={pinnedRowRef}
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
'--header-height': `${headerHeight}px`,
|
'--header-height': `${headerHeight}px`,
|
||||||
minHeight: `${Array.from(
|
minHeight: `${Array.from(
|
||||||
{ length: pinnedRowCount ?? 0 },
|
{ length: pinnedRowCount },
|
||||||
() => 0,
|
() => 0,
|
||||||
).reduce((a, _, i) => a + getRowHeight(i, cellProps), 0)}px`,
|
).reduce((a, _, i) => a + getRowHeight(i, cellProps), 0)}px`,
|
||||||
} as React.CSSProperties
|
} as React.CSSProperties
|
||||||
@@ -647,16 +635,9 @@ export const ItemTableList = ({
|
|||||||
className={styles.noScrollbar}
|
className={styles.noScrollbar}
|
||||||
columnCount={totalColumnCount}
|
columnCount={totalColumnCount}
|
||||||
columnWidth={(index, cellProps) => {
|
columnWidth={(index, cellProps) => {
|
||||||
return typeof columnWidth === 'number'
|
return columnWidth(index + pinnedLeftColumnCount, cellProps);
|
||||||
? columnWidth
|
|
||||||
: columnWidth(
|
|
||||||
index + (pinnedLeftColumnCount ?? 0),
|
|
||||||
cellProps,
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
rowCount={
|
rowCount={Array.from({ length: pinnedRowCount }, () => 0).length}
|
||||||
Array.from({ length: pinnedRowCount ?? 0 }, () => 0).length
|
|
||||||
}
|
|
||||||
rowHeight={getRowHeight}
|
rowHeight={getRowHeight}
|
||||||
/>
|
/>
|
||||||
{enableHeader && <div className={styles.itemTablePinnedHeaderShadow} />}
|
{enableHeader && <div className={styles.itemTablePinnedHeaderShadow} />}
|
||||||
@@ -669,14 +650,12 @@ export const ItemTableList = ({
|
|||||||
className={styles.height100}
|
className={styles.height100}
|
||||||
columnCount={totalColumnCount}
|
columnCount={totalColumnCount}
|
||||||
columnWidth={(index, cellProps) => {
|
columnWidth={(index, cellProps) => {
|
||||||
return typeof columnWidth === 'number'
|
return columnWidth(index + pinnedLeftColumnCount, cellProps);
|
||||||
? columnWidth
|
|
||||||
: columnWidth(index + (pinnedLeftColumnCount ?? 0), cellProps);
|
|
||||||
}}
|
}}
|
||||||
onCellsRendered={handleOnCellsRendered}
|
onCellsRendered={handleOnCellsRendered}
|
||||||
rowCount={totalRowCount}
|
rowCount={totalRowCount}
|
||||||
rowHeight={(index, cellProps) => {
|
rowHeight={(index, cellProps) => {
|
||||||
return getRowHeight(index + (pinnedRowCount ?? 0), cellProps);
|
return getRowHeight(index + pinnedRowCount, cellProps);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{pinnedLeftColumnCount > 0 && showLeftShadow && (
|
{pinnedLeftColumnCount > 0 && showLeftShadow && (
|
||||||
@@ -692,27 +671,27 @@ export const ItemTableList = ({
|
|||||||
className={styles.itemTablePinnedColumnsGridContainer}
|
className={styles.itemTablePinnedColumnsGridContainer}
|
||||||
style={{
|
style={{
|
||||||
minWidth: `${Array.from(
|
minWidth: `${Array.from(
|
||||||
{ length: pinnedRightColumnCount ?? 0 },
|
{ length: pinnedRightColumnCount },
|
||||||
() => 0,
|
() => 0,
|
||||||
).reduce(
|
).reduce(
|
||||||
(a, _, i) =>
|
(a, _, i) =>
|
||||||
a +
|
a +
|
||||||
(typeof columnWidth === 'number'
|
columnWidth(
|
||||||
? columnWidth
|
|
||||||
: columnWidth(
|
|
||||||
i + pinnedLeftColumnCount + totalColumnCount,
|
i + pinnedLeftColumnCount + totalColumnCount,
|
||||||
cellProps,
|
cellProps,
|
||||||
)),
|
),
|
||||||
0,
|
0,
|
||||||
)}px`,
|
)}px`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!!(pinnedRightColumnCount || pinnedRowCount) && (
|
{!!(pinnedRightColumnCount || pinnedRowCount) && (
|
||||||
<div
|
<div
|
||||||
className={styles.itemTablePinnedIntersectionGridContainer}
|
className={clsx(styles.itemTablePinnedIntersectionGridContainer, {
|
||||||
|
[styles.withHeader]: enableHeader,
|
||||||
|
})}
|
||||||
style={{
|
style={{
|
||||||
minHeight: `${Array.from(
|
minHeight: `${Array.from(
|
||||||
{ length: pinnedRowCount ?? 0 },
|
{ length: pinnedRowCount },
|
||||||
() => 0,
|
() => 0,
|
||||||
).reduce((a, _, i) => a + getRowHeight(i, cellProps), 0)}px`,
|
).reduce((a, _, i) => a + getRowHeight(i, cellProps), 0)}px`,
|
||||||
}}
|
}}
|
||||||
@@ -723,9 +702,7 @@ export const ItemTableList = ({
|
|||||||
className={styles.noScrollbar}
|
className={styles.noScrollbar}
|
||||||
columnCount={pinnedRightColumnCount}
|
columnCount={pinnedRightColumnCount}
|
||||||
columnWidth={(index, cellProps) => {
|
columnWidth={(index, cellProps) => {
|
||||||
return typeof columnWidth === 'number'
|
return columnWidth(
|
||||||
? columnWidth
|
|
||||||
: columnWidth(
|
|
||||||
index + pinnedLeftColumnCount + totalColumnCount,
|
index + pinnedLeftColumnCount + totalColumnCount,
|
||||||
cellProps,
|
cellProps,
|
||||||
);
|
);
|
||||||
@@ -748,16 +725,14 @@ export const ItemTableList = ({
|
|||||||
className={clsx(styles.noScrollbar, styles.height100)}
|
className={clsx(styles.noScrollbar, styles.height100)}
|
||||||
columnCount={pinnedRightColumnCount}
|
columnCount={pinnedRightColumnCount}
|
||||||
columnWidth={(index, cellProps) => {
|
columnWidth={(index, cellProps) => {
|
||||||
return typeof columnWidth === 'number'
|
return columnWidth(
|
||||||
? columnWidth
|
|
||||||
: columnWidth(
|
|
||||||
index + pinnedLeftColumnCount + totalColumnCount,
|
index + pinnedLeftColumnCount + totalColumnCount,
|
||||||
cellProps,
|
cellProps,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
rowCount={totalRowCount}
|
rowCount={totalRowCount}
|
||||||
rowHeight={(index, cellProps) => {
|
rowHeight={(index, cellProps) => {
|
||||||
return getRowHeight(index + (pinnedRowCount ?? 0), cellProps);
|
return getRowHeight(index + pinnedRowCount, cellProps);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user