fix(cuesheet): infinite render loop on resizing columns

This commit is contained in:
Carlos Valente
2025-09-15 21:36:45 +02:00
committed by Carlos Valente
parent 304832ecde
commit 7bbdab7dd9
5 changed files with 121 additions and 44 deletions
@@ -7,7 +7,7 @@ import { getAccessibleColour } from '../../../../common/utils/styleUtils';
import { AppMode } from '../../../../ontimeConfig';
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
import { SortableCell } from './SortableCell';
import { Draggable, SortableCell, TableCell } from './SortableCell';
import style from '../CuesheetTable.module.scss';
@@ -16,8 +16,9 @@ interface CuesheetHeaderProps {
cuesheetMode: AppMode;
}
export default function CuesheetHeader({ headerGroup, cuesheetMode }: CuesheetHeaderProps) {
export function SortableCuesheetHeader({ headerGroup, cuesheetMode }: CuesheetHeaderProps) {
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
return (
<tr key={headerGroup.id}>
{cuesheetMode === AppMode.Edit && <th className={style.actionColumn} tabIndex={-1} />}
@@ -43,8 +44,10 @@ export default function CuesheetHeader({ headerGroup, cuesheetMode }: CuesheetHe
return (
<SortableCell
key={header.column.columnDef.id}
header={header}
columnId={header.column.id}
colSpan={header.colSpan}
injectedStyles={{ width: `calc(var(--header-${header?.id}-size) * 1px)`, ...customStyles }}
draggable={<Draggable header={header} />}
>
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
</SortableCell>
@@ -54,3 +57,43 @@ export default function CuesheetHeader({ headerGroup, cuesheetMode }: CuesheetHe
</tr>
);
}
export function CuesheetHeader({ headerGroup, cuesheetMode }: CuesheetHeaderProps) {
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
return (
<tr key={headerGroup.id}>
{cuesheetMode === AppMode.Edit && <th className={style.actionColumn} tabIndex={-1} />}
{!hideIndexColumn && (
<th className={style.indexColumn} tabIndex={-1}>
#
</th>
)}
{headerGroup.headers.map((header) => {
const customBackground = header.column.columnDef.meta?.colour;
const canWrite = header.column.columnDef.meta?.canWrite;
const customStyles: CSSProperties = {
opacity: canWrite ? 1 : 0.6,
};
if (customBackground) {
const customColour = getAccessibleColour(customBackground);
customStyles.backgroundColor = customColour.backgroundColor;
customStyles.color = customColour.color;
}
return (
<TableCell
key={header.column.columnDef.id}
columnId={header.column.id}
colSpan={header.colSpan}
injectedStyles={{ width: `calc(var(--header-${header?.id}-size) * 1px)`, ...customStyles }}
draggable={<Draggable header={header} />}
>
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
</TableCell>
);
})}
</tr>
);
}
@@ -8,16 +8,16 @@ import type { ExtendedEntry } from '../../../../common/utils/rundownMetadata';
import style from '../CuesheetTable.module.scss';
interface SortableCellProps {
header: Header<ExtendedEntry, unknown>;
columnId: string;
colSpan: number;
injectedStyles: CSSProperties;
children: ReactNode;
draggable: ReactNode;
}
export function SortableCell({ header, injectedStyles, children }: SortableCellProps) {
const { column, colSpan } = header;
export function SortableCell({ columnId, colSpan, injectedStyles, children, draggable }: SortableCellProps) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: column.id,
id: columnId,
});
// build drag styles
@@ -34,12 +34,31 @@ export function SortableCell({ header, injectedStyles, children }: SortableCellP
<div {...attributes} {...listeners}>
{children}
</div>
<div
onDoubleClick={() => header.column.resetSize()}
onMouseDown={header.getResizeHandler()}
onTouchStart={header.getResizeHandler()}
className={style.resizer}
/>
{draggable}
</th>
);
}
export function TableCell({ colSpan, injectedStyles, children, draggable }: SortableCellProps) {
return (
<th style={injectedStyles} colSpan={colSpan} tabIndex={-1}>
<div>{children}</div>
{draggable}
</th>
);
}
interface DraggableProps {
header: Header<ExtendedEntry, unknown>;
}
export function Draggable({ header }: DraggableProps) {
return (
<div
onDoubleClick={() => header.column.resetSize()}
onMouseDown={header.getResizeHandler()}
onTouchStart={header.getResizeHandler()}
className={style.resizer}
/>
);
}