feat(FN-779): make inline editor taller with 4-row default and mount-time resize
- Increase inline editor textarea default rows from 1 to 4 for better multi-line editing - Add mount-time auto-resize to fit content on initial render - Add regression tests for taller inline editor behavior - Update documentation to reflect the new taller editor defaults
This commit is contained in:
@@ -40,7 +40,7 @@ AI-guided interactive planning for creating well-specified tasks from high-level
|
||||
|
||||
### Task Management
|
||||
- **Kanban Board**: Drag-and-drop task management across columns (Triage, Todo, In Progress, In Review, Done)
|
||||
- **Inline Editing**: Quick-edit a task's description directly on the board for Triage and Todo columns. Double-click a card or use the pencil icon — visible on hover for desktop, always visible on mobile for touch accessibility. Inline editing changes only the description; the title is preserved. To edit both title and description, use the task detail modal.
|
||||
- **Inline Editing**: Quick-edit a task's description directly on the board for Triage and Todo columns. The editor opens as a taller multi-line editing area (4 visible lines) for comfortable editing of longer descriptions, and auto-grows to fit existing content. Double-click a card or use the pencil icon — visible on hover for desktop, always visible on mobile for touch accessibility. Inline editing changes only the description; the title is preserved. To edit both title and description, use the task detail modal.
|
||||
- **Task Detail Editing**: Edit task title and description directly in the task detail modal. Click the pencil icon in the modal header (available for Triage and Todo tasks) to enter edit mode.
|
||||
- **List View**: Alternative tabular view for tasks with sorting and filtering. The "Hide Done" toggle hides both Done and Archived tasks for an active-work-only view.
|
||||
- **Model Selection at Creation**: Choose executor and validator AI models while creating tasks from the board or list view, or leave them unset to use the global defaults. Quick-add model dropdowns in both the board triage column and the list view honor saved favorite providers and pinned models, matching the rest of the dashboard model UI.
|
||||
|
||||
@@ -161,10 +161,16 @@ function TaskCardComponent({
|
||||
setEditDescription(task.description || "");
|
||||
}, [task.id, task.description]);
|
||||
|
||||
// Auto-focus on description textarea when entering edit mode
|
||||
// Auto-focus and auto-resize description textarea when entering edit mode
|
||||
useEffect(() => {
|
||||
if (isEditing) {
|
||||
descTextareaRef.current?.focus();
|
||||
if (isEditing && descTextareaRef.current) {
|
||||
const el = descTextareaRef.current;
|
||||
el.focus();
|
||||
// Apply the same resize logic used in handleDescChange so the textarea
|
||||
// opens at the correct height for existing long descriptions without
|
||||
// requiring the user to type first.
|
||||
el.style.height = "auto";
|
||||
el.style.height = el.scrollHeight + "px";
|
||||
}
|
||||
}, [isEditing]);
|
||||
|
||||
@@ -511,7 +517,7 @@ function TaskCardComponent({
|
||||
onKeyDown={handleDescKeyDown}
|
||||
onBlur={handleBlur}
|
||||
disabled={isSaving}
|
||||
rows={1}
|
||||
rows={4}
|
||||
/>
|
||||
{isSaving && (
|
||||
<div className="card-edit-loading">
|
||||
|
||||
@@ -1387,6 +1387,53 @@ describe("TaskCard inline editing", () => {
|
||||
expect(screen.queryByPlaceholderText(/Task title/i)).toBeNull();
|
||||
expect(screen.getByPlaceholderText(/Task description/i)).toBeDefined();
|
||||
});
|
||||
|
||||
it("opens the description textarea with 4 visible rows", () => {
|
||||
const task = makeEditableTask({ description: "Some text" });
|
||||
|
||||
render(
|
||||
<TaskCard
|
||||
task={task}
|
||||
onOpenDetail={vi.fn()}
|
||||
addToast={noopToast}
|
||||
onUpdateTask={noopUpdateTask}
|
||||
/>
|
||||
);
|
||||
|
||||
// Enter edit mode
|
||||
const card = document.querySelector('[data-id="FN-099"]');
|
||||
fireEvent.doubleClick(card!);
|
||||
|
||||
const descTextarea = screen.getByPlaceholderText(/Task description/i) as HTMLTextAreaElement;
|
||||
expect(descTextarea).toBeDefined();
|
||||
expect(descTextarea.getAttribute("rows")).toBe("4");
|
||||
});
|
||||
|
||||
it("applies mount-time auto-resize for existing long descriptions", () => {
|
||||
// A multi-line description that would exceed the default 4-row height
|
||||
const longDescription = Array(10).fill("This is a line of description text.").join("\n");
|
||||
const task = makeEditableTask({ description: longDescription });
|
||||
|
||||
render(
|
||||
<TaskCard
|
||||
task={task}
|
||||
onOpenDetail={vi.fn()}
|
||||
addToast={noopToast}
|
||||
onUpdateTask={noopUpdateTask}
|
||||
/>
|
||||
);
|
||||
|
||||
// Enter edit mode
|
||||
const card = document.querySelector('[data-id="FN-099"]');
|
||||
fireEvent.doubleClick(card!);
|
||||
|
||||
const descTextarea = screen.getByPlaceholderText(/Task description/i) as HTMLTextAreaElement;
|
||||
// The mount-time resize effect sets height to scrollHeight + "px".
|
||||
// In JSDOM, scrollHeight is 0 (no real layout), so the style ends up
|
||||
// as "0px" — but the important thing is the effect *did* set the
|
||||
// height property, proving the auto-resize logic runs on mount.
|
||||
expect(descTextarea.style.height).not.toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -3974,7 +3974,7 @@ body {
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
line-height: 1.4;
|
||||
min-height: 38px;
|
||||
min-height: 80px;
|
||||
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user