Skip to content

feat(ui): add Bible Reader search - #396

Open
camrun91 wants to merge 25 commits into
mainfrom
cl/ype-5766_search_ui
Open

camrun91 wants to merge 25 commits into
mainfrom
cl/ype-5766_search_ui

Conversation

@camrun91

@camrun91 camrun91 commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

Important

This pull request was started by Cameron Llewellyn and passed onto Cameron Pak

Bible Reader search

Adds toolbar search with suggestions, browser-local recents, testament filters, verse previews, and navigation that centers the selected verse while dimming surrounding verses. Hosts can use useBibleSearch headlessly or override the toolbar action with onSearchPress.

Closes YPE-5766. Parent: YPE-5622.

UI views

Current Chromium captures using live API data. Filters expand as an accordion; reduced motion uses a fade.

Trending and recents Suggestions
Trending and recent searches Search suggestions before submission
Results Expanded filters
Verse results with collapsed filters Old Testament, New Testament, and Both filters
Dark mode Dark mode search results and expanded filters

Verification and remaining limitations

  • Full unit suite: 1,435 passed, 2 skipped. Chromium stories: 61 passed. Build/typecheck and lint passed.
  • Inspected live views, keyboard disclosure, reduced motion, and interrupted accordion transitions.
  • Some cross-testament searches hit an API pagination HTTP 400; this remains a retryable failure, not a false empty state. A pagination failure can still appear alongside the verse-preview spinner.
  • New labels use English fallbacks until upstream localization syncs.

RetriggerConfidence Score: 5/5

The PR appears safe to merge.

Summary

The PR adds end-to-end Bible Reader search with suggestions, local recents, testament filters, paginated verse results, navigation, and transient verse focus.

  • Introduces a reusable useBibleSearch session and search client integration.
  • Adds the toolbar search interface, result previews, filtering, accessibility behavior, and browser-local recents.
  • Centralizes structural USFM parsing with bounded range expansion.
  • Adds extensive unit, interaction, navigation, and workflow coverage.

Diagram

sequenceDiagram
  participant User
  participant SearchUI as BibleReaderSearch
  participant Hook as useBibleSearch
  participant API as SearchClient
  participant Reader as BibleReader
  User->>SearchUI: Enter or select query
  SearchUI->>Hook: submit query and filter
  Hook->>API: Search verse pages
  API-->>Hook: Hits and continuation token
  Hook-->>SearchUI: Results with previews
  User->>SearchUI: Select verse
  SearchUI->>Reader: Navigate to passage and focus verse
  Reader-->>User: Center verse and dim surroundings
Loading

Reviews (16) · Last reviewed commit: "chore: merge main into Bible search bran..."

@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cb1ff01

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@youversion/platform-core Minor
@youversion/platform-react-hooks Minor
@youversion/platform-react-ui Minor
vite-react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment thread packages/core/src/usfm-reference.ts
Comment thread packages/ui/src/i18n/locales/en.json Outdated
Base automatically changed from cl/ype-5750_search_api to main September 14, 2026 16:08
Search hits and the structural validator both need the same chapter/verse
shape. parseUsfmReference owns that grammar so inverted ranges drop at
the boundary instead of leaking into the reader.
The PRD's suggestion-suppression, stale-page, and dedupe rules are
consequences of one SearchSession union plus a pure reducer, so the eight
phases can be proven without timers or network.
Headless hosts get one phase and five commands. Debounce, language-range
gating, and page commits stay inside the hook so UI never sees tokens or
TanStack Query.
Content can scroll and dim only after the destination chapter is on screen. A seq mailbox plus a hold timer keeps focus separate from verse selection.
Hosts get a zero-required-prop search dialog that talks to useBibleSearch and navigates through one Root-owned verse-focus mailbox. English keys land here so the UI can ship; platform-localization still owns the canonical source.
The public helpers and Reader search UI are new surface on core, hooks, and ui, so they ship as minors together.
The first keystroke after submit left the submitted lane while debounce still
held that query. Suggestions then re-fetched it and showed a spinner. Debounce
null while submitted, and skip queriesRequest until the new input settles.
The hold-clear scroll listener sat on the renderer root, which does not
scroll. Listen on the nearest overflow ancestor instead. Drop the unused
focusedVerses return. Content never read it.
@camrun91
camrun91 force-pushed the cl/ype-5766_search_ui branch from 1773708 to b29aaf2 Compare September 14, 2026 21:40
Widen useDebounce test props so null flush typechecks. Wait for the Reader
canvas before clicking Search. Revert human en.json edits and keep English
via t() defaultValue until platform-localization syncs bibleSearch* keys.
Comment thread packages/ui/src/i18n/locales/en.json
The previous CI fix copied en.json from the deleted search API tip, which still differed from main. That kept Locale Ownership red and broke version-picker and verse tests that assert main's English copy.
Unsafe integer endpoints stall `verse += 1` at 2^53 and oversized spans allocate huge arrays. Lock the intended rejection before the parser change.
Number.isInteger accepted 2^53 endpoints, so verse += 1 never advanced and search hits could hang. Reject non-safe integers and spans over 250 verses instead of expanding them.

@cameronapak cameronapak left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

YPE-5766

Summary

Standards: 0 must-fix. Spec: 10 must-fix. Primary concern: host navigation is unavailable and automatic scrolling clears selected-verse focus before arrival.

For Agents
  • CI: failing. Integration Tests reports 582 passing assertions and 11 unhandled rejections; the cause is not established. Other build, typecheck, lint, and unit-test checks pass.
  • Bot review: clear; earlier bot findings are resolved.
  • Event: REQUEST_CHANGES
  • HEAD: 9720ea4
  • Spec: the user-supplied artifact of the Search PRD, linked from parent YPE-5622.
  • Verification: 92 existing targeted Vitest tests passed. Three focused regression reproductions failed for result deduplication, stale suggestions, and wildcard fallback. Chromium confirmed automatic scrolling clears focus before arrival. Temporary reproduction fixtures were removed.

Written by Code Reviewer bot on behalf of Cam.

Comment thread packages/ui/src/components/bible-reader.tsx Outdated
Comment thread packages/ui/src/lib/use-transient-verse-focus.ts
Comment thread packages/hooks/src/internal/bible-search-session.ts
Comment thread packages/hooks/src/useBibleSearch.ts
Comment thread packages/ui/src/components/bible-reader-search.tsx
Comment thread packages/hooks/src/useBibleSearch.ts Outdated
Comment thread packages/ui/src/components/bible-reader-search.tsx Outdated
Comment thread packages/ui/src/components/bible-reader-search.tsx
Comment thread packages/hooks/src/internal/bible-search-session.ts Outdated
Comment thread packages/core/src/usfm-reference.ts
Comment thread .size-limit.js

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change allows for us to be able to easily add Zod to the UI package

@Dustin-Kelley Dustin-Kelley left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review posted by Claude (AI agent) on behalf of Dustin. Four inline comments below using Conventional Comments.

Comment thread packages/core/src/schemas/search.ts Outdated
Comment thread packages/hooks/src/utility/useDebounce.ts Outdated
Comment thread packages/hooks/src/internal/bible-search-session.ts Outdated
vReq?.versionId,
vReq?.query ?? '',
vReq?.pageToken ?? '',
props.bookIds,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): props.bookIds is part of the searchVerses query key, but the fetch never uses it — filtering is client-side in deriveSearchPhase.

Toggling the testament filter while a page is in flight changes the key, so TanStack abandons that request and fires an identical /v1/search-verses call under the new key; the first response is cached under a key that's never observed again.

Dropping props.bookIds from the key removes the redundant request with no behaviour change.

Posted by Claude on behalf of Dustin.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm keeping bookIds in this query key for this PR. You're right that it can duplicate a request, but removing it changes the agreed filter behavior: switching testament after a failed continuation must immediately clear the stale error and retry. Avoiding the extra request needs separate error-reset/retry handling rather than only removing the key.

Verification evidence
  • Coordinator-run counterexample: temporarily removed bookIds and ran pnpm --filter @youversion/platform-react-hooks exec vitest run src/useBibleSearch.test.tsx -t 'replaces a failed continuation'. The test failed: expected nextPage: loading, received nextPage: failed.
  • Restored bookIds in 7d6fe84. Full unit suite: 1437 passed, 2 live API tests skipped; 61 Chromium stories passed.
  • This retains the extra-request tradeoff; it does not implement request deduplication across testament filters.

Written by Coding Agent on behalf of Cam.

@abharms abharms left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the current head (77aa9e6) against YPE-5766, its parent ticket, the PR's stated behavior, the public navigation contract, and the existing review threads. I left four confirmed issues inline; the first three are blocking.

The exclusive browsing/submitted search lane and stale-response guards are especially well designed—they make concurrent suggestion/result behavior much easier to reason about. The transient-focus implementation also shows thoughtful accessibility work around focus timing, reduced motion, and preserving user input.

I did not rerun the suite locally; the PR's GitHub checks are green at this head.

Comment thread packages/hooks/src/utility/useDebounce.ts Outdated
Comment thread packages/ui/src/components/bible-reader.tsx
Comment thread packages/ui/src/components/bible-reader.tsx
Comment thread packages/hooks/src/internal/bible-search-session.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants