fix(directory-picker): address review — modal layering, root nav, stale state

- HIGH: the "Browse Folders..." entry in the New Session RN <Modal> expanded
  a sibling BottomSheet, which a native Modal always covers (a
  BottomSheetModal through the root portal would be covered too), so the
  primary entry point was invisible/untouchable. The modal is now closed
  before the sheet expands and restored on cancel via a new onDismiss
  callback (restoreNewSessionOnDismiss ref); picking a folder proceeds to
  session creation without reopening the modal.

- MEDIUM: parentOf("/") returned "/" so Up at the POSIX root looped forever;
  it now returns null at "/", "\" and Windows drive roots alike, disabling
  the Up button there.

- LOW: opening the sheet with no known start directory (server home not
  loaded yet) showed the previous open's stale entries; it now clears state,
  invalidates in-flight loads, and shows an "Enter a path above to start
  browsing" empty state. Sheet init also no longer re-runs on snap-point
  drags (wasOpen guard).

- Extracted the pure path helpers (stripTrailingSlash/parentOf/nameOf) into
  src/lib/path-utils.ts (no RN imports) with node --test coverage for POSIX
  root, Windows drive roots, trailing slashes, and backslash paths.

typecheck clean; 97/97 tests pass (16 new).
This commit is contained in:
engineer
2026-07-16 15:57:31 -07:00
parent f0a7c1d868
commit 7e9b3981c3
4 changed files with 184 additions and 30 deletions

View File

@@ -275,17 +275,28 @@ export default function SessionsScreen() {
}
}
// The browser sheet is a sibling of the New Session <Modal>. A native RN
// Modal layers above everything in the React root (including bottom-sheet
// portals), so the modal must be closed before the sheet is shown; this ref
// remembers to bring it back if the user cancels without picking a folder.
const restoreNewSessionOnDismiss = useRef(false)
const openBrowser = useCallback(
(startDir: string | null, mode: "create" | "switch") => {
setBrowseStartDir(startDir || serverHome || null)
setBrowseMode(mode)
if (mode === "create" && showNewSession) {
restoreNewSessionOnDismiss.current = true
setShowNewSession(false)
}
browserSheetRef.current?.expand()
},
[serverHome],
[serverHome, showNewSession],
)
const onBrowserSelect = useCallback(
(directory: string) => {
restoreNewSessionOnDismiss.current = false
if (browseMode === "switch") {
handleSwitchDirectory(directory)
dirSheetRef.current?.close()
@@ -296,6 +307,13 @@ export default function SessionsScreen() {
[browseMode, handleSwitchDirectory, onCreateInDirectory],
)
const onBrowserDismiss = useCallback(() => {
if (restoreNewSessionOnDismiss.current) {
restoreNewSessionOnDismiss.current = false
setShowNewSession(true)
}
}, [])
const onFabPress = () => {
// Quick create in current project
onCreateSession()
@@ -666,6 +684,7 @@ export default function SessionsScreen() {
clientForDirectory={clientForDirectory}
isDark={isDark}
onSelect={onBrowserSelect}
onDismiss={onBrowserDismiss}
/>
</View>
)