Skip to content

fix(ios): resolve input heading weight within a custom font family - #1163

Open
wildseansy wants to merge 1 commit into
software-mansion:mainfrom
wildseansy:fix/ios-input-heading-weight-custom-font
Open

wildseansy wants to merge 1 commit into
software-mansion:mainfrom
wildseansy:fix/ios-input-heading-weight-custom-font

Conversation

@wildseansy

@wildseansy wildseansy commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

What/Why?

Follow-up to #586. With a custom editor font (a bundled family with separate regular and bold faces), EnrichedMarkdownTextInput headings on iOS still render at regular weight, even though the heading weight is bold by default. Inline bold in the same editor is correct.

headingFontForLevel: builds the heading font from [_baseFont.fontDescriptor fontDescriptorByAddingAttributes:{UIFontDescriptorTraitsAttribute: {UIFontWeightTrait: weight}}]. That descriptor still carries the font-name attribute, and for a custom font the name pins the exact face (for example the regular one), so the weight trait is ignored. System fonts are not affected, which is why this works with the default font. Inline bold works because the formatter goes through fontDescriptorWithSymbolicTraits:, which re-matches within the family.

This change also resolves the font by family name plus the weight trait (no name attribute), the way React Native's RCTFont resolves a weight inside a family, and keeps whichever result's weight trait is closer to the requested weight. The result is cached in _headingFontCache as before. Two properties follow from comparing the two candidates:

  • The family result is used only when it is strictly closer to the requested weight, so a base font that already resolves correctly (the system font) keeps its previous result.
  • A weight with no exact face in the family (for example 600 when only regular and bold exist) resolves to the nearest face inside the family, instead of falling back to a different font.

This is the same direction as the review on #586 (resolve weights within the family, keep iOS consistent with Android and the preview).

Context from #586: its first commit derived the bold face with fontDescriptorWithSymbolicTraits: (which does re-match within a custom family), and the review replaced that with the single weight-trait path for every weight, so bold and the other weights share one code path. That is the path this PR builds on. It keeps the weight-trait approach and the shared weight table, and adds the family lookup so a custom font whose descriptor pins its face still resolves every weight inside the family. It does not go back to special-casing bold.

Testing

  • Built the example app with fontFamily: "Avenir Next" on the editor, on an iPhone simulator running iOS 27 (also checked with a bundled custom family in a separate app).
  • Before: typed H1/H2 and headings loaded from saved markdown render at regular weight.
  • After: the same headings render bold in the same family, including a heading typed on a fresh empty line, and match the face used by the read-only renderer. Inline bold and italic behave as before.
  • Android headings already keep their weight with the same app, so this is iOS only.
  • Not run: the example app's E2E suite, a system-font base on a device (unchanged by construction, since the original result wins ties), and weights other than bold on a device.

Screenshots

Example app, EnrichedMarkdownTextInput with fontFamily: "Avenir Next", iPhone simulator on iOS 27. Same content in both; the inline bold is unchanged, only the headings differ.

Before After

PR Checklist

  • Code compiles and runs on iOS
  • Code compiles and runs on Android
  • Updated documentation/README if applicable
  • Ran example app to verify changes
  • E2E tests are passing
  • Required E2E tests have been added (if applicable)

🤖 Generated with Claude Code

https://claude.ai/code/session_01MRyUZFqR1H4uhUJg6hkeci

headingFontForLevel: added the weight trait to the base font's descriptor,
which still carries the font-name attribute. For a custom font the name
pins the exact face (e.g. regular), so the weight trait was ignored and
headings rendered at regular weight. Also resolve by family plus weight
trait and keep whichever face is closer to the requested weight, so a
custom family picks its own nearest face. System fonts keep the previous
result.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRyUZFqR1H4uhUJg6hkeci

This branch has not been deployed

No deployments
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