|
|
@@ -31,61 +31,70 @@ export default function SearchForm({
|
|
|
}) {
|
|
|
const canSearch = typeof qDraft === "string" && qDraft.trim().length > 0;
|
|
|
|
|
|
+ // RHL-038 UI behavior:
|
|
|
+ // - Single scope shows an extra combobox (branch picker).
|
|
|
+ // - Multi/All does not.
|
|
|
+ // - We animate the combobox container (max-width/max-height/opacity) so the
|
|
|
+ // query block (input + search button) grows/shrinks smoothly.
|
|
|
+ const showSingleBranchCombobox = Boolean(
|
|
|
+ isAdminDev && scope === SEARCH_SCOPE.SINGLE
|
|
|
+ );
|
|
|
+
|
|
|
return (
|
|
|
<div className="space-y-4">
|
|
|
<form
|
|
|
onSubmit={(e) => {
|
|
|
e.preventDefault();
|
|
|
-
|
|
|
- // UX rule:
|
|
|
- // - Only submit when the query is non-empty.
|
|
|
- // - This keeps the Search API safe and avoids accidental “match everything”.
|
|
|
if (!canSearch) return;
|
|
|
-
|
|
|
onSubmit();
|
|
|
}}
|
|
|
className="space-y-4"
|
|
|
>
|
|
|
{/*
|
|
|
- Layout goal (RHL-038):
|
|
|
- - Desktop: one row with (1) scope, (2) query, (3) limit
|
|
|
- - Mobile: natural stacking
|
|
|
- Implementation:
|
|
|
- - Use a responsive grid that becomes 3 columns on lg+
|
|
|
- - Align items to the bottom so labels line up nicely.
|
|
|
+ Layout goal:
|
|
|
+ - Desktop: everything on one line (scope + optional single combobox | query | limit)
|
|
|
+ - Mobile: stack to avoid horizontal overflow
|
|
|
*/}
|
|
|
- <div className="flex items-start justify-between gap-3 flex-nowrap">
|
|
|
- <div className="flex justify-start gap-2 items-center">
|
|
|
- {/* 1) Scope (admin/dev only) */}
|
|
|
- {isAdminDev ? (
|
|
|
+ <div className="flex flex-col gap-3 lg:flex-row items-start lg:flex-nowrap">
|
|
|
+ {/* Left block: scope + (animated) single-branch combobox */}
|
|
|
+ {isAdminDev ? (
|
|
|
+ <div className="flex items-end shrink-0">
|
|
|
<SearchScopeSelect
|
|
|
branch={branch}
|
|
|
scope={scope}
|
|
|
onScopeChange={onScopeChange}
|
|
|
isSubmitting={isSubmitting}
|
|
|
/>
|
|
|
- ) : null}
|
|
|
|
|
|
- {/*
|
|
|
- Admin/dev: SINGLE branch selection.
|
|
|
- We keep this *below* the main row so the top row stays exactly:
|
|
|
- Scope | Query | Limit
|
|
|
- */}
|
|
|
- {isAdminDev && scope === SEARCH_SCOPE.SINGLE ? (
|
|
|
- <div>
|
|
|
+ {/*
|
|
|
+ Animated presence (no mount/unmount):
|
|
|
+ - When hidden: max-w-0/max-h-0 + opacity-0 so it takes no space.
|
|
|
+ - When shown: expands to a reasonable max size.
|
|
|
+ This animation drives the smooth resize of the query input block.
|
|
|
+ */}
|
|
|
+ <div
|
|
|
+ className={[
|
|
|
+ "overflow-hidden transition-all duration-200 ease-in-out",
|
|
|
+ showSingleBranchCombobox
|
|
|
+ ? "ml-2 max-w-44 max-h-24 opacity-100"
|
|
|
+ : "ml-0 max-w-0 max-h-0 opacity-0 pointer-events-none",
|
|
|
+ ].join(" ")}
|
|
|
+ aria-hidden={showSingleBranchCombobox ? "false" : "true"}
|
|
|
+ >
|
|
|
<SearchSingleBranchCombobox
|
|
|
branch={branch}
|
|
|
branchesStatus={branchesStatus}
|
|
|
availableBranches={availableBranches}
|
|
|
onSingleBranchChange={onSingleBranchChange}
|
|
|
- isSubmitting={isSubmitting}
|
|
|
+ // Disable when hidden so it can't be focused/clicked.
|
|
|
+ isSubmitting={isSubmitting || !showSingleBranchCombobox}
|
|
|
/>
|
|
|
</div>
|
|
|
- ) : null}
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
|
|
|
- <div className="flex flex-1">
|
|
|
- {/* 2) Query (always) */}
|
|
|
+ {/* Middle block: query must take the most space */}
|
|
|
+ <div className="flex-1 min-w-0">
|
|
|
<SearchQueryBox
|
|
|
qDraft={qDraft}
|
|
|
onQDraftChange={onQDraftChange}
|
|
|
@@ -96,33 +105,18 @@ export default function SearchForm({
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- {/* 3) Limit (always) */}
|
|
|
- <SearchLimitSelect
|
|
|
- limit={limit}
|
|
|
- onLimitChange={onLimitChange}
|
|
|
- isSubmitting={isSubmitting}
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- {/*
|
|
|
- Admin/dev: SINGLE branch selection.
|
|
|
- We keep this *below* the main row so the top row stays exactly:
|
|
|
- Scope | Query | Limit
|
|
|
- */}
|
|
|
- {/* {isAdminDev && scope === SEARCH_SCOPE.SINGLE ? (
|
|
|
- <div>
|
|
|
- <SearchSingleBranchCombobox
|
|
|
- branch={branch}
|
|
|
- branchesStatus={branchesStatus}
|
|
|
- availableBranches={availableBranches}
|
|
|
- onSingleBranchChange={onSingleBranchChange}
|
|
|
+ {/* Right block: limit stays “content-sized” */}
|
|
|
+ <div className="shrink-0">
|
|
|
+ <SearchLimitSelect
|
|
|
+ limit={limit}
|
|
|
+ onLimitChange={onLimitChange}
|
|
|
isSubmitting={isSubmitting}
|
|
|
/>
|
|
|
</div>
|
|
|
- ) : null} */}
|
|
|
+ </div>
|
|
|
</form>
|
|
|
|
|
|
- {/* Multi scope branch picker remains below the form row (as requested). */}
|
|
|
+ {/* Multi scope branch picker remains below */}
|
|
|
{isAdminDev && scope === SEARCH_SCOPE.MULTI ? (
|
|
|
<SearchMultiBranchPicker
|
|
|
branchesStatus={branchesStatus}
|