Skip to content

YPE-2256: abstract BibleChapterPicker content + override#225

Merged
cameronapak merged 6 commits intomainfrom
YPE-2256-react-sdk-abstract-bible-chapter-picker-content-view-for-rn-expo-sdk
May 5, 2026
Merged

YPE-2256: abstract BibleChapterPicker content + override#225
cameronapak merged 6 commits intomainfrom
YPE-2256-react-sdk-abstract-bible-chapter-picker-content-view-for-rn-expo-sdk

Conversation

@Dustin-Kelley
Copy link
Copy Markdown
Collaborator

@Dustin-Kelley Dustin-Kelley commented May 5, 2026

Summary

  • Export BibleChapterPicker.Content for standalone rendering (Expo DOM / native sheet).
  • Add onChapterPickerPress to intercept trigger presses and suppress popover.
  • Add unit tests and a changeset for @youversion/platform-react-ui.

Test plan

  • pnpm --filter @youversion/platform-react-ui test

Made with Cursor

Greptile Summary

This PR extracts the book-list and search UI into a standalone BibleChapterPicker.Content component and adds an onChapterPickerPress prop to Root that intercepts trigger presses and suppresses the built-in Popover, enabling consumers to render the picker inside a native bottom sheet or Expo DOM component.

  • Content extraction: book accordion, chapter buttons, and search input are moved from an inline PopoverContent render into a reusable Content component that accepts an optional onRequestClose callback; popover mode passes () => setIsPopoverOpen(false), standalone mode omits it.
  • onChapterPickerPress override: when set on Root, the Trigger renders a plain button (or cloneElement for asChild) and calls the callback with { book, chapter, versionId } instead of opening the Popover.
  • New exports: BibleChapterPicker.Content, BibleChapterPickerContentProps, and BibleChapterPickerPressData are exported from the package index; a minor changeset is included.

Confidence Score: 5/5

Safe to merge — the refactor is well-scoped, the existing popover path is preserved faithfully, and the new standalone path is exercised by the added tests.

The core popover flow is unchanged in behavior; Content is a mechanical extraction of the same JSX that was previously inlined. The override path is additive and guarded by a simple conditional. No data-loss or broken-contract scenarios were found in the changed code paths.

packages/ui/src/components/bible-chapter-picker.tsx — the untracked setTimeout in scrollToCurrentBook is worth addressing before this becomes a source of multiple simultaneous scroll attempts.

Important Files Changed

Filename Overview
packages/ui/src/components/bible-chapter-picker.tsx Major refactor: extracts book-list/search UI into a standalone Content component, adds onChapterPickerPress override path that bypasses the Popover, and exposes Content on the BibleChapterPicker namespace. One new finding: untracked timer in scrollToCurrentBook.
packages/ui/src/components/bible-chapter-picker.test.tsx New test file covering onChapterPickerPress callback args, popover suppression when override is set, and default popover-open behaviour; ResizeObserver is correctly stubbed for jsdom.
packages/ui/src/components/index.ts Exports the two new public types (BibleChapterPickerContentProps, BibleChapterPickerPressData) alongside existing exports.
.changeset/quick-baboons-stare.md Minor-version changeset for @youversion/platform-react-ui describing the new Content export and onChapterPickerPress addition.
packages/hooks/vitest.config.ts Adds exclude for dist and node_modules to the hooks package vitest config to prevent built artifacts from being picked up by the test runner.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User clicks Trigger] --> B{onChapterPickerPress set on Root?}
    B -- Yes --> C[handlePress called]
    C --> D[props.onClick fired]
    D --> E[scrollToCurrentBook called]
    E --> F[onChapterPickerPress callback called with book/chapter/versionId]
    F --> G[Consumer renders native sheet / Expo DOM]
    G --> H[BibleChapterPicker.Content rendered standalone]
    H --> I{User selects chapter}
    I --> J[setBook + setChapter, setSearchQuery cleared, onRequestClose called]
    B -- No --> K[handleOpenPopover called]
    K --> L[props.onClick fired]
    L --> M[scrollToCurrentBook called]
    M --> N[Popover opens, Content rendered inside PopoverContent]
    N --> O{User selects chapter}
    O --> P[setBook + setChapter, setSearchQuery cleared, setIsPopoverOpen false]
Loading

Fix All in Claude Code Fix All in Cursor

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/ui/src/components/bible-chapter-picker.tsx:128-141
The timer returned by `setTimeout` inside `scrollToCurrentBook` is never stored, so it cannot be cancelled before the next call. If the user clicks the trigger in quick succession, multiple 200 ms timers accumulate and all fire, each calling `scrollIntoView`. The `useEffect` block just below this function correctly uses `clearTimeout` to cancel the previous timer — the same pattern should be applied here using a ref.

```suggestion
  const scrollToCurrentBookTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const scrollToCurrentBook = () => {
    if (book) {
      setExpandedBook(book);
      if (scrollToCurrentBookTimerRef.current !== null) {
        clearTimeout(scrollToCurrentBookTimerRef.current);
      }
      scrollToCurrentBookTimerRef.current = setTimeout(() => {
        scrollToCurrentBookTimerRef.current = null;
        const element = bookElementsRef.current[book];
        if (element && typeof element.scrollIntoView === 'function') {
          element.scrollIntoView({
            behavior: 'smooth',
            block: 'start',
          });
        }
      }, 200);
    }
  };
```

Reviews (4): Last reviewed commit: "Fix scrolling and default book in Bible ..." | Re-trigger Greptile

Context used:

  • Rule used - Always invalidate existing timers before creating ... (source)

Learned From
lifechurch/youversion/user-applications/mobile/bible-ios#4801

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 5, 2026

🦋 Changeset detected

Latest commit: de4d87f

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-react-ui Minor
vite-react Patch
@youversion/platform-core Minor
@youversion/platform-react-hooks Minor

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

@cameronapak cameronapak marked this pull request as ready for review May 5, 2026 18:02
Comment thread packages/ui/src/components/bible-chapter-picker.tsx
Comment thread packages/ui/src/components/bible-chapter-picker.tsx
Comment thread packages/ui/src/components/bible-chapter-picker.tsx
Excludes dist and node_modules from Vitest tests to prevent unexpected
behavior.
Add checks for `scrollIntoView` availability and set a default book for
the picker to improve user experience and robustness.
Copy link
Copy Markdown
Collaborator

@cameronapak cameronapak left a comment

Choose a reason for hiding this comment

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

LGTM!

Comment thread packages/ui/src/components/bible-chapter-picker.test.tsx
@cameronapak cameronapak merged commit e5a8681 into main May 5, 2026
6 checks passed
@cameronapak cameronapak deleted the YPE-2256-react-sdk-abstract-bible-chapter-picker-content-view-for-rn-expo-sdk branch May 5, 2026 19:30
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.

2 participants