Skip to content

WIP: YPE-2197: Extract standalone popover content components for native sheet rendering#222

Closed
cameronapak wants to merge 1 commit intomainfrom
YPE-2197-react-native-sdk-react-sdk-core-phase-3-1
Closed

WIP: YPE-2197: Extract standalone popover content components for native sheet rendering#222
cameronapak wants to merge 1 commit intomainfrom
YPE-2197-react-native-sdk-react-sdk-core-phase-3-1

Conversation

@cameronapak
Copy link
Copy Markdown
Collaborator

@cameronapak cameronapak commented May 1, 2026

Summary

  • Extract BibleChapterPickerContent, BibleVersionPickerContent, BibleReaderSettingsContent, and FootnoteContent as standalone exported components that can be rendered outside of popovers (e.g., in native bottom sheets via Expo DOM components)
  • Add onContentClick callbacks to BibleChapterPicker.Root, BibleVersionPicker.Root, and BibleReader.Root that intercept trigger clicks and pass content props to the callback instead of opening a popover
  • Add onFootnoteContentClick prop threaded through BibleTextViewVerse.HtmlBibleTextHtmlVerseFootnoteButton
  • Add UserMenu to BibleReader compound export
  • All content components are self-contained (call hooks internally, manage their own state)

Test plan

  • pnpm typecheck passes
  • pnpm lint passes
  • 63 unit tests pass
  • 99 integration tests pass (including "Search Resets After Selection" regression fix via openCount key)

Greptile Summary

This PR extracts BibleChapterPickerContent, BibleVersionPickerContent, BibleReaderSettingsContent, and FootnoteContent as standalone exported components so they can be rendered outside of popovers (e.g., in Expo DOM native bottom sheets). An onContentClick callback pattern is added to each Root component that intercepts trigger clicks and passes content props to the caller instead of opening a popover.

  • The background prop is part of the public API for all three new content components but is never applied inside the component implementations — consumers using background=\"dark\" in a native sheet will see no theming effect.
  • Both BibleChapterPicker.Trigger and BibleVersionPicker.Trigger replace <PopoverTrigger> with a <div onClick> when onContentClick is set, breaking keyboard accessibility.

Confidence Score: 3/5

Safe to merge after resolving the background theming gap in the standalone content components; accessibility issues should also be addressed.

A P1 finding (background prop part of public API but silently no-ops in all three content components) could mislead consumers of the new standalone API, particularly for the stated native-sheet use-case. Multiple P2 accessibility issues (div-based triggers) reinforce the need for a follow-up. Score sits at 3 to reflect the P1 API correctness gap.

packages/ui/src/components/bible-chapter-picker.tsx and packages/ui/src/components/bible-version-picker.tsx — background prop and keyboard-accessibility on the new div triggers.

Important Files Changed

Filename Overview
packages/ui/src/components/bible-chapter-picker.tsx Extracts BibleChapterPickerContent as standalone component and adds onContentClick bypass; background prop declared in public type but never applied inside the component, and div-based trigger lacks keyboard accessibility.
packages/ui/src/components/bible-version-picker.tsx Major refactor moving all picker state into BibleVersionPickerContent; background prop silently ignored; openCount key mechanism cleanly fixes search-reset regression; div trigger has same keyboard-accessibility gap.
packages/ui/src/components/bible-reader.tsx Extracts BibleReaderSettingsContent and adds onSettingsContentClick bypass; background prop unused in content component; _currentFontSize discarded without display or documentation.
packages/ui/src/components/verse.tsx Cleanly extracts FootnoteContent and threads onFootnoteContentClick through BibleTextView → Verse.Html → BibleTextHtml → VerseFootnoteButton; no issues found.
packages/ui/src/components/index.ts Correctly exports all new standalone content components and their prop types; no issues.
packages/ui/src/components/bible-chapter-picker.stories.tsx Adds BibleChapterPicker.Content to the existing story; trivial change, no issues.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Root["Root (onContentClick?)"]
    Root -->|"onContentClick provided"| CtxOnly["Context.Provider only\n(no Popover wrapper)"]
    Root -->|"no onContentClick"| PopoverRoot["Popover + Context.Provider"]

    CtxOnly --> Trigger
    PopoverRoot --> Trigger
    PopoverRoot --> Content["Compound Content\n(PopoverContent wrapper)"]

    Trigger{"onContentClick\nin context?"}
    Trigger -->|yes| DivBtn["div onClick\n→ calls onContentClick(contentProps)\n(native sheet caller renders StandaloneContent)"]
    Trigger -->|no| PopoverTrigger["PopoverTrigger\n(opens popover)"]

    Content --> StandaloneContent["Standalone Content Component\n(BibleChapterPickerContent /\nBibleVersionPickerContent /\nBibleReaderSettingsContent)"]

    DivBtn -.->|"consumer renders standalone"| StandaloneContent
Loading

Comments Outside Diff (3)

  1. packages/ui/src/components/bible-chapter-picker.tsx, line 422-431 (link)

    P2 Div trigger not keyboard-accessible

    When onContentClick is provided, BibleChapterPicker.Trigger replaces <PopoverTrigger> with a plain <div onClick>. A <div> is not in the tab order by default and receives no Enter/Space key events, so keyboard-only users cannot open the picker. Switch to <button type="button"> or add role="button", tabIndex={0}, and an onKeyDown handler to restore keyboard accessibility.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/ui/src/components/bible-chapter-picker.tsx
    Line: 422-431
    
    Comment:
    **Div trigger not keyboard-accessible**
    
    When `onContentClick` is provided, `BibleChapterPicker.Trigger` replaces `<PopoverTrigger>` with a plain `<div onClick>`. A `<div>` is not in the tab order by default and receives no `Enter`/`Space` key events, so keyboard-only users cannot open the picker. Switch to `<button type="button">` or add `role="button"`, `tabIndex={0}`, and an `onKeyDown` handler to restore keyboard accessibility.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code Fix in Cursor

  2. packages/ui/src/components/bible-version-picker.tsx, line 1380-1395 (link)

    P2 Same div-trigger accessibility gap in BibleVersionPicker.Trigger

    When onContentClick is set, BibleVersionPicker.Trigger also renders a <div onClick> wrapper without role, tabIndex, or keyboard handlers. The same <button type="button"> fix applies here.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/ui/src/components/bible-version-picker.tsx
    Line: 1380-1395
    
    Comment:
    **Same div-trigger accessibility gap in `BibleVersionPicker.Trigger`**
    
    When `onContentClick` is set, `BibleVersionPicker.Trigger` also renders a `<div onClick>` wrapper without `role`, `tabIndex`, or keyboard handlers. The same `<button type="button">` fix applies here.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code Fix in Cursor

  3. packages/ui/src/components/bible-reader.tsx, line 500-505 (link)

    P2 _currentFontSize received but not rendered

    currentFontSize is accepted in BibleReaderSettingsContentProps and destructured with an _ prefix signalling intentional non-use, yet no current-size indicator is shown in the UI. If the native-sheet consumer passes this to synchronise the displayed size with the reader's state, the silent discard could leave the sheet UI out of sync. Either render the value (e.g., as a label between the two A buttons) or document that it is intentionally unused.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/ui/src/components/bible-reader.tsx
    Line: 500-505
    
    Comment:
    **`_currentFontSize` received but not rendered**
    
    `currentFontSize` is accepted in `BibleReaderSettingsContentProps` and destructured with an `_` prefix signalling intentional non-use, yet no current-size indicator is shown in the UI. If the native-sheet consumer passes this to synchronise the displayed size with the reader's state, the silent discard could leave the sheet UI out of sync. Either render the value (e.g., as a label between the two A buttons) or document that it is intentionally unused.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code Fix in Cursor

Fix All in Claude Code Fix All in Cursor

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

---

### Issue 1 of 4
packages/ui/src/components/bible-chapter-picker.tsx:41-45
**`background` prop declared but silently ignored**

`BibleChapterPickerContentProps` exposes a `background` prop, but the component only destructures `versionId`, `defaultBook`, and `onSelectChapter``background` is never applied inside the JSX. The same issue exists in `BibleVersionPickerContent` (only destructures `versionId` / `onSelectVersion`) and `BibleReaderSettingsContent` (only destructures font-size/family state). When a consumer renders these in a native bottom sheet and passes `background="dark"`, no theming takes effect — the component will always render without a theme attribute on its wrapper.

Consider either adding a `data-yv-theme` wrapper div keyed to `background`, or removing the prop from the public type until it's implemented.

### Issue 2 of 4
packages/ui/src/components/bible-chapter-picker.tsx:422-431
**Div trigger not keyboard-accessible**

When `onContentClick` is provided, `BibleChapterPicker.Trigger` replaces `<PopoverTrigger>` with a plain `<div onClick>`. A `<div>` is not in the tab order by default and receives no `Enter`/`Space` key events, so keyboard-only users cannot open the picker. Switch to `<button type="button">` or add `role="button"`, `tabIndex={0}`, and an `onKeyDown` handler to restore keyboard accessibility.

```suggestion
      <button
        type="button"
        data-yv-sdk
        data-yv-theme={theme}
        onClick={() => onContentClick(contentProps)}
        className="yv:inline-flex yv:cursor-pointer"
      >
```

### Issue 3 of 4
packages/ui/src/components/bible-version-picker.tsx:1380-1395
**Same div-trigger accessibility gap in `BibleVersionPicker.Trigger`**

When `onContentClick` is set, `BibleVersionPicker.Trigger` also renders a `<div onClick>` wrapper without `role`, `tabIndex`, or keyboard handlers. The same `<button type="button">` fix applies here.

### Issue 4 of 4
packages/ui/src/components/bible-reader.tsx:500-505
**`_currentFontSize` received but not rendered**

`currentFontSize` is accepted in `BibleReaderSettingsContentProps` and destructured with an `_` prefix signalling intentional non-use, yet no current-size indicator is shown in the UI. If the native-sheet consumer passes this to synchronise the displayed size with the reader's state, the silent discard could leave the sheet UI out of sync. Either render the value (e.g., as a label between the two A buttons) or document that it is intentionally unused.

Reviews (1): Last reviewed commit: "feat(ui): extract standalone popover con..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

…ick callbacks for native sheet rendering

Extract BibleChapterPickerContent, BibleVersionPickerContent, BibleReaderSettingsContent, and FootnoteContent as standalone exported components. Add onContentClick/onFootnoteContentClick callbacks to intercept popover clicks for rendering in native bottom sheets via Expo DOM components.

- BibleChapterPickerContent: self-contained, calls useBooks internally, manages search/accordion state
- BibleVersionPickerContent: self-contained, calls useVersions/useLanguages internally, manages search/filter/language state
- BibleReaderSettingsContent: exported with font size/family controls
- FootnoteContent: renders footnote list with verse context, onFootnoteContentClick threaded through BibleTextView → Verse.Html → BibleTextHtml → VerseFootnoteButton
- Added UserMenu to BibleReader compound export
- All compound components support onContentClick prop to skip popover rendering
- Added openCount key to force fresh mount on version picker reopen
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 1, 2026

⚠️ No Changeset found

Latest commit: 0177791

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Comment on lines +41 to +45
if (searchQuery.trim() === '') return books.data;
return books.data.filter((book) =>
book.title?.toLowerCase().includes(searchQuery.toLowerCase()),
);
}, [books?.data, searchQuery]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 background prop declared but silently ignored

BibleChapterPickerContentProps exposes a background prop, but the component only destructures versionId, defaultBook, and onSelectChapterbackground is never applied inside the JSX. The same issue exists in BibleVersionPickerContent (only destructures versionId / onSelectVersion) and BibleReaderSettingsContent (only destructures font-size/family state). When a consumer renders these in a native bottom sheet and passes background="dark", no theming takes effect — the component will always render without a theme attribute on its wrapper.

Consider either adding a data-yv-theme wrapper div keyed to background, or removing the prop from the public type until it's implemented.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/components/bible-chapter-picker.tsx
Line: 41-45

Comment:
**`background` prop declared but silently ignored**

`BibleChapterPickerContentProps` exposes a `background` prop, but the component only destructures `versionId`, `defaultBook`, and `onSelectChapter``background` is never applied inside the JSX. The same issue exists in `BibleVersionPickerContent` (only destructures `versionId` / `onSelectVersion`) and `BibleReaderSettingsContent` (only destructures font-size/family state). When a consumer renders these in a native bottom sheet and passes `background="dark"`, no theming takes effect — the component will always render without a theme attribute on its wrapper.

Consider either adding a `data-yv-theme` wrapper div keyed to `background`, or removing the prop from the public type until it's implemented.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Cursor

@cameronapak cameronapak changed the title YPE-2197: Extract standalone popover content components for native sheet rendering WIP: YPE-2197: Extract standalone popover content components for native sheet rendering May 1, 2026
@cameronapak cameronapak marked this pull request as draft May 1, 2026 21:02
@cameronapak cameronapak closed this May 4, 2026
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.

1 participant