From 16708cd7cc8f23919d5183a71a4230f725713a8f Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Mon, 15 Jun 2026 02:39:04 +0100 Subject: [PATCH] feat(base): seed editor value on type-to-edit for free-text cells --- .../ee/base/components/cells/cell-email.tsx | 13 ++++++- .../ee/base/components/cells/cell-number.tsx | 3 ++ .../ee/base/components/cells/cell-text.tsx | 13 ++++++- .../src/ee/base/components/cells/cell-url.tsx | 13 ++++++- .../ee/base/hooks/use-editable-text-cell.ts | 37 ++++++++++++++++--- 5 files changed, 67 insertions(+), 12 deletions(-) diff --git a/apps/client/src/ee/base/components/cells/cell-email.tsx b/apps/client/src/ee/base/components/cells/cell-email.tsx index 15982698c..0d93f69fa 100644 --- a/apps/client/src/ee/base/components/cells/cell-email.tsx +++ b/apps/client/src/ee/base/components/cells/cell-email.tsx @@ -15,9 +15,18 @@ type CellEmailProps = { const toDraft = (value: unknown) => (typeof value === "string" ? value : ""); const parse = (draft: string) => draft || null; -export function CellEmail({ value, isEditing, onCommit, onCancel }: CellEmailProps) { +export function CellEmail({ value, property, rowId, isEditing, onCommit, onCancel }: CellEmailProps) { const { draft, setDraft, inputRef, handleKeyDown, handleBlur } = - useEditableTextCell({ value, isEditing, onCommit, onCancel, toDraft, parse }); + useEditableTextCell({ + value, + isEditing, + onCommit, + onCancel, + toDraft, + parse, + rowId, + propertyId: property.id, + }); if (isEditing) { return ( diff --git a/apps/client/src/ee/base/components/cells/cell-number.tsx b/apps/client/src/ee/base/components/cells/cell-number.tsx index 0e88442e0..cbb50a991 100644 --- a/apps/client/src/ee/base/components/cells/cell-number.tsx +++ b/apps/client/src/ee/base/components/cells/cell-number.tsx @@ -92,6 +92,7 @@ export function parseNumberDraft(draft: string): number | null { export function CellNumber({ value, property, + rowId, isEditing, onCommit, onCancel, @@ -105,6 +106,8 @@ export function CellNumber({ onCancel, toDraft, parse: parseNumberDraft, + rowId, + propertyId: property.id, }); if (isEditing) { diff --git a/apps/client/src/ee/base/components/cells/cell-text.tsx b/apps/client/src/ee/base/components/cells/cell-text.tsx index 24410b96b..172e0350a 100644 --- a/apps/client/src/ee/base/components/cells/cell-text.tsx +++ b/apps/client/src/ee/base/components/cells/cell-text.tsx @@ -16,9 +16,18 @@ type CellTextProps = { const toDraft = (value: unknown) => (typeof value === "string" ? value : ""); const parse = (draft: string) => draft; -export function CellText({ value, isEditing, onCommit, onCancel }: CellTextProps) { +export function CellText({ value, property, rowId, isEditing, onCommit, onCancel }: CellTextProps) { const { draft, setDraft, inputRef, handleKeyDown, handleBlur } = - useEditableTextCell({ value, isEditing, onCommit, onCancel, toDraft, parse }); + useEditableTextCell({ + value, + isEditing, + onCommit, + onCancel, + toDraft, + parse, + rowId, + propertyId: property.id, + }); if (isEditing) { return ( diff --git a/apps/client/src/ee/base/components/cells/cell-url.tsx b/apps/client/src/ee/base/components/cells/cell-url.tsx index fb637ef20..c7c4de35e 100644 --- a/apps/client/src/ee/base/components/cells/cell-url.tsx +++ b/apps/client/src/ee/base/components/cells/cell-url.tsx @@ -16,9 +16,18 @@ type CellUrlProps = { const toDraft = (value: unknown) => (typeof value === "string" ? value : ""); const parse = (draft: string) => draft || null; -export function CellUrl({ value, isEditing, onCommit, onCancel }: CellUrlProps) { +export function CellUrl({ value, property, rowId, isEditing, onCommit, onCancel }: CellUrlProps) { const { draft, setDraft, inputRef, handleKeyDown, handleBlur } = - useEditableTextCell({ value, isEditing, onCommit, onCancel, toDraft, parse }); + useEditableTextCell({ + value, + isEditing, + onCommit, + onCancel, + toDraft, + parse, + rowId, + propertyId: property.id, + }); if (isEditing) { return ( diff --git a/apps/client/src/ee/base/hooks/use-editable-text-cell.ts b/apps/client/src/ee/base/hooks/use-editable-text-cell.ts index 996d5a3ad..e7d833609 100644 --- a/apps/client/src/ee/base/hooks/use-editable-text-cell.ts +++ b/apps/client/src/ee/base/hooks/use-editable-text-cell.ts @@ -1,4 +1,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; +import { useStore, type PrimitiveAtom } from "jotai"; +import { pendingTypeInsertAtom, type PendingTypeInsert } from "@/ee/base/atoms/base-atoms"; export type UseEditableTextCellParams = { value: unknown; @@ -9,6 +11,8 @@ export type UseEditableTextCellParams = { toDraft: (value: unknown) => string; /** draft string -> the value passed to onCommit */ parse: (draft: string) => unknown; + rowId?: string; + propertyId?: string; }; export type EditableTextCell = { @@ -26,6 +30,8 @@ export function useEditableTextCell({ onCancel, toDraft, parse, + rowId, + propertyId, }: UseEditableTextCellParams): EditableTextCell { const [draft, setDraft] = useState(() => toDraft(value)); const inputRef = useRef(null); @@ -33,18 +39,37 @@ export function useEditableTextCell({ const wasEditingRef = useRef(false); const toDraftRef = useRef(toDraft); toDraftRef.current = toDraft; + const store = useStore(); useEffect(() => { if (isEditing && !wasEditingRef.current) { committedRef.current = false; - setDraft(toDraftRef.current(value)); - requestAnimationFrame(() => { - inputRef.current?.focus(); - inputRef.current?.select(); - }); + const pending = store.get(pendingTypeInsertAtom); + const seeded = + pending != null && + pending.rowId === rowId && + pending.propertyId === propertyId; + if (seeded) { + setDraft(pending.char); + store.set(pendingTypeInsertAtom as PrimitiveAtom, null); + requestAnimationFrame(() => { + const el = inputRef.current; + if (el) { + el.focus(); + const len = el.value.length; + el.setSelectionRange(len, len); + } + }); + } else { + setDraft(toDraftRef.current(value)); + requestAnimationFrame(() => { + inputRef.current?.focus(); + inputRef.current?.select(); + }); + } } wasEditingRef.current = isEditing; - }, [isEditing, value]); + }, [isEditing, value, rowId, propertyId, store]); const commitOnce = useCallback( (val: unknown) => {