YPE-5440 / RNV2-2: Hybrid VerseOfTheDay (native chrome + DOM text) - #183
Dustin-Kelley wants to merge 15 commits into
Conversation
RNV2-2. Native Card, share, and YouVersion attribution wrap the DOM BibleTextView so scripture styling stays in WebView. Light/dark resolve on native before they cross the bridge. Share uses the native Share API. Public props are unchanged. The full-component DOM wrapper stays for RNV2-10. Co-authored-by: Dustin Kelley <Dustin-Kelley@users.noreply.github.com>
The share payload came from a separate plain-text fetch, and one failure left the share button disabled and the reference line blank for the life of the mount while the DOM view still painted the verse. The hook now exposes loadShareSource; the button is gated only on the passage id and a press refetches when the background fetch missed. Nothing mounts VerseOfTheDayDom after the hybrid rewrite, so remove its ImplKey and registerDefault. The DOM file stays for RNV2-10. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bmanquen
left a comment
There was a problem hiding this comment.
Two-axis review (standards + spec vs YPE-5440). Inline comments below mark what must be addressed before merging; everything else found was judgement-call level.
A failed VOTD request left a spinner with Share disabled. Split loading from failure so the card can recover. Co-authored-by: Cursor <cursoragent@cursor.com>
Native share still fetches and builds a payload for excluded, non-permitted, and language-filtered versions. Co-authored-by: Cursor <cursoragent@cursor.com>
Native header and Share fetched a version the DOM verse body would refuse. Share now uses the same permit, exclude, and language rules as the web SDK, with the provider lists as arguments. Co-authored-by: Cursor <cursoragent@cursor.com>
onShare currently fires on Expo web, which changes the public callback from the old DOM wrapper. Co-authored-by: Cursor <cursoragent@cursor.com>
The old wrapper left onShare unset on web so the Web Share flow ran. The hybrid chrome called the host callback on every platform. Co-authored-by: Cursor <cursoragent@cursor.com>
Hybrid VOTD already resolves through useTheme. The ADR still described the old WebView-owned system path. Co-authored-by: Cursor <cursoragent@cursor.com>
Language allowlists now check version metadata before fetching passage text. In-flight share results also key on the filter lists so a slower permissive request cannot restore a refused header or payload. Co-authored-by: Cursor <cursoragent@cursor.com>
Typecheck failed because renderHook's rerender requires the hook props argument. Match the existing wrapper pattern with rerender(undefined). Co-authored-by: Dustin Kelley <Dustin-Kelley@users.noreply.github.com>
Keep onShare native-only. On web the header still loads share text and uses navigator.share, or the clipboard when that API is missing. Co-authored-by: Cursor <cursoragent@cursor.com>
renderHook.rerender requires an argument under tsconfig.test.json, so the filter-tightening case never typechecked. Co-authored-by: Cursor <cursoragent@cursor.com>
…ouversion/platform-sdk-reactnative-expo into cursor/hybrid-votd-rnv2-2-b0c5
| ) { | ||
| setResult({ passageId, versionId, filters, data }) | ||
| } | ||
| return data |
There was a problem hiding this comment.
issue: A Share press can still send a version that the current filters refuse.
For Agents: reject a stale Share retry
If a press starts
loadShareSourceunder permissive provider filters and those filters tighten before the fetch settles,sameFilterspreventssetResult, but this unconditionalreturn datastill gives the old payload tohandleShare. That handler can then invoke the consumer callback, browser Share, or nativeShare.sharefor a now-refused version. Returnnullwhen the request snapshot no longer matchescurrentRef, and test an in-flight Share press after a filter change. The new hook test only checksshareSourcestate.
Written by Code Reviewer bot on behalf of Cam.
| const themeContext = useTheme() | ||
| const { t } = useSdkTranslation() | ||
| const resolvedTheme = useTheme(theme ?? background) | ||
| const [sampledDayOfYear] = useState(() => getDayOfYear(new Date())) |
There was a problem hiding this comment.
praise: Pinning the day when the card mounts keeps the verse and its Share text on the same date across midnight.
For Agents: pinned calendar day
The sampled day feeds native passage resolution and the DOM verse bridge instead of allowing each surface to resolve “today” independently.
Written by Code Reviewer bot on behalf of Cam.
Summary
Pilot / canonical hybrid VerseOfTheDay for YPE-5440 / RNV2-2.
Native chrome (Card surface, share button, YouVersion attribution, sun icon, title/reference) wraps the DOM
BibleTextViewfor the verse. Scripture stays in WebView for USFM/HTML/CSS. PublicVerseOfTheDayprops and exported types are unchanged.This is the quality gate before Phase 4 bulk: native chrome + Project A primitives + the native↔DOM bridge end to end.
IOS




Android


Hybrid split
Native
Card/Button/Text+ tokens)Share(or consumeronShare)useTheme(closes the ADR 0021 VOTD exception —systemresolves on native, not inside the WebView)DOM (unchanged scripture path)
packages/ui/src/dom/bible-text-view.tsxrenders the verselight | darkon the in-WebView provider (RNV2-4)--yv-reader-*CSSHighlightsPaint+ Controlled Highlights Latch)fetchBibleContent(no parallel client)Kept on purpose
packages/ui/src/dom/verse-of-the-day.tsxis not deleted. RNV2-10 removes the full-component wrapper.How to verify
Layer-3 coverage: render, light/dark tokens + bridge theme, native Share / consumer
onShare, embed defaults, and the highlights latch againstBibleTextViewDom.Example app: drop-in —
<VerseOfTheDay versionId={3034} />is the same public API.Screenshots
Skipped. The VM has no YouVersion app key (
apps/example/.envis not present), so a live light/dark capture would not render scripture.Test plan
pnpm lintGreptile Summary
This PR converts VerseOfTheDay into a hybrid component with native presentation around DOM-rendered scripture while preserving its public API.
Confidence Score: 5/5
The PR appears safe to merge.
No blocking failure remains.
Important Files Changed
Sequence Diagram
Reviews (9): Last reviewed commit: "Merge branch 'cursor/hybrid-votd-rnv2-2-..." | Re-trigger Greptile