-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTable.tsx
116 lines (105 loc) · 3.36 KB
/
Table.tsx
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import classNames from "classnames";
import { useContext, useEffect, useRef, useState } from "react";
// Store
import { PlayerContext } from "@/store/player";
// Styles
import s from "./Table.module.scss";
interface TableItem {
[field: string]: string | number | DetailedTableItem;
}
interface DetailedTableItem {
html: React.ReactNode;
whileHover?: React.ReactNode;
pass?: any;
}
interface TableProps extends React.HTMLAttributes<HTMLElement> {
data: TableItem[];
spacing: string[];
headless?: boolean;
headClassName?: string;
headerClassName?: string;
rowClassName?: string;
dataClassName?: string;
}
export default function Table({
data,
spacing,
headless,
className,
headClassName,
headerClassName,
rowClassName,
dataClassName,
}: TableProps) {
const context = useContext(PlayerContext);
const tableHeadRef = useRef<HTMLElement>(null);
const [isHovering, setHovering] = useState(-1);
const [headSticked, setHeadSticked] = useState(false);
useEffect(() => {
const listener = () => {
const rect = tableHeadRef.current?.getBoundingClientRect() as DOMRect;
if (rect && rect.top <= 56) {
setHeadSticked(true);
} else setHeadSticked(false);
};
document.addEventListener("scroll", listener, { capture: true });
return () => {
document.removeEventListener("scroll", listener, { capture: true });
};
}, []);
return (
<div
role="grid"
aria-rowcount={data.length}
aria-colcount={Object.keys(data[0]).length}
className={classNames(s.table, className)}
style={{ ["--grid-columns" as string]: spacing.join(" ") }}
>
{!headless && (
<header ref={tableHeadRef} className={classNames(s.tableHead, headSticked && s.sticked, headClassName)}>
<div role="row" aria-rowindex={1} className={classNames(s.tableRow, !headless && s.spaced)}>
{Object.keys(data[0]).map((field) => (
<div key={field} role="columnheader" className={classNames(s.tableHeader, headerClassName)}>
{field}
</div>
))}
</div>
</header>
)}
<div role="presentation" className={s.tableBody}>
{data.map((row, rowIdx) => (
<div
key={rowIdx}
role="row"
aria-rowindex={rowIdx + 2}
onMouseEnter={() => setHovering(rowIdx)}
onMouseLeave={() => setHovering(-1)}
>
<div
className={classNames(s.tableRow, !headless && s.spaced, rowClassName)}
onDoubleClick={() => {
const data = row.Track as DetailedTableItem;
context.setPlaying(true);
context.setPlayback((val) => ({
...val,
...data.pass,
elapsed: 0,
}));
}}
>
{Object.values(row).map((prop, propIdx) => (
<div key={propIdx} role="gridcell" className={classNames(s.tableData, dataClassName)}>
{typeof prop === "object"
? prop.whileHover && isHovering === rowIdx
? (prop as DetailedTableItem).whileHover
: (prop as DetailedTableItem).html
: prop}
</div>
))}
</div>
</div>
))}
</div>
</div>
);
}