feat(KB-656): add autoExpand prop to QuickEntryBox
- Add autoExpand prop to QuickEntryBox (defaults to true for backward compatibility)
- When autoExpand is true, component auto-expands on focus
- List view passes autoExpand={false} to keep view collapsed by default
- Board view continues to auto-expand using default behavior
- Add tests for both autoExpand modes and verify focus behavior
This commit is contained in:
@@ -194,6 +194,7 @@ function ColumnComponent({ column, tasks, maxConcurrent, onMoveTask, onOpenDetai
|
||||
availableModels={availableModels}
|
||||
onPlanningMode={onPlanningMode}
|
||||
onSubtaskBreakdown={onSubtaskBreakdown}
|
||||
autoExpand={true}
|
||||
/>
|
||||
)}
|
||||
{column === "in-progress" ? (
|
||||
|
||||
@@ -730,6 +730,7 @@ export function ListView({
|
||||
availableModels={availableModels}
|
||||
onPlanningMode={onPlanningMode}
|
||||
onSubtaskBreakdown={onSubtaskBreakdown}
|
||||
autoExpand={false}
|
||||
/>
|
||||
</div>
|
||||
{filteredCount === 0 ? (
|
||||
|
||||
@@ -24,6 +24,12 @@ interface QuickEntryBoxProps {
|
||||
* Called when the user clicks the "Subtask" button to trigger subtask breakdown.
|
||||
*/
|
||||
onSubtaskBreakdown?: (description: string) => void;
|
||||
/**
|
||||
* When true, the component automatically expands when focused.
|
||||
* Set to false to keep the view collapsed until manually toggled.
|
||||
* Defaults to true for backward compatibility.
|
||||
*/
|
||||
autoExpand?: boolean;
|
||||
}
|
||||
|
||||
function getModelSelectionValue(provider?: string, modelId?: string): string {
|
||||
@@ -46,7 +52,7 @@ function parseModelSelection(value: string): { provider?: string; modelId?: stri
|
||||
};
|
||||
}
|
||||
|
||||
export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels, onPlanningMode, onSubtaskBreakdown }: QuickEntryBoxProps) {
|
||||
export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels, onPlanningMode, onSubtaskBreakdown, autoExpand = true }: QuickEntryBoxProps) {
|
||||
const [description, setDescription] = useState(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
return localStorage.getItem(STORAGE_KEY) || "";
|
||||
@@ -334,6 +340,13 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleFocus = useCallback(() => {
|
||||
// Auto-expand on focus when autoExpand prop is true (default)
|
||||
if (autoExpand) {
|
||||
setIsExpanded(true);
|
||||
}
|
||||
}, [autoExpand]);
|
||||
|
||||
const toggleDep = useCallback((id: string) => {
|
||||
setDependencies((prev) =>
|
||||
prev.includes(id) ? prev.filter((d) => d !== id) : [...prev, id],
|
||||
@@ -474,6 +487,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
disabled={isSubmitting || isDisabled}
|
||||
data-testid="quick-entry-input"
|
||||
|
||||
@@ -180,17 +180,26 @@ describe("QuickEntryBox", () => {
|
||||
expect((textarea as HTMLTextAreaElement).placeholder).toBe("Add a task...");
|
||||
});
|
||||
|
||||
it("does NOT expand on focus", () => {
|
||||
renderQuickEntryBox({}, { startCollapsed: true });
|
||||
// Component starts with disclosure expanded by default
|
||||
it("does NOT expand on focus when autoExpand is false", () => {
|
||||
renderQuickEntryBox({ autoExpand: false });
|
||||
const textarea = screen.getByTestId("quick-entry-input");
|
||||
|
||||
fireEvent.focus(textarea);
|
||||
|
||||
// Should NOT auto-expand on focus (manual toggle only)
|
||||
// Should NOT auto-expand on focus when autoExpand is false
|
||||
expect(textarea.classList.contains("quick-entry-input--expanded")).toBe(false);
|
||||
});
|
||||
|
||||
it("expands on focus by default (backward compatible)", () => {
|
||||
renderQuickEntryBox();
|
||||
const textarea = screen.getByTestId("quick-entry-input");
|
||||
|
||||
fireEvent.focus(textarea);
|
||||
|
||||
// Should auto-expand on focus by default (autoExpand defaults to true)
|
||||
expect(textarea.classList.contains("quick-entry-input--expanded")).toBe(true);
|
||||
});
|
||||
|
||||
it("toggle button expands the view", () => {
|
||||
renderQuickEntryBox({}, { startCollapsed: true });
|
||||
// Component starts with disclosure expanded by default
|
||||
@@ -838,12 +847,13 @@ describe("QuickEntryBox", () => {
|
||||
expect(props.onCreate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// After creation, input should be cleared
|
||||
// After creation, input is cleared and focus is restored
|
||||
expect((textarea as HTMLTextAreaElement).value).toBe("");
|
||||
// Disclosure preference persists - controls remain visible since we expanded earlier
|
||||
expect(screen.getByTestId("quick-entry-deps-button")).toBeTruthy();
|
||||
expect(screen.getByTestId("plan-button")).toBeTruthy();
|
||||
expect(screen.getByTestId("subtask-button")).toBeTruthy();
|
||||
|
||||
// With autoExpand=true (default), textarea auto-expands on focus restore
|
||||
// So the toggle should be expanded (controls visible)
|
||||
expect(screen.getByTestId("quick-entry-toggle").getAttribute("aria-expanded")).toBe("true");
|
||||
expect(document.getElementById("quick-entry-controls")?.hasAttribute("hidden")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user