Skip to content

fix(0.81): backport main fixes (transforms, colors, ScrollView, text selection, CVEs)#2876

Merged
Saadnajmi merged 13 commits intomicrosoft:0.81-stablefrom
Saadnajmi:0.81/backport-main-fixes
Mar 28, 2026
Merged

fix(0.81): backport main fixes (transforms, colors, ScrollView, text selection, CVEs)#2876
Saadnajmi merged 13 commits intomicrosoft:0.81-stablefrom
Saadnajmi:0.81/backport-main-fixes

Conversation

@Saadnajmi
Copy link
Copy Markdown
Collaborator

@Saadnajmi Saadnajmi commented Mar 27, 2026

Summary

Backport of 10 commits from main to 0.81-stable:

Conflict resolutions

  • RCTUIView.h/m → On 0.81-stable, RCTUIView lives in React/Base/RCTUIKit.h and React/Base/macOS/RCTUIKit.m (the RCTUIKit module refactor hasn't landed on 0.81). Transform changes were manually applied to these files.
  • RCTUIKitCompat.h/mNSColor (RCTAppearanceResolving) category was added to RCTUIKit.h/m instead.
  • Lockfile conflicts resolved by accepting incoming CVE fixes.

Test Plan

  • Same as the original PRs
  • Verify transforms render correctly on macOS (old + new arch)
  • Verify dark mode color resolution works in Fabric
  • Verify ScrollView resize and content inset behavior
  • Verify text selection with selectable={true}
  • Verify enableFocusRing on TextInput in Fabric

🤖 Generated with Claude Code

Saadnajmi and others added 9 commits March 27, 2026 17:44
Fixes compilation errors that block macOS SPM builds, helping unblock

- **RCTLinkingManager**: combined iOS and macOS implementations into a
single file
using `#if TARGET_OS_OSX` guards. Added missing
`NativeLinkingManagerSpec`
conformance (`openSettings`, `sendIntent`, `getTurboModule`), removed
unused
import, deleted the `macos/` overlay directory, and cleaned up the
podspec
- **RCTCursor.m**: replaced `Foundation.h` + conditional `AppKit.h` with
`RCTUIKit`
  umbrella header
- **RCTViewComponentView.mm**: removed duplicate `cursor` property check
introduced
  during merge

- [x] macOS SPM build passes (verified on `feature/spm-macos-support` —
zero errors from these files)
- [ ] Verify iOS build is not regressed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
… both arches (microsoft#2866)

CSS transforms (`rotate`, `scale`, `translateX`, etc.) were not
rendering on macOS with the New Architecture (Fabric). This PR fixes the
root cause and related issues.

On macOS, `NSView` has no built-in `transform` property (unlike `UIView`
on iOS). AppKit's layer-backed view system resets `layer.transform` to
identity during its layout/display cycle. This means any transform set
on the layer is silently discarded.

**1. Add `transform3D` property to `RCTUIView` with anchor point and hit
testing fixes**
- Stores the transform in an ivar so it survives AppKit's reset
- Re-applies the transform in `updateLayer` (called during AppKit's
display phase)
- `wantsUpdateLayer` is conditional on having a custom transform or
`displayLayer:` delegate, so `drawRect:` still works for text views
- Compensates for macOS `layer.anchorPoint` defaulting to `{0, 0}`
instead of `{0.5, 0.5}`, so transforms apply from the view's center
- `hitTest:` and `RCTUIViewHitTestWithEvent` use `CALayer` coordinate
conversion, which correctly accounts for `layer.transform` (`NSView`'s
`convertPoint:fromView:` does not)

**2. Use `transform3D` in Fabric component views**
- `RCTViewComponentView` uses `self.transform3D` instead of
`self.layer.transform` on macOS
- Removes duplicated anchor point compensation and `hitTest:` override
now handled by `RCTUIView`

**3. Update Paper hit testing callers for transform-aware coordinate
conversion**
- Updates `RCTUIViewHitTestWithEvent` callers in Paper architecture to
use the new `fromView` parameter, enabling transform-aware hit testing
in old architecture as well

- [x] Verified transforms render correctly on macOS Fabric: rotate,
scale, translateX, opacity, combined rotate+scale
- [x] Verified text still renders (conditional `wantsUpdateLayer`
prevents skipping `drawRect:`)
- [x] Verified hit testing works on transformed views (Pressable with
click counters)
- [x] Verified no regression on non-transformed views

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Bumps [undici](https://github.com/nodejs/undici) from 5.29.0 to 6.24.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/nodejs/undici/releases">undici's
releases</a>.</em></p>
<blockquote>
<h2>v6.24.0</h2>
<h1>Undici v6.24.0 Security Release Notes (LTS)</h1>
<p>This release backports fixes for security vulnerabilities affecting
the v6 line.</p>
<h2>Upgrade guidance</h2>
<p>All users on v6 should upgrade to <strong>v6.24.0</strong> or
later.</p>
<h2>Fixed advisories</h2>
<ul>
<li>
<p><a
href="https://github.com/nodejs/undici/security/advisories/GHSA-2mjp-6q6p-2qxm">GHSA-2mjp-6q6p-2qxm</a>
/ CVE-2026-1525 (Medium)<br />
Inconsistent interpretation of HTTP requests (request/response smuggling
class issue).</p>
</li>
<li>
<p><a
href="https://github.com/nodejs/undici/security/advisories/GHSA-f269-vfmq-vjvj">GHSA-f269-vfmq-vjvj</a>
/ CVE-2026-1528 (High)<br />
Malicious WebSocket 64-bit frame length handling could crash the
client.</p>
</li>
<li>
<p><a
href="https://github.com/nodejs/undici/security/advisories/GHSA-4992-7rv2-5pvq">GHSA-4992-7rv2-5pvq</a>
/ CVE-2026-1527 (Medium)<br />
CRLF injection via the <code>upgrade</code> option.</p>
</li>
<li>
<p><a
href="https://github.com/nodejs/undici/security/advisories/GHSA-v9p9-hfj2-hcw8">GHSA-v9p9-hfj2-hcw8</a>
/ CVE-2026-2229 (High)<br />
Unhandled exception from invalid <code>server_max_window_bits</code> in
WebSocket permessage-deflate negotiation.</p>
</li>
<li>
<p><a
href="https://github.com/nodejs/undici/security/advisories/GHSA-vrm6-8vpv-qv8q">GHSA-vrm6-8vpv-qv8q</a>
/ CVE-2026-1526 (High)<br />
Unbounded memory consumption in WebSocket permessage-deflate
decompression.</p>
</li>
</ul>
<h2>Not applicable to v6</h2>
<ul>
<li><a
href="https://github.com/nodejs/undici/security/advisories/GHSA-phc3-fgpg-7m6h">GHSA-phc3-fgpg-7m6h</a>
/ CVE-2026-2581 affects <code>&gt;= 7.17.0 &lt; 7.24.0</code> only.</li>
</ul>
<h2>Affected and patched ranges (v6)</h2>
<ul>
<li>CVE-2026-1525: affected <code>&lt; 6.24.0</code>, patched
<code>6.24.0</code></li>
<li>CVE-2026-1528: affected <code>&gt;= 6.0.0 &lt; 6.24.0</code>,
patched <code>6.24.0</code></li>
<li>CVE-2026-1527: affected <code>&lt; 6.24.0</code>, patched
<code>6.24.0</code></li>
<li>CVE-2026-2229: affected <code>&lt; 6.24.0</code>, patched
<code>6.24.0</code></li>
<li>CVE-2026-1526: affected <code>&lt; 6.24.0</code>, patched
<code>6.24.0</code></li>
</ul>
<h2>References</h2>
<ul>
<li>GitHub Security Advisories: <a
href="https://github.com/nodejs/undici/security/advisories">https://github.com/nodejs/undici/security/advisories</a></li>
<li>NVD CVE-2026-1525: <a
href="https://nvd.nist.gov/vuln/detail/CVE-2026-1525">https://nvd.nist.gov/vuln/detail/CVE-2026-1525</a></li>
<li>NVD CVE-2026-1528: <a
href="https://nvd.nist.gov/vuln/detail/CVE-2026-1528">https://nvd.nist.gov/vuln/detail/CVE-2026-1528</a></li>
<li>NVD CVE-2026-1527: <a
href="https://nvd.nist.gov/vuln/detail/CVE-2026-1527">https://nvd.nist.gov/vuln/detail/CVE-2026-1527</a></li>
<li>NVD CVE-2026-2229: <a
href="https://nvd.nist.gov/vuln/detail/CVE-2026-2229">https://nvd.nist.gov/vuln/detail/CVE-2026-2229</a></li>
<li>NVD CVE-2026-1526: <a
href="https://nvd.nist.gov/vuln/detail/CVE-2026-1526">https://nvd.nist.gov/vuln/detail/CVE-2026-1526</a></li>
</ul>
<h2>v6.23.0</h2>
<h2>⚠️ Security Release</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/nodejs/undici/commit/8873c947271faf1ebc455bdc6158ecbc022ecfa9"><code>8873c94</code></a>
Bumped v6.24.0</li>
<li><a
href="https://github.com/nodejs/undici/commit/411bd01a42e7917009bbf686f7628b99d67bbce9"><code>411bd01</code></a>
test(websocket): use node:assert for Node 18 compatibility</li>
<li><a
href="https://github.com/nodejs/undici/commit/844bf59699d778944f78a24ae819c0e8f295766e"><code>844bf59</code></a>
test: fix http2 lint regressions in backport</li>
<li><a
href="https://github.com/nodejs/undici/commit/a444e4f13e8958b4e1ac42bc0d53ace7fba0a9c1"><code>a444e4f</code></a>
test: stabilize h2 and tls-cert-leak under current test runner</li>
<li><a
href="https://github.com/nodejs/undici/commit/dc032a1050d5489b8ce9b4c22aafba98a942f87b"><code>dc032a1</code></a>
fix: h2 CI (<a
href="https://redirect.github.com/nodejs/undici/issues/4395">#4395</a>)</li>
<li><a
href="https://github.com/nodejs/undici/commit/4cd3f4b3a2ef910ba728c47ae78294d956410450"><code>4cd3f4b</code></a>
test: increase bitness in <code>test/fixtures/*.pem</code> (<a
href="https://redirect.github.com/nodejs/undici/issues/3659">#3659</a>)</li>
<li><a
href="https://github.com/nodejs/undici/commit/7df6442194b7a54e9ac734335e6e0a56a9bc6666"><code>7df6442</code></a>
fix: adapt websocket frame-limit handling for v6 parser</li>
<li><a
href="https://github.com/nodejs/undici/commit/4e0179ae643e6f4380f24cc3683c1b1ca2afb094"><code>4e0179a</code></a>
fix: reject duplicate content-length and host headers</li>
<li><a
href="https://github.com/nodejs/undici/commit/5a97f0893b53ba7d1d5549d3df7e55d9c2673f89"><code>5a97f08</code></a>
Fix websocket 64-bit length overflow</li>
<li><a
href="https://github.com/nodejs/undici/commit/e43e898603dd5e0c14a75b08b83257598d664a39"><code>e43e898</code></a>
fix: validate upgrade header to prevent CRLF injection</li>
<li>Additional commits viewable in <a
href="https://github.com/nodejs/undici/compare/v5.29.0...v6.24.0">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by [GitHub Actions](<a
href="https://www.npmjs.com/~GitHub">https://www.npmjs.com/~GitHub</a>
Actions), a new releaser for undici since your current version.</p>
</details>
<details>
<summary>Install script changes</summary>
<p>This version modifies <code>prepare</code> script that runs during
installation. Review the package contents before updating.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=undici&package-manager=npm_and_yarn&previous-version=5.29.0&new-version=6.24.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/microsoft/react-native-macos/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Fix content inset adjustments for macOS ScrollView.

<!-- Thanks for submitting a pull request! We appreciate you spending
the time to work on these changes. Please provide enough information so
that others can review your pull request. The four fields below are
mandatory. -->

<!-- This fork of react-native provides React Native for macOS for the
community. It also contains some changes that are required for usage
internal to Microsoft. We are working on reducing the diff between
Facebook's public version of react-native and our
microsoft/react-native-macos fork. Long term, we want this fork to only
contain macOS concerns and have the other iOS and Android concerns
contributed upstream.

If you are making a new change then one of the following should be done:
- Consider if it is possible to achieve the desired behavior without
making a change to microsoft/react-native-macos. Often a change can be
made in a layer above in facebook/react-native instead.
- Create a corresponding PR against
[facebook/react-native](https://github.com/facebook/react-native)
**Note:** Ideally you would wait for Facebook feedback before submitting
to Microsoft, since we want to ensure that this fork doesn't deviate
from upstream.
-->

## Summary:

<!-- Explain the **motivation** for making this change. What existing
problem does the pull request solve? -->

## Test Plan:

<!-- Demonstrate the code is solid. Example: The exact commands you ran
and their output, screenshots / videos if the pull request changes the
user interface. -->

---------

Co-authored-by: Saad Najmi <sanajmi@microsoft.com>
…e deps (microsoft#2874)

- update react-native-macos-init to npm-registry-fetch 19.x
- refresh root and docsite lockfiles to pick patched tar/minimatch paths
- upgrade api-extractor and serve-handler where it removes override
pressure
- collapse remaining minimatch resolutions to the smallest set Yarn will
honor
…ue} (microsoft#2864)

Followup from microsoft#2845 

## Summary
- Implements native text selection support for `<Text
selectable={true}>` in the Fabric (new architecture) renderer
- On **macOS**, swaps the content view to an `NSTextView` subclass that
handles click-drag, double-click (word), and triple-click (line)
selection, plus right-click context menus
- On **iOS**, swaps to a `UITextView` subclass that leverages built-in
gesture recognizers for long-press-to-select
- The selectable text view is created lazily — only when
`selectable={true}` — so there is zero overhead for non-selectable text
(the common case)
- Ungates `RCTTextLayoutManager.getTextStorageForAttributedString:` so
both platforms can sync Fabric's attributed string into the native text
view

| iOS | macOS |
| ----------- | ----------- |
| <img width="506" height="960" alt="Screenshot 2026-03-20 at 11 30
06 PM"
src="https://github.com/user-attachments/assets/ac7ce231-0969-4003-a3ca-55fae4e35515"
/> | <img width="805" height="868" alt="Screenshot 2026-03-20 at 11 36
36 PM"
src="https://github.com/user-attachments/assets/9cc0e951-8bff-41a5-92ff-1f3589ab7279"
/> |

## Approach

Rather than adding selection logic to the existing
`RCTParagraphTextView`, this introduces a separate
`RCTParagraphSelectableTextView` (platform-native text view) that is
swapped in as the content view when the `selectable` prop is set. This
keeps the non-selectable path untouched and avoids runtime cost for the
default case.

On macOS, mouse events are intercepted at the
`RCTParagraphComponentView` level to distinguish single clicks
(forwarded to JS for `onPress`) from drag/double-click/triple-click
gestures (forwarded to the `NSTextView` for native selection). Touch
cancellation walks the view hierarchy to toggle `RCTSurfaceTouchHandler`
without modifying that class.

On iOS, `UITextView` handles selection natively through its built-in
gesture recognizers — no custom hit-testing needed.

## Test plan

Add the following to RNTesterPlayground and verify on both macOS and
iOS:

```jsx
import {Alert, StyleSheet, Text, View} from 'react-native';

function Playground() {
  return (
    <View style={styles.container}>
      <Text style={styles.heading}>Text Selection Test</Text>

      <Text style={styles.label}>Selectable text (try click-drag, double-click, right-click):</Text>
      <Text selectable={true} style={styles.selectableText}>
        This text should be selectable. Try clicking and dragging to select a
        range of text. Double-click to select a word. Triple-click to select a
        line. Right-click to see the context menu.
      </Text>

      <Text style={styles.label}>Non-selectable text (default):</Text>
      <Text style={styles.nonSelectableText}>
        This text should NOT be selectable. Clicking and dragging should not
        create a text selection. This is the default behavior.
      </Text>

      <Text style={styles.label}>Selectable with nested styles:</Text>
      <Text selectable={true} style={styles.selectableText}>
        This has <Text style={styles.bold}>bold text</Text> and{' '}
        <Text style={styles.italic}>italic text</Text> and{' '}
        <Text style={styles.colored}>colored text</Text> inside it.
        Selection should work across all styled ranges.
      </Text>

      <Text style={styles.label}>Selectable with onPress (should not conflict):</Text>
      <Text
        selectable={true}
        onPress={() => Alert.alert('Text pressed!')}
        style={styles.pressableText}>
        This text is both selectable and pressable. A single click should
        trigger onPress. Click-drag should start a selection instead.
      </Text>
    </View>
  );
}
```

- [ ] Verify `<Text selectable={true}>` enables click-drag selection on
macOS
- [ ] Verify double-click selects a word, triple-click selects a line on
macOS
- [ ] Verify right-click shows native context menu with Copy on macOS
- [ ] Verify `<Text selectable={true}>` enables long-press selection on
iOS
- [ ] Verify non-selectable text (default) is unchanged on both
platforms
- [ ] Verify `onPress` still fires for single clicks on selectable text
- [ ] Verify nested styled text renders correctly when selectable
- [ ] Verify selection is cleared when text loses focus

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Kyle Essenmacher <15271436+kessenma@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary

- preserve macOS ScrollView position during live resize in root and
surface hosting views
- align Fabric ScrollView contentInset and contentOffset behavior with
the existing macOS scrollview implementation
- prevent resize-driven scroll drift in the macOS Paper ScrollView path

## Test Plan

- Build RNTester-macOS
- Verify RNTester runs normally
- Manually resize windows containing ScrollView content and confirm
content offset remains stable
## Summary
Add backporting infrastructure for cherry-picking changes across release
branches. This includes:

- **`.ai/commands/backport.md`** — Shared AI-tool-agnostic backport
instructions (works with Claude Code, Copilot, or any AI assistant)
- **`.claude/commands/backport.md`** — Claude Code `/backport` slash
command wrapper
- **`.github/workflows/microsoft-backport.yml`** — GitHub Actions
workflow triggered by `/backport <branch>` comments on PRs, with
auto-update support when source PR changes
- **`docsite/docs/contributing/backporting.md`** — Documentation page
covering all backport methods

### Features
- Multi-branch support: `/backport 0.81-stable 0.82-stable`
- Works on both open and merged PRs
- Auto-updates backport PRs when source PR gets new commits
- GitHub App authentication via `actions/create-github-app-token@v2`
- Handles conflicts gracefully with manual instructions

## Test plan
- [ ] Verify docsite builds: `cd docsite && yarn start` — check
"Backporting" page under Contributing
- [ ] Test `/backport` slash command locally in Claude Code
- [ ] Merge a test PR, comment `/backport 0.81-stable`, verify workflow
creates backport PR

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@Saadnajmi Saadnajmi requested a review from a team as a code owner March 27, 2026 22:51
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 27, 2026

⚠️ No Changeset found

Latest commit: e60eac8

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.

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Saadnajmi and others added 3 commits March 27, 2026 21:23
… workflow to main

- RCTPlatformColor is defined in RCTUIKitCompat.h on main (post-refactor),
  but that file doesn't exist on 0.81-stable. Add the #define to RCTUIKit.h
  for both iOS (UIColor) and macOS (NSColor).
- Restrict the backport GitHub Action's pull_request trigger to only the
  main branch so it doesn't run on backport PRs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Saadnajmi Saadnajmi merged commit e979766 into microsoft:0.81-stable Mar 28, 2026
13 of 14 checks passed
@Saadnajmi Saadnajmi deleted the 0.81/backport-main-fixes branch March 28, 2026 03:33
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.

4 participants