Skip to content

feat(ui): swap the serif font from Source Serif 4 to Untitled Serif (YPE-1350, YPE-1910) - #304

Open
cameronapak wants to merge 8 commits into
mainfrom
ype-1350-react-sdk-biblereader-use-correct-serif-font-swap-source-serif-for-untitled
Open

feat(ui): swap the serif font from Source Serif 4 to Untitled Serif (YPE-1350, YPE-1910)#304
cameronapak wants to merge 8 commits into
mainfrom
ype-1350-react-sdk-biblereader-use-correct-serif-font-swap-source-serif-for-untitled

Conversation

@cameronapak

@cameronapak cameronapak commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Warning

YPE-1350 | YPE-1910

What problems was I solving

The SDK's serif face was Source Serif 4, a Google Fonts stand-in adopted when ADR-0001 pulled the hardcoded brand @font-face blocks out of the SDK. The BibleReader has therefore never rendered in YouVersion's brand serif.

ADR-0001's finding was about delivery, not the typeface: a hardcoded @font-face pointing at a CDN woff2 puts the file in front of third-party developer apps with nothing in the SDK able to gate it. So it set one condition for bringing a brand font back — load it via /v1/fonts/{font_id}/stylesheet, which requires an app key. Untitled Serif now does exactly that.

Shipped, this means: the BibleReader and every other serif surface render in Untitled Serif, delivered from the Fonts API using the app key consumers already supply — no font file in the repo, no new prop, no setup. A consumer who blocks the new hosts falls back to Source Serif 4 with no layout break, so the downside case is exactly today's behavior.

The sans stack is untouched and stays 'Inter', sans-serif. This is a serif-only change.

What user-facing changes did I ship

  • packages/core/src/styles/theme.css--yv-font-serif becomes 'Untitled Serif', 'Source Serif 4', serif, so every serif surface follows at once: BibleReader body text, the Bible card, BibleText, the version-picker abbreviation tile, footnotes, chapter headings, and the lg Verse of the Day card (this is YPE-1910's scope, done in the same pass)
  • packages/ui/src/components/YouVersionProvider.tsxnew outbound request. The provider now renders a hoisted <link rel="stylesheet"> to https://api.youversion.com/v1/fonts/1/stylesheet, plus woff2 fetches from cdn.youversion.com. No new prop and no opt-out
  • packages/ui/src/components/bible-reader.tsx — the reader's default font changes to Untitled Serif, and readers whose saved preference is the old Source Serif stack are migrated on load so the picker still shows serif as active
  • packages/ui/src/i18n/locales/en.json — the font picker button reads "Untitled" instead of "Source Serif" (same in es / fr — a proper noun, so it isn't translated). These three edits are the blocking CI failure — see Open item
  • packages/ui/README.mdstrict-CSP consumers must allowlist https://api.youversion.com in style-src and https://cdn.youversion.com in font-src. This also removes a stale storage.googleapis.com entry for a host the SDK no longer calls
  • .changeset/untitled-serif-via-fonts-api.md — minor across all three packages (new request + default-font change, so not a patch)

How I implemented it

Five commits. The walkthrough artifact has the same journey with inline diffs.

1 · Load the font, move the tokens (7607cb5)

  • packages/ui/src/lib/yv-fonts.tsx (new) — builds https://{apiHost}/v1/fonts/1/stylesheet?app_key={key} and renders <link rel="stylesheet" precedence="yv-sdk-fonts">. This is the SDK's first runtime-value-dependent stylesheet: the URL needs the app key, which is only known at render time, so it can't live in the build-time-frozen __YV_STYLES__ blob. React 19 hoists the link into <head> and dedupes by href, so multiple providers still yield one link. Returns null on a missing/whitespace key — no key, nothing to 401
  • YouVersionProvider.tsx — mounted after the MissingAppKey guard, so only the has-a-key branch requests it
  • theme.css + global.css — the serif stack is declared twice and cannot be an alias: core can't import Tailwind, and @theme inline values are inlined into utilities rather than emitted as runtime custom properties. Both got the same literal, both got comments saying so
  • font-tokens.test.ts (new) — reads both CSS files off disk and asserts the two declarations stay byte-identical, that Untitled Serif is first, and that Source Serif 4 is still in the stack and still @import-ed. Nothing else catches drift; jsdom never loads either sheet
  • yv-fonts.test.tsx (new) — URL shape, percent-encoding, custom apiHost, missing key, dedupe across two roots. The notable assertion is that children still commit: React can suspend a commit on <link precedence> until the sheet loads and jsdom never fires load, which would have meant mounting the provider could blank a consumer's tree

2 · Move the reader (03f6aca)

The token swap alone can't reach reader body text. bible-reader.tsx writes --yv-reader-font-family inline from its own state, and bible-reader.css applies it to every descendant — since that inline property is always defined, it wins over --yv-font-serif. So the reader needed its own changes:

  • verse-html-utils.ts — adds UNTITLED_SERIF_FONT; SOURCE_SERIF_FONT is @deprecated but kept, because the migration needs the literal to compare against
  • bible-reader.tsx — the hydrate step maps exactly one legacy value forward: savedFontFamily === SOURCE_SERIF_FONT ? UNTITLED_SERIF_FONT : savedFontFamily. Deliberately not validation — FontFamily is (string & {}) on purpose, so a host-supplied defaultFontFamily="Georgia" must still round-trip. Without the migration, a reader who'd already picked serif would reload to a picker with neither button active
  • bible-card.tsx — passes fontFamily explicitly rather than inheriting the token, so it needed the same swap
  • bible-reader.test.tsx — two new hydrate tests (migrate the legacy value; leave a non-legacy value alone)
  • bible-reader.stories.tsxLoadsSavedPreferencesFromLocalStorage still seeds the legacy value, then asserts the migrated result on the CSS custom property, in localStorage, and on the active picker button

3 · Record the decision (65c8815)

4 · Review passes (f6a53a2, c7e3ebb)

  • Public-repo hygiene. Both ADRs publish with this repo, so the licensing narrative came out of both — including ADR-0003's CDN probe table, which printed an unauthenticated font URL and a compliance argument that don't belong in a public repo
  • Removed the other brand font entirely (ADR-0001, ADR-0003, theme.css, global.css, font-tokens.test.ts). It documented a decision about a font the SDK doesn't use. Verified it never shipped: changeset 2ba9e6d added it and 0d184fc reverted it, both landing in 2.2.0, so the released package never carried it. Anything implying Untitled Serif is not cleared came out too. Two bible-chapter-picker.test.tsx test names still referenced it while asserting only size and weight — renamed to what they check
  • Scoped the suspense claim. The comments in yv-fonts.tsx / yv-fonts.test.tsx asserted React "only suspends for stylesheets inserted during a transition." React's docs say the component rendering a precedence stylesheet suspends while it loads, with no transition caveat. The test proves the synchronous path only, so it now says that and flags the transition path as uncovered — a latency risk on a transition-driven mount, not a hang, since failures settle too
  • Covered YvFonts' own guard. The missing-key test routes through the provider's MissingAppKey branch, so YvFonts' !appKey?.trim() guard never executed. Now tested directly for undefined / empty / whitespace, and the leaked console.error spy is restored
  • README: dropped the font-display: swap claim. That property comes from a stylesheet the Fonts API authors, not this SDK

Verified against the endpoint directly: GET /v1/fonts/1/stylesheet returns 401 Failed to resolve API Key with no key and 401 Invalid ApiKey with ?app_key=bogus — so the query-param form the SDK builds is accepted by the gateway.

Deviations from the plan

Plan: 04-structure-outline-untitled-serif-swap.md

Implemented as planned

  • <YvFonts /> matches the plan's snippet exactly — hardcoded font id 1, apiHost default, precedence="yv-sdk-fonts", null on empty key
  • Both token declarations, the drift-guard test, the reader default + migration + picker label, the i18n key rename, ADR-0003 and the ADR-0001 status update, the README CSP section, and the changeset

Deviations/surprises

  • Reader body scope moved from Phase 1 to Phase 2. The outline originally expected the token swap to change reader body text, then corrected itself in-document once the inline --yv-reader-font-family pin was found. The code follows the corrected plan. Not an implementation deviation — a plan self-correction
  • The migration unit test doesn't assert --yv-reader-font-family. Reaching that property requires rendering <BibleReader.Content />, which calls usePassage and throws YouVersion context not found — that test file mocks the hooks package but renders no provider. The custom-property assertion lives in the story instead. Pre-flagged in the plan
  • ADR-0003 shipped substantially shorter than drafted. The plan called for an ADR recording the full rationale; review established that this repo is public, so the licensing narrative and a CDN probe table were cut. What remains is what the code depends on
  • The i18n step is now known to be wrong as planned. The outline said to rename the key in all three locale files directly. Repo policy says those files are upstream-owned — see Open item

Additions not in plan

  • font-tokens.test.ts also guards the sans token pair for drift, not just serif — same pattern, no reason to leave the other half unguarded
  • The migration story additionally asserts the migrated value was re-persisted to localStorage, beyond the plan's "assert the migrated one on the CSS property"
  • The c7e3ebb docs cleanup was not planned work; it came out of review

Items planned but not implemented

None.

Open item — locale ownership

This is the one red check. .github/scripts/check-locale-ownership.sh fails any PR touching packages/ui/src/i18n/locales/** unless it's a platform-localization sync PR. This PR renames sourceSerifFontNameuntitledSerifFontName in all three.

It's a chicken-and-egg, and both halves were reproduced locally: revert the locale files and i18n Check fails instead, because bible-reader.tsx calls t('untitledSerifFontName') and the key wouldn't exist — that check hard-fails on a t() reference missing from en.json.

The only clean path is the documented one in docs/i18n-guidelines.md:

  1. Add react.untitledSerifFontName upstream in platform-localization (sources/common/en.json)
  2. Merge there → distribute-react.yml opens a chore/localization-sync-react-* PR here
  3. Rebase this PR and drop the three locale edits

Until that lands, this PR can't go green either way. Removing react.sourceSerifFontName upstream should be a follow-up after this merges, not part of step 1 — removing it while main still calls t('sourceSerifFontName') would turn i18n Check red on main.

Not changed on purpose

  • packages/{ui,core,hooks}/CHANGELOG.md still carry the original 2.2.0 entries, including the font naming this PR cleaned out of the ADRs. Rewriting shipped release notes falsifies the record
  • ADR-0001 keeps its …-pending-licensing.md filename, even though the title no longer says that. Three published CHANGELOG entries link to that path and renaming would break them. Happy to rename if you'd rather take the dead links

How to verify it

git fetch origin ype-1350-react-sdk-biblereader-use-correct-serif-font-swap-source-serif-for-untitled
git checkout ype-1350-react-sdk-biblereader-use-correct-serif-font-swap-source-serif-for-untitled
pnpm install && pnpm build

Manual Testing

  • pnpm dev:web with a real app key → BibleReader body text renders Untitled Serif (not Source Serif 4). DevTools → Network shows one request to api.youversion.com/v1/fonts/1/stylesheet and woff2 fetches from cdn.youversion.com
  • Open reader settings → the serif button reads "Untitled" and is active by default
  • Seed the legacy preference, reload, confirm it migrates:
    localStorage.setItem('youversion-platform:reader:font-family', '"Source Serif 4", serif') → after reload the value is the Untitled stack and the picker still shows serif active
  • Pass a custom defaultFontFamily="Georgia", pick it, reload → still Georgia (migration must not clobber host values)
  • Block api.youversion.com (DevTools request blocking or a strict CSP) → serif text falls back to Source Serif 4 with no layout break
  • Bible card, BibleText, footnotes, chapter headings, and the lg VOTD card all render Untitled Serif (YPE-1910 scope)
  • Apply the README's CSP block verbatim in a scratch host app and confirm nothing is blocked

Automated Tests

pnpm test        # 30 files / 370 unit tests
pnpm typecheck
pnpm lint
pnpm build

Description for the changelog

Swap the SDK's serif face from Source Serif 4 to Untitled Serif, YouVersion's brand serif, loaded from the YouVersion Fonts API — strict-CSP consumers must allowlist api.youversion.com (style-src) and cdn.youversion.com (font-src).

Greptile Summary

The PR adopts Untitled Serif as the SDK-wide serif face.

  • Loads the font stylesheet through the YouVersion Fonts API using the provider’s app key.
  • Updates shared font tokens, Bible Reader defaults, saved-preference migration, and serif picker behavior.
  • Documents the required CSP origins and architectural decision.
  • Adds coverage for stylesheet injection, token consistency, and preference migration.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported locale-ownership issue was resolved by removing locale files from this PR after the synchronized English key landed.

Important Files Changed

Filename Overview
packages/ui/src/lib/yv-fonts.tsx Adds app-key-authorized loading of the Untitled Serif stylesheet with React resource hoisting and deduplication.
packages/ui/src/components/YouVersionProvider.tsx Mounts the font resource loader only after the existing missing-app-key guard.
packages/ui/src/components/bible-reader.tsx Changes the reader’s default and picker option to Untitled Serif and migrates the exact legacy preference.
packages/ui/src/lib/verse-html-utils.ts Defines the new serif stack while retaining the legacy constant for preference migration.
packages/core/src/styles/theme.css Promotes Untitled Serif in the shared core serif token while preserving Source Serif 4 as fallback.
packages/ui/src/styles/global.css Mirrors the updated serif stack in the UI Tailwind theme.
packages/ui/src/styles/font-tokens.test.ts Guards consistency between the duplicated core and UI font tokens.
packages/ui/README.md Documents the new stylesheet and font CDN origins required by strict CSP configurations.

Sequence Diagram

sequenceDiagram
  participant App as Consumer App
  participant Provider as YouVersionProvider
  participant FontsAPI as Fonts API
  participant CDN as Font CDN
  Provider->>FontsAPI: Request stylesheet with app key
  FontsAPI-->>Provider: "Untitled Serif @font-face stylesheet"
  Provider->>CDN: Fetch referenced woff2 files
  CDN-->>Provider: Untitled Serif font data
  Provider-->>App: Render serif surfaces with fallback stack
Loading

Reviews (6): Last reviewed commit: "Merge branch 'main' into ype-1350-react-..." | Re-trigger Greptile

@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: efc2e24

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/ui/src/i18n/locales/en.json Outdated
@cameronapak cameronapak self-assigned this Jul 28, 2026
Comment thread docs/adr/0003-adopt-untitled-serif-via-fonts-api.md Outdated
@cameronapak cameronapak changed the title feat(ui): swap the reader serif from Source Serif 4 to Untitled Serif (YPE-1350, YPE-1910) WIP: feat(ui): swap the reader serif from Source Serif 4 to Untitled Serif (YPE-1350, YPE-1910) Jul 29, 2026
Comment thread docs/adr/0001-revert-brand-fonts-pending-licensing.md Outdated
Comment thread docs/adr/0001-revert-brand-fonts-pending-licensing.md Outdated
Comment thread docs/adr/0001-revert-brand-fonts-pending-licensing.md Outdated
Comment thread docs/adr/0003-adopt-untitled-serif-via-fonts-api.md Outdated
Comment thread packages/core/src/styles/theme.css
cameronapak added a commit that referenced this pull request Jul 29, 2026
Review feedback on PR #304. Aktiv Grotesk was never published — it landed in a
changeset and was reverted before release — so naming it in the ADRs and style
comments documents a decision about a font we do not use and never shipped.
Untitled Serif is cleared, so anything implying otherwise is wrong too.

- ADR-0001: retitle without "pending licensing", drop the Aktiv Grotesk bullet
  and the licensing narrative. What remains is the decision the code actually
  depends on: a hardcoded @font-face is the wrong delivery pattern for an SDK
  that renders inside third-party apps, so brand fonts load from
  /v1/fonts/{font_id}/stylesheet. Reduced from two re-introduction conditions
  to that one.
- ADR-0003: drop the Aktiv Grotesk mentions and the "licensing is cleared"
  paragraph; state the sans stack is simply unchanged.
- theme.css / global.css / font-tokens.test.ts: same, in the comments.
- bible-chapter-picker.test.tsx: two test names still said "Aktiv" while
  asserting only size and weight. Renamed to what they check.

Filename kept as 0001-revert-brand-fonts-pending-licensing.md so the three
published CHANGELOG links keep resolving; those changelogs are release history
and are left as-is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cameronapak cameronapak changed the title WIP: feat(ui): swap the reader serif from Source Serif 4 to Untitled Serif (YPE-1350, YPE-1910) feat(ui): swap the serif font from Source Serif 4 to Untitled Serif (YPE-1350, YPE-1910) Jul 29, 2026
cameronapak added a commit that referenced this pull request Jul 30, 2026
Review feedback on PR #304. Aktiv Grotesk was never published — it landed in a
changeset and was reverted before release — so naming it in the ADRs and style
comments documents a decision about a font we do not use and never shipped.
Untitled Serif is cleared, so anything implying otherwise is wrong too.

- ADR-0001: retitle without "pending licensing", drop the Aktiv Grotesk bullet
  and the licensing narrative. What remains is the decision the code actually
  depends on: a hardcoded @font-face is the wrong delivery pattern for an SDK
  that renders inside third-party apps, so brand fonts load from
  /v1/fonts/{font_id}/stylesheet. Reduced from two re-introduction conditions
  to that one.
- ADR-0003: drop the Aktiv Grotesk mentions and the "licensing is cleared"
  paragraph; state the sans stack is simply unchanged.
- theme.css / global.css / font-tokens.test.ts: same, in the comments.
- bible-chapter-picker.test.tsx: two test names still said "Aktiv" while
  asserting only size and weight. Renamed to what they check.

Filename kept as 0001-revert-brand-fonts-pending-licensing.md so the three
published CHANGELOG links keep resolving; those changelogs are release history
and are left as-is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cameronapak
cameronapak force-pushed the ype-1350-react-sdk-biblereader-use-correct-serif-font-swap-source-serif-for-untitled branch from c7e3ebb to b24b9a1 Compare July 30, 2026 15:27
cameronapak and others added 7 commits July 30, 2026 10:41
…-1910)

Serif stack becomes 'Untitled Serif', 'Source Serif 4', serif in both
declarations — core's --yv-font-serif and ui's @theme inline --font-serif.
They are literal duplicates, not aliases, so font-tokens.test.ts now guards
them against drift (the first test to assert a font token's value).

Delivery is a new <YvFonts /> rendered from YouVersionProvider: a React 19
hoisted <link> to /v1/fonts/1/stylesheet, the gated endpoint ADR-0001 named
as the required consumption pattern. This is the SDK's first runtime-value-
dependent stylesheet — the URL needs the app key, which __YV_STYLES__ cannot
know at build time. It renders only in the normal branch; no key, no font.

Source Serif 4 stays loaded as the fallback, so nothing regresses when the
request is blocked or the host has no key.

Reader body text still renders Source Serif 4: Verse.Html sets
--yv-reader-font-family inline from the reader's own state, which shadows the
token. Phase 2 changes that constant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eference (YPE-1350)

The reader pins its own font: Verse.Html sets --yv-reader-font-family inline
from component state, which shadows the CSS token. So the Phase 1 stack change
could not reach passage body text until the constant behind that inline value
changed. This is that change.

- UNTITLED_SERIF_FONT is the new default; SOURCE_SERIF_FONT stays exported as
  @deprecated because the hydrate-time migration still needs to recognize it.
- Returning readers who chose serif before this shipped stored the old stack.
  Without mapping it forward they would hydrate to a value matching neither
  picker button — no button active, and Source Serif 4 forever. The migration
  is deliberately narrow rather than full validation: FontFamily is an open
  type on purpose, so a host passing defaultFontFamily="Georgia" must still
  round-trip. A test covers that non-legacy values pass through untouched.
- bible-card.tsx had the same inline pin hardcoded; swapped too. YPE-1910 names
  the Bible card explicitly.
- Locale files trade sourceSerifFontName for untitledSerifFontName ("Untitled",
  per the ticket wording). They are SDK-private, so removal is safe.

Verified in Chrome: body text renders Untitled Serif, picker shows "Untitled"
active, a seeded legacy value migrates and re-persists, and Inter survives a
reload unmigrated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…350)

ADR-0001 is Accepted and names two conditions for re-introducing brand fonts.
Shipping the font without touching it would leave the repo's own documentation
contradicting its code.

ADR-0003 records both conditions as met, and is deliberately blunt about what
the access control actually is: gated discovery plus revocable CDN URLs, not
file-level authentication. ADR-0001's finding that the woff2 is publicly
downloadable is unchanged and still true — what changed is the reading of the
licence constraint, which is YouVersion's to interpret. Saying so keeps the two
ADRs consistent; the alternative was a quiet contradiction.

The sign-off is verbal, from Klim directly, relayed and confirmed by Cameron Pak
on 2026-07-28. The ADR names it as verbal rather than implying a paper trail
exists, and says to amend if written confirmation surfaces.

Aktiv Grotesk stays reverted; ADR-0001 is superseded in part only.

Also: the README's CSP section was stale — it still listed storage.googleapis.com
for Aktiv Grotesk, which no longer ships. Replaced with the hosts actually used
now. That section is the answer for strict-CSP consumers, since there is
deliberately no opt-out prop.

Changeset is minor across all three packages (core's CSS changes too) and calls
out the new outbound request, the CSP entries, and the default font change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e claim

This repo is public and both ADRs are published with it. Strip the licensing
narrative from ADR-0001 and ADR-0003 down to what the code needs to know:
which face is cleared, and that it must be served by the Fonts API rather than
shipped in the repo. Licensing specifics are tracked internally.

Also drop ADR-0003's CDN probe table, which published an unauthenticated font
URL and a compliance argument that don't belong in a public repo.

Code changes:

- yv-fonts.tsx / yv-fonts.test.tsx: the comments asserted React "only suspends
  for stylesheets inserted during a transition". React's docs say the component
  rendering a `precedence` stylesheet suspends while it loads, without scoping
  that to transitions. The test proves the synchronous path only, so say that
  and flag the transition path as uncovered.
- yv-fonts.test.tsx: the missing-key test goes through the provider's
  MissingAppKey guard, so YvFonts' own guard was never executed. Cover it
  directly for undefined / empty / whitespace keys, and restore the console
  spy it left installed.
- README: drop the `font-display: swap` claim. That property comes from a
  stylesheet the Fonts API authors, not this SDK, so we can't promise it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review feedback on PR #304. Aktiv Grotesk was never published — it landed in a
changeset and was reverted before release — so naming it in the ADRs and style
comments documents a decision about a font we do not use and never shipped.
Untitled Serif is cleared, so anything implying otherwise is wrong too.

- ADR-0001: retitle without "pending licensing", drop the Aktiv Grotesk bullet
  and the licensing narrative. What remains is the decision the code actually
  depends on: a hardcoded @font-face is the wrong delivery pattern for an SDK
  that renders inside third-party apps, so brand fonts load from
  /v1/fonts/{font_id}/stylesheet. Reduced from two re-introduction conditions
  to that one.
- ADR-0003: drop the Aktiv Grotesk mentions and the "licensing is cleared"
  paragraph; state the sans stack is simply unchanged.
- theme.css / global.css / font-tokens.test.ts: same, in the comments.
- bible-chapter-picker.test.tsx: two test names still said "Aktiv" while
  asserting only size and weight. Renamed to what they check.

Filename kept as 0001-revert-brand-fonts-pending-licensing.md so the three
published CHANGELOG links keep resolving; those changelogs are release history
and are left as-is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR 0003 was taken by the locale-ownership-gate ADR merged in #308.
Renames the file and heading, updates cross-references in ADR-0001,
the changeset, theme.css, global.css, and yv-fonts.tsx.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#306

The rename now lives in platform-localization (merged to main in #306),
so the feature PR no longer edits the upstream-owned locale files. The
picker resolves t('untitledSerifFontName') from main's bundle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cameronapak
cameronapak force-pushed the ype-1350-react-sdk-biblereader-use-correct-serif-font-swap-source-serif-for-untitled branch from b24b9a1 to a374c35 Compare July 30, 2026 15:43
@cameronapak

Copy link
Copy Markdown
Collaborator Author

Ready for review @jaredhightower-youversion or @camrun91

P.S. Dustin and I are out of office the rest of this week due to being over hours and will resume on Monday

@camrun91

Copy link
Copy Markdown
Collaborator

Review notes — worth fixing before merge

Two items from review that I'd like addressed before this lands:

[High] Suspending stylesheet not contained

Files: packages/ui/src/components/YouVersionProvider.tsx, packages/ui/src/lib/yv-fonts.tsx

<YvFonts /> renders a React 19 <link rel="stylesheet" precedence> as a sibling of children with no local Suspense boundary. When it suspends, the nearest boundary is above the provider in the consumer app — so their entire tree can be held during font fetch.

Combined with no opt-out, every consumer inherits first-nav latency to api.youversion.com.

Suggested fix: wrap the font link in a local boundary inside the provider:

<Suspense fallback={null}>
  <YvFonts  />
</Suspense>

That keeps suspension scoped to the provider instead of bubbling up to the app.


[Medium] Changeset is stale vs the branch

File: .changeset/untitled-serif-via-fonts-api.md (and matching ADR-0004 wording)

The changeset text doesn't match what's actually in the branch:

  • It claims the picker reads "Untitled", but the locale string is "Untitled Serif".
  • It claims sourceSerifFontName is gone from private locales, but it's still present in all six locale files.

Those lines ship into published CHANGELOGs, so please update the changeset (and the ADR wording to match) before merge.

@camrun91 camrun91 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.

See above request of changes.

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.

3 participants