diff --git a/.changeset/bible-card-footnote-press.md b/.changeset/bible-card-footnote-press.md new file mode 100644 index 00000000..941b5d17 --- /dev/null +++ b/.changeset/bible-card-footnote-press.md @@ -0,0 +1,4 @@ +--- +"@youversion/platform-react-ui": minor +--- +Add optional `onFootnotePress` callback to `BibleCard` for custom footnote handling (same pattern as `BibleReader`). diff --git a/packages/ui/src/components/bible-card.test.tsx b/packages/ui/src/components/bible-card.test.tsx index abc86d42..ca147137 100644 --- a/packages/ui/src/components/bible-card.test.tsx +++ b/packages/ui/src/components/bible-card.test.tsx @@ -2,8 +2,10 @@ * @vitest-environment jsdom */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { render, act, within } from '@testing-library/react'; +import { render, act, within, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { BibleCard } from './bible-card'; +import type { FootnoteData } from './verse'; import { usePassage, useVersion, useTheme } from '@youversion/platform-react-hooks'; import type { BiblePassage, BibleVersion } from '@youversion/platform-core'; @@ -119,3 +121,50 @@ describe('BibleCard - Delayed spinner', () => { ); }); }); + +describe('BibleCard - onFootnotePress callback', () => { + const mockPassageWithFootnote: BiblePassage = { + id: 'JHN.1', + content: `
5The light shines1:5 Or understood.
`, + reference: 'JHN.1', + }; + + beforeEach(() => { + vi.mocked(useTheme).mockReturnValue('light'); + vi.mocked(useVersion).mockReturnValue({ + version: mockVersion, + loading: false, + error: null, + refetch: vi.fn(), + }); + vi.mocked(usePassage).mockReturnValue({ + passage: mockPassageWithFootnote, + loading: false, + error: null, + refetch: vi.fn(), + }); + }); + + it('should call onFootnotePress when provided via BibleCard', async () => { + const onFootnotePress = vi.fn(); + + const { container } = render( + , + ); + + const button = await waitFor(() => { + const btn = container.querySelector('[data-verse-footnote="5"] button'); + expect(btn).not.toBeNull(); + return btn as HTMLButtonElement; + }); + + await userEvent.click(button); + + expect(onFootnotePress).toHaveBeenCalledTimes(1); + const data = onFootnotePress.mock.calls[0]![0] as FootnoteData; + expect(data.verseNum).toBe('5'); + expect(data.reference).toBe('JHN.1'); + expect(data.notes).toHaveLength(1); + expect(data.notes[0]).toContain('Or understood'); + }); +}); diff --git a/packages/ui/src/components/bible-card.tsx b/packages/ui/src/components/bible-card.tsx index 9d5dde6c..a2a52f50 100644 --- a/packages/ui/src/components/bible-card.tsx +++ b/packages/ui/src/components/bible-card.tsx @@ -1,6 +1,6 @@ import { usePassage, useVersion, useTheme } from '@youversion/platform-react-hooks'; import { DEFAULT_LICENSE_FREE_BIBLE_VERSION } from '@youversion/platform-core'; -import { BibleTextView } from './verse'; +import { BibleTextView, type FootnoteData } from './verse'; import { BibleAppLogoLockup } from './bible-app-logo-lockup'; import { BibleVersionPicker, type BibleVersionPickerPressData } from './bible-version-picker'; import { Button } from './ui/button'; @@ -37,6 +37,7 @@ export type BibleCardProps = { background?: 'light' | 'dark'; showVersionPicker?: boolean; onVersionPickerPress?: (data: BibleVersionPickerPressData) => void; + onFootnotePress?: (data: FootnoteData) => void; }; function BibleCardHeaderError(): React.ReactNode { @@ -127,6 +128,7 @@ export function BibleCard({ background, showVersionPicker = false, onVersionPickerPress, + onFootnotePress, }: BibleCardProps): React.ReactNode { // Controlled only when both versionId + onVersionChange are provided. // versionId alone seeds uncontrolled state, preserving backwards compatibility @@ -198,6 +200,7 @@ export function BibleCard({ loading: passageLoading, error: passageError, }} + onFootnotePress={onFootnotePress} />