mirror of
https://github.com/docmost/docmost.git
synced 2026-07-10 14:05:00 +10:00
feat(base): seed editor value on type-to-edit for free-text cells
This commit is contained in:
@@ -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 (
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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<HTMLInputElement>(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<PendingTypeInsert>, 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) => {
|
||||
|
||||
Reference in New Issue
Block a user