mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-14 11:53:49 +00:00
e5b30770ce
* refactor: cuesheet table body * feat: add table navigation
126 lines
4.0 KiB
TypeScript
126 lines
4.0 KiB
TypeScript
import { memo, MutableRefObject, useLayoutEffect, useRef, useState } from 'react';
|
|
import { IoEllipsisHorizontal } from '@react-icons/all-files/io5/IoEllipsisHorizontal';
|
|
import { flexRender, Table } from '@tanstack/react-table';
|
|
import Color from 'color';
|
|
import { OntimeEvent, OntimeRundownEntry } from 'ontime-types';
|
|
|
|
import IconButton from '../../../../common/components/buttons/IconButton';
|
|
import { cx, getAccessibleColour } from '../../../../common/utils/styleUtils';
|
|
import { useCuesheetOptions } from '../../cuesheet.options';
|
|
import { useCuesheetTableMenu } from '../cuesheet-table-menu/useCuesheetTableMenu';
|
|
|
|
import style from '../CuesheetTable.module.scss';
|
|
|
|
interface EventRowProps {
|
|
rowId: string;
|
|
event: OntimeEvent;
|
|
eventIndex: number;
|
|
rowIndex: number;
|
|
isPast?: boolean;
|
|
selectedRef?: MutableRefObject<HTMLTableRowElement | null>;
|
|
skip?: boolean;
|
|
colour?: string;
|
|
rowBgColour?: string;
|
|
table: Table<OntimeRundownEntry>;
|
|
/** hack to force re-rendering of the row when the column sizes change */
|
|
columnSizing: Record<string, number>;
|
|
}
|
|
|
|
export default memo(EventRow, (prevProps, nextProps) => {
|
|
return (
|
|
prevProps.rowId === nextProps.rowId &&
|
|
prevProps.event.revision === nextProps.event.revision &&
|
|
prevProps.eventIndex === nextProps.eventIndex &&
|
|
prevProps.rowIndex === nextProps.rowIndex &&
|
|
prevProps.isPast === nextProps.isPast &&
|
|
prevProps.selectedRef === nextProps.selectedRef &&
|
|
prevProps.rowBgColour === nextProps.rowBgColour &&
|
|
prevProps.table === nextProps.table &&
|
|
prevProps.columnSizing === nextProps.columnSizing
|
|
);
|
|
});
|
|
|
|
function EventRow(props: EventRowProps) {
|
|
const { rowId, event, eventIndex, rowIndex, isPast, selectedRef, rowBgColour, table } = props;
|
|
const { hideIndexColumn, showActionMenu } = useCuesheetOptions();
|
|
const ownRef = useRef<HTMLTableRowElement>(null);
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
|
|
const openMenu = useCuesheetTableMenu((store) => store.openMenu);
|
|
|
|
useLayoutEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry.isIntersecting) {
|
|
setIsVisible(true);
|
|
}
|
|
},
|
|
{
|
|
root: null,
|
|
threshold: 0.01,
|
|
},
|
|
);
|
|
|
|
const handleRefCurrent = ownRef.current;
|
|
if (selectedRef) {
|
|
setIsVisible(true);
|
|
} else if (handleRefCurrent) {
|
|
observer.observe(handleRefCurrent);
|
|
}
|
|
|
|
return () => {
|
|
if (handleRefCurrent) {
|
|
observer.unobserve(handleRefCurrent);
|
|
}
|
|
};
|
|
}, [ownRef, selectedRef]);
|
|
|
|
const { color, backgroundColor } = getAccessibleColour(event.colour);
|
|
const mutedText = Color(color).fade(0.4).hexa();
|
|
|
|
return (
|
|
<tr
|
|
className={cx([style.eventRow, event.skip ?? style.skip])}
|
|
style={{ opacity: `${isPast ? '0.2' : '1'}` }}
|
|
ref={selectedRef ?? ownRef}
|
|
>
|
|
{showActionMenu && (
|
|
<td className={style.actionColumn} tabIndex={-1} role='cell'>
|
|
<IconButton
|
|
aria-label='Options'
|
|
onClick={(e) => {
|
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
const yPos = 8 + rect.y + rect.height / 2;
|
|
openMenu({ x: rect.x, y: yPos }, event.id, rowIndex);
|
|
}}
|
|
>
|
|
<IoEllipsisHorizontal />
|
|
</IconButton>
|
|
</td>
|
|
)}
|
|
{!hideIndexColumn && (
|
|
<td className={style.indexColumn} style={{ backgroundColor, color: mutedText }} tabIndex={-1} role='cell'>
|
|
{eventIndex}
|
|
</td>
|
|
)}
|
|
{isVisible
|
|
? table
|
|
.getRow(rowId)
|
|
?.getVisibleCells()
|
|
.map((cell) => {
|
|
return (
|
|
<td
|
|
key={cell.id}
|
|
style={{ width: cell.column.getSize(), backgroundColor: rowBgColour }}
|
|
tabIndex={-1}
|
|
role='cell'
|
|
>
|
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
</td>
|
|
);
|
|
})
|
|
: null}
|
|
</tr>
|
|
);
|
|
}
|