-
Notifications
You must be signed in to change notification settings - Fork 112
Expand file tree
/
Copy pathCell.tsx
More file actions
98 lines (90 loc) · 3.08 KB
/
Cell.tsx
File metadata and controls
98 lines (90 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import type { Column, CoreCell, CoreHeader } from '@tanstack/react-table';
import { flexRender } from '@tanstack/react-table';
import { clsx } from 'clsx';
import type { CSSProperties, HTMLAttributes } from 'react';
import { useId, useState } from 'react';
import { classNames } from '../AnalyticalTableV2.module.css.js';
import { ColumnPopover } from './ColumnPopover.js';
//todo type
const getCommonPinningStyles = (column: Column<any>): CSSProperties => {
const isPinned = column.getIsPinned();
const isLastLeftPinnedColumn = isPinned === 'left' && column.getIsLastColumn('left');
const isFirstRightPinnedColumn = isPinned === 'right' && column.getIsFirstColumn('right');
return {
boxShadow: isLastLeftPinnedColumn
? '-4px 0 4px -4px gray inset'
: isFirstRightPinnedColumn
? '4px 0 4px -4px gray inset'
: undefined,
insetInlineStart: isPinned === 'left' ? `${column.getStart('left')}px` : undefined,
insetInlineEnd: isPinned === 'right' ? `${column.getAfter('right')}px` : undefined,
position: isPinned ? 'sticky' : 'relative',
width: column.getSize(),
zIndex: isPinned ? 1 : 0
};
};
interface CellProps<TData, TValue> {
style?: CSSProperties;
role: HTMLAttributes<HTMLDivElement>['role'];
/**
* cell object (e.g. `header`, `cell`)
*/
cell: CoreCell<TData, TValue> | CoreHeader<TData, TValue>;
//todo type
renderable: any;
startIndex: number;
isFirstFocusableCell?: boolean;
isSortable?: boolean;
isSelectionCell: boolean;
isSelectableCell?: boolean;
}
//todo: create own component for header cells or handle this via props?
export function Cell<TData, TValue>(props: CellProps<TData, TValue>) {
const {
style = {},
role,
cell,
renderable,
startIndex,
isFirstFocusableCell,
isSortable,
isSelectionCell,
isSelectableCell,
...rest
} = props;
const cellContext = cell.getContext();
const isInteractive = isSortable;
const openerId = `${useId()}-opener`;
const [popoverOpen, setPopoverOpen] = useState(false);
const openPopover = () => {
setPopoverOpen(true);
};
return (
<>
<div
{...rest}
id={openerId}
role={role}
style={{
...getCommonPinningStyles(cell.column),
...style
}}
className={clsx(classNames.cell, isInteractive && classNames.headerInteractive)}
aria-colindex={startIndex + 1}
data-cell={'true'}
tabIndex={isFirstFocusableCell ? 0 : undefined}
//todo: keydown (Enter) keyup(Space) required as well
onClick={isInteractive ? openPopover : undefined}
data-selection-cell={isSelectionCell ? 'true' : undefined}
data-selectable-cell={isSelectableCell ? 'true' : undefined}
>
{flexRender(renderable, cellContext)}
</div>
{/*`id` as opener is simpler than Ref, because we can't add a ref directly as prop (React18)*/}
{popoverOpen && (
<ColumnPopover isSortable={isSortable} openerId={openerId} setOpen={setPopoverOpen} column={cell.column} />
)}
</>
);
}
Cell.displayName = 'AnalyticalTableV2Cell';