fix(base): sync header/body horizontal scroll on header focus; expand row via Space, drop expander from tab order

This commit is contained in:
Philipinho
2026-06-15 04:08:52 +01:00
parent cc951ae883
commit 8fc538386d
4 changed files with 31 additions and 5 deletions
@@ -181,6 +181,7 @@ export const GridCell = memo(function GridCell({
<Tooltip label={t("Expand")} position="bottom" openDelay={400}>
<button
type="button"
tabIndex={-1}
className={classes.rowExpandButton}
onClick={() => onExpandRow(rowId)}
onDoubleClick={(e) => e.stopPropagation()}
@@ -37,6 +37,7 @@ import { AddRowButton } from "./add-row-button";
import { GridGhostRows } from "./grid-ghost-rows";
import { SelectionActionBar } from "./selection-action-bar";
import { useBaseEditable } from "@/ee/base/context/base-editable";
import { useRowExpand } from "@/ee/base/context/row-expand";
import { GridRowOrderProvider } from "@/ee/base/context/grid-row-order";
import classes from "@/ee/base/styles/grid.module.css";
@@ -120,6 +121,7 @@ export function GridContainer({
rowIdsRef.current = rowIds;
const getOrderedRowIds = useCallback(() => rowIdsRef.current, []);
const editable = useBaseEditable();
const onExpandRow = useRowExpand();
const [editingCell, setEditingCell] = useAtom(editingCellAtomFamily(pageId)) as unknown as [EditingCell, (val: EditingCell) => void];
const editingCellRef = useRef(editingCell);
@@ -334,6 +336,13 @@ export function GridContainer({
[toggleRow],
);
const expandRow = useCallback(
(rowId: string) => {
onExpandRow?.(rowId);
},
[onExpandRow],
);
const prevEditingRef = useRef(editingCell);
useEffect(() => {
const prev = prevEditingRef.current;
@@ -385,6 +394,7 @@ export function GridContainer({
clearSelection,
deleteSelected,
toggleRowSelection,
expandRow,
});
const activeCell = editingCell ?? focusedCell;
@@ -25,6 +25,7 @@ type UseGridKeyboardNavOptions = {
clearSelection: () => void;
deleteSelected: () => void | Promise<void>;
toggleRowSelection: (rowId: string) => void;
expandRow: (rowId: string) => void;
};
const isPrintableKey = (e: KeyboardEvent) =>
@@ -52,6 +53,7 @@ export function useGridKeyboardNav({
clearSelection,
deleteSelected,
toggleRowSelection,
expandRow,
}: UseGridKeyboardNavOptions) {
const getColIds = useCallback(
() =>
@@ -244,12 +246,15 @@ export function useGridKeyboardNav({
}
break;
default: {
if (e.key === " " && focusedCell.propertyId === "__row_number") {
if (e.key === " ") {
e.preventDefault();
toggleRowSelection(focusedCell.rowId);
} else if (e.key === " " && propertyType(focusedCell.propertyId) === "checkbox") {
e.preventDefault();
openEditor(focusedCell);
if (focusedCell.propertyId === "__row_number") {
toggleRowSelection(focusedCell.rowId);
} else if (propertyType(focusedCell.propertyId) === "checkbox") {
openEditor(focusedCell);
} else {
expandRow(focusedCell.rowId);
}
} else if (isPrintableKey(e)) {
e.preventDefault();
beginTypeToEdit(focusedCell, e.key);
@@ -275,6 +280,7 @@ export function useGridKeyboardNav({
clearSelection,
deleteSelected,
toggleRowSelection,
expandRow,
],
);
@@ -38,7 +38,15 @@ export function useHorizontalScrollSync<
body.scrollLeft += e.deltaY;
};
const onHeaderScroll = () => {
if (rafId !== 0) return;
if (body.scrollLeft !== header.scrollLeft) {
body.scrollLeft = header.scrollLeft;
}
};
body.addEventListener("scroll", onBodyScroll, { passive: true });
header.addEventListener("scroll", onHeaderScroll, { passive: true });
header.addEventListener("wheel", onHeaderWheel, { passive: false });
// Initial sync in case the body is already scrolled when the hook mounts.
@@ -46,6 +54,7 @@ export function useHorizontalScrollSync<
return () => {
body.removeEventListener("scroll", onBodyScroll);
header.removeEventListener("scroll", onHeaderScroll);
header.removeEventListener("wheel", onHeaderWheel);
if (rafId !== 0) cancelAnimationFrame(rafId);
};