feat(base): insert row below via Shift+Enter on the primary cell

This commit is contained in:
Philipinho
2026-06-16 13:22:54 +01:00
parent c43ac7fc8c
commit 2e80fc457c
5 changed files with 75 additions and 31 deletions
@@ -18,7 +18,7 @@ type BaseTableProps = {
isFetchingNextPage: boolean;
onFetchNextPage: () => void;
onCellUpdate: (rowId: string, propertyId: string, value: unknown) => void;
onAddRow: () => void;
onAddRow: (afterRowId?: string, focusPropertyId?: string) => void;
onColumnReorder: (columnId: string, finishIndex: number) => void;
onResizeEnd: () => void;
onRowReorder: (
@@ -12,6 +12,7 @@ import {
FilterGroup,
ViewSortConfig,
EditingCell,
FocusedCell,
IBaseProperty,
} from "@/ee/base/types/base.types";
import {
@@ -25,6 +26,7 @@ import { useUpdateViewMutation } from "@/ee/base/queries/base-view-query";
import {
activeViewIdAtomFamily,
editingCellAtomFamily,
focusedCellAtomFamily,
} from "@/ee/base/atoms/base-atoms";
import { useBaseTable } from "@/ee/base/hooks/use-base-table";
import { isSystemPropertyType } from "@/ee/base/property-types/property-type.registry";
@@ -89,6 +91,10 @@ export function BaseView({ pageId, embedded, editable = true, titleSlot }: BaseV
editingCellAtomFamily(pageId),
) as unknown as [EditingCell, (val: EditingCell) => void];
const [, setFocusedCell] = useAtom(
focusedCellAtomFamily(pageId),
) as unknown as [FocusedCell, (val: FocusedCell) => void];
const views = useMemo(
() =>
[...(base?.views ?? [])].sort((a, b) =>
@@ -221,33 +227,42 @@ export function BaseView({ pageId, embedded, editable = true, titleSlot }: BaseV
[editable, pageId, updateRow],
);
const handleAddRow = useCallback(() => {
if (!editable) return;
createRowMutation.mutate(
{ pageId },
{
onSuccess: (newRow) => {
const firstEditable = table.getVisibleLeafColumns().find((col) => {
if (col.id === "__row_number") return false;
const prop = col.columnDef.meta?.property as
| IBaseProperty
| undefined;
return (
!!prop &&
prop.type !== "checkbox" &&
!isSystemPropertyType(prop.type)
);
});
const propertyId = (
firstEditable?.columnDef.meta?.property as IBaseProperty | undefined
)?.id;
if (propertyId) {
setEditingCell({ rowId: newRow.id, propertyId });
}
const handleAddRow = useCallback(
(afterRowId?: string, focusPropertyId?: string) => {
if (!editable) return;
createRowMutation.mutate(
{ pageId, ...(afterRowId ? { afterRowId } : {}) },
{
onSuccess: (newRow) => {
let propertyId = focusPropertyId;
if (!propertyId) {
const firstEditable = table.getVisibleLeafColumns().find((col) => {
if (col.id === "__row_number") return false;
const prop = col.columnDef.meta?.property as
| IBaseProperty
| undefined;
return (
!!prop &&
prop.type !== "checkbox" &&
!isSystemPropertyType(prop.type)
);
});
propertyId = (
firstEditable?.columnDef.meta?.property as
| IBaseProperty
| undefined
)?.id;
}
if (propertyId) {
setEditingCell({ rowId: newRow.id, propertyId });
setFocusedCell({ rowId: newRow.id, propertyId });
}
},
},
},
);
}, [editable, pageId, createRowMutation, table, setEditingCell]);
);
},
[editable, pageId, createRowMutation, table, setEditingCell, setFocusedCell],
);
const handleViewChange = useCallback(
(viewId: string) => {
@@ -67,7 +67,7 @@ type GridContainerProps = {
table: Table<IBaseRow>;
properties: IBaseProperty[];
onCellUpdate: (rowId: string, propertyId: string, value: unknown) => void;
onAddRow?: () => void;
onAddRow?: (afterRowId?: string, focusPropertyId?: string) => void;
pageId: string;
onColumnReorder?: (columnId: string, finishIndex: number) => void;
onResizeEnd?: () => void;
@@ -378,6 +378,13 @@ export function GridContainer({
[table, setFocusedCell],
);
const handleAddRowBelow = useCallback(
(afterRowId: string, focusPropertyId: string) => {
onAddRow?.(afterRowId, focusPropertyId);
},
[onAddRow],
);
useGridKeyboardNav({
table,
properties,
@@ -395,6 +402,7 @@ export function GridContainer({
deleteSelected,
toggleRowSelection,
expandRow,
addRow: handleAddRowBelow,
});
const activeCell = editingCell ?? focusedCell;
@@ -21,7 +21,7 @@ type ViewRendererProps = {
isFetchingNextPage: boolean;
onFetchNextPage: () => void;
onCellUpdate: (rowId: string, propertyId: string, value: unknown) => void;
onAddRow: () => void;
onAddRow: (afterRowId?: string, focusPropertyId?: string) => void;
onColumnReorder: (columnId: string, finishIndex: number) => void;
onResizeEnd: () => void;
onRowReorder: (
@@ -1,4 +1,4 @@
import { useCallback, useEffect } from "react";
import { useCallback, useEffect, useMemo } from "react";
import { Table } from "@tanstack/react-table";
import {
IBaseRow,
@@ -26,6 +26,7 @@ type UseGridKeyboardNavOptions = {
deleteSelected: () => void | Promise<void>;
toggleRowSelection: (rowId: string) => void;
expandRow: (rowId: string) => void;
addRow: (afterRowId: string, focusPropertyId: string) => void;
};
const isPrintableKey = (e: KeyboardEvent) =>
@@ -54,6 +55,7 @@ export function useGridKeyboardNav({
deleteSelected,
toggleRowSelection,
expandRow,
addRow,
}: UseGridKeyboardNavOptions) {
const getColIds = useCallback(
() =>
@@ -79,6 +81,11 @@ export function useGridKeyboardNav({
[properties],
);
const primaryPropertyId = useMemo(
() => properties.find((p) => p.isPrimary)?.id,
[properties],
);
const goEditing = useCallback(
(next: CellCoord) => {
(document.activeElement as HTMLElement | null)?.blur();
@@ -142,6 +149,12 @@ export function useGridKeyboardNav({
}
case "Enter": {
e.preventDefault();
if (e.shiftKey && editingCell.propertyId === primaryPropertyId) {
(document.activeElement as HTMLElement | null)?.blur();
setEditingCell(null);
addRow(editingCell.rowId, editingCell.propertyId);
break;
}
const next = computeNextCell(
getRowIds(),
getColIds(),
@@ -241,7 +254,13 @@ export function useGridKeyboardNav({
case "Enter":
case "F2":
e.preventDefault();
if (focusedCell.propertyId === "__row_number") {
if (
e.key === "Enter" &&
e.shiftKey &&
focusedCell.propertyId === primaryPropertyId
) {
addRow(focusedCell.rowId, focusedCell.propertyId);
} else if (focusedCell.propertyId === "__row_number") {
toggleRowSelection(focusedCell.rowId);
} else {
openEditor(focusedCell);
@@ -284,6 +303,8 @@ export function useGridKeyboardNav({
deleteSelected,
toggleRowSelection,
expandRow,
primaryPropertyId,
addRow,
],
);