(null);
const createFolder = async () => {
const trimmedName = name.trim();
if (!trimmedName || creating) return;
setCreating(true);
setError(null);
try {
await onCreateDirectory(trimmedName);
setEditing(false);
} catch (err) {
setError(err instanceof Error ? err.message : t("common:failedToCreateFolder"));
} finally {
setCreating(false);
}
};
return (
{editing ? (
{
setName(next);
setError(null);
}}
onSubmit={() => void createFolder()}
onCancel={() => setEditing(false)}
/>
) : (
{t("common:folders")}
)}
);
}
/** The inline "new folder" row, extracted to keep the toolbar under the
* max-lines-per-function cap. */
function NewFolderForm({
name,
error,
creating,
touchRows,
onNameChange,
onSubmit,
onCancel,
}: {
name: string;
error: string | null;
creating: boolean;
touchRows: boolean;
onNameChange: (next: string) => void;
onSubmit: () => void;
onCancel: () => void;
}) {
const { t } = useTranslation();
return (
onNameChange(event.target.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
event.preventDefault();
onSubmit();
} else if (event.key === "Escape") {
onCancel();
}
}}
placeholder={t("common:folderName")}
autoFocus
className={cn("min-w-0 flex-1", touchRows && "h-10")}
/>
{error ? (
{error}
) : null}
);
}
function Entries({
listing,
loading,
error,
onDescend,
touchRows,
fillAvailableHeight,
}: {
listing: DirectoryListing | null;
loading: boolean;
error: string | null;
onDescend: (path: string) => void;
touchRows?: boolean;
fillAvailableHeight?: boolean;
}) {
const { t } = useTranslation();
if (loading) return ;
if (error) return ;
if (!listing || listing.entries.length === 0) {
return ;
}
return (
e.stopPropagation()}
>
{listing.entries.map((entry) => (
))}
);
}
function EmptyRow({ text, variant, testId }: { text: string; variant?: "error"; testId?: string }) {
return (
{text}
);
}
function Footer({
choosable,
onUseScratch,
onChoose,
}: {
choosable: boolean;
onUseScratch: () => void;
onChoose: () => void;
}) {
const { t } = useTranslation();
return (
);
}