From 1b5c081e1e1b7fb7a5af4eb3151846928d55c265 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Mon, 15 Jun 2026 04:54:23 +0100
Subject: [PATCH] fix(base): tab from long-text editor moves to next cell
instead of leaving the table
---
.../base/components/cells/cell-long-text.tsx | 8 +++++-
.../src/ee/base/components/grid/grid-cell.tsx | 27 +++++++++++++++++++
.../property-type.descriptor.ts | 1 +
3 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/apps/client/src/ee/base/components/cells/cell-long-text.tsx b/apps/client/src/ee/base/components/cells/cell-long-text.tsx
index 756ec09f7..2c3900562 100644
--- a/apps/client/src/ee/base/components/cells/cell-long-text.tsx
+++ b/apps/client/src/ee/base/components/cells/cell-long-text.tsx
@@ -13,6 +13,7 @@ type CellLongTextProps = {
onCommit: (value: unknown) => void;
onValueChange: (value: unknown) => void;
onCancel: () => void;
+ onTabNavigate?: (shiftKey: boolean) => void;
};
const toText = (value: unknown) => (typeof value === "string" ? value : "");
@@ -27,6 +28,7 @@ export function CellLongText({
onCommit,
onValueChange,
onCancel,
+ onTabNavigate,
}: CellLongTextProps) {
const [draft, setDraft] = useState(() => toText(value));
const cancelledRef = useRef(false);
@@ -127,7 +129,11 @@ export function CellLongText({
}}
onKeyDown={(e) => {
e.stopPropagation();
- if (e.key === "Escape") {
+ if (e.key === "Tab") {
+ e.preventDefault();
+ commit();
+ onTabNavigate?.(e.shiftKey);
+ } else if (e.key === "Escape") {
e.preventDefault();
cancel();
} else if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
diff --git a/apps/client/src/ee/base/components/grid/grid-cell.tsx b/apps/client/src/ee/base/components/grid/grid-cell.tsx
index 90243a0a6..07a3d754d 100644
--- a/apps/client/src/ee/base/components/grid/grid-cell.tsx
+++ b/apps/client/src/ee/base/components/grid/grid-cell.tsx
@@ -18,6 +18,7 @@ import {
getDescriptor,
} from "@/ee/base/property-types/property-type.registry";
import { cellValuesEqual } from "@/ee/base/components/cells/cell-value-equal";
+import { computeNextCell } from "@/ee/base/utils/grid-cell-nav";
import { useBaseEditable } from "@/ee/base/context/base-editable";
import { useRowExpand } from "@/ee/base/context/row-expand";
import { RowNumberCell } from "./row-number-cell";
@@ -132,6 +133,31 @@ export const GridCell = memo(function GridCell({
setEditingCell(null);
}, [setEditingCell]);
+ const handleTabNavigate = useCallback(
+ (shiftKey: boolean) => {
+ if (!property) return;
+ const tableInstance = cell.getContext().table;
+ const colIds = tableInstance
+ .getVisibleLeafColumns()
+ .filter((c) => c.id !== "__row_number")
+ .map((c) => c.id);
+ const rowIds = tableInstance.getRowModel().rows.map((r) => r.id);
+ const next = computeNextCell(
+ rowIds,
+ colIds,
+ { rowId, propertyId: property.id },
+ 0,
+ shiftKey ? -1 : 1,
+ true,
+ );
+ if (next) {
+ setEditingCell(next);
+ setFocusedCell(next);
+ }
+ },
+ [cell, rowId, property, setEditingCell, setFocusedCell],
+ );
+
if (isRowNumber) {
return (
{property.isPrimary && onExpandRow && !isEditing && (
diff --git a/apps/client/src/ee/base/property-types/property-type.descriptor.ts b/apps/client/src/ee/base/property-types/property-type.descriptor.ts
index 28e9fc275..8b33ad110 100644
--- a/apps/client/src/ee/base/property-types/property-type.descriptor.ts
+++ b/apps/client/src/ee/base/property-types/property-type.descriptor.ts
@@ -17,6 +17,7 @@ export type CellComponentProps = {
onCommit: (value: unknown) => void;
onValueChange: (value: unknown) => void;
onCancel: () => void;
+ onTabNavigate?: (shiftKey: boolean) => void;
};
export type FilterInputKind =