diff --git a/.changeset/calm-tabs-scroll.md b/.changeset/calm-tabs-scroll.md new file mode 100644 index 00000000..f46cd20d --- /dev/null +++ b/.changeset/calm-tabs-scroll.md @@ -0,0 +1,5 @@ +--- +"react-native-bottom-tabs": patch +--- + +Fix `scrollEdgeAppearance` on iOS 26 and newer. diff --git a/artifacts/issue-532/README.md b/artifacts/issue-532/README.md new file mode 100644 index 00000000..b8a659be --- /dev/null +++ b/artifacts/issue-532/README.md @@ -0,0 +1,76 @@ +# Issue #532: iOS scroll-edge appearance evidence + +## Expected behavior + +The public API defines three values for `scrollEdgeAppearance`: + +- `transparent`: when the bottom edge of an observable scroll view reaches the tab bar, the bar has no opaque background or separator and content remains visible beneath the system tab-bar material. +- `opaque`: the tab bar uses a theme-appropriate opaque background. A supplied `barTintColor` replaces the theme background. +- `default` or unconfigured: UIKit retains its platform-default appearance. + +The transparent and opaque example screens use the same tabs and article content. At matching scroll positions, the opaque example must have a solid system background behind the complete tab bar, while the transparent example must retain the floating Liquid Glass presentation. + +## Environment + +- Date: 2026-08-31 +- App: repository `apps/example` workspace, React Native 0.81.4, New Architecture enabled +- Device: iPhone 17 Pro simulator (`CD1ADD09-474F-4618-899B-689243327BC6`) +- Runtime: iOS 27.0 +- Xcode: 27.0 Beta 4 (`27A5228h`) +- agent-device: 0.20.10 +- Metro: repository example bundle on port 8085 + +No iOS 26.x runtime is installed in the available environment. The requested reproduction range was iOS 26 or newer, so the iOS 27.0 runtime exercises the `#available(iOS 26.0, *)` implementation and satisfies that range. These captures must not be represented as exact iOS 26.x evidence; an iOS 26.x compatibility run remains optional follow-up evidence if that runtime becomes available. + +## Reproduction + +The installed example app was opened with the repository's Metro bundle. For both existing example routes, the Article tab was captured at `What is Lorem Ipsum?`, scrolled down three equivalent agent-device scroll units, and explicitly verified at `Where can I get some?` before the bottom capture. + +Before the fix, `Four Tabs - Transparent scroll edge appearance` and `Four Tabs - Opaque scroll edge appearance` both rendered as the same floating Liquid Glass tab bar at both positions: + +- [Transparent, top](baseline/screenshots/transparent-top.png) +- [Transparent, bottom](baseline/screenshots/transparent-bottom.png) +- [Opaque, top](baseline/screenshots/opaque-top.png) +- [Opaque, bottom](baseline/screenshots/opaque-bottom.png) +- [Transparent scroll recording](baseline/videos/transparent-scroll.mp4) +- [Opaque scroll recording](baseline/videos/opaque-scroll.mp4) + +## Diagnosis and fix verification + +Runtime inspection confirmed that the JavaScript prop reached native code and that UIKit held the expected `UITabBarAppearance` values: the opaque route had `systemBackgroundColor` with a visible background, and the transparent route had a hidden scroll-edge background. On iOS 26 and newer, the floating Liquid Glass tab bar does not render those appearance-object background states as an opaque backing surface. Setting the public `UITabBar.backgroundColor` does control that backing surface. + +The fix therefore sets the tab bar's own background on iOS 26 and newer when the requested appearance is opaque, when `translucent={false}` already requires opacity, or when a `barTintColor` is supplied for a non-transparent appearance. It preserves the supplied dynamic `UIColor`; otherwise opaque configurations use dynamic `systemBackground`. Transparent always clears the backing, and default/unconfigured configurations without a custom color retain the platform default. The existing `UITabBarAppearance` configuration remains responsible for item styling, shadows, and pre-iOS-26 behavior. + +After the fix, the opaque route has a solid theme background while transparent and default preserve the platform Liquid Glass appearance. All cases were recorded at the same top and bottom article positions: + +- [Default, top](verification/screenshots/default-top.png) +- [Default, bottom](verification/screenshots/default-bottom.png) +- [Default scroll recording](verification/videos/default-scroll.mp4) +- [Transparent, top](verification/screenshots/transparent-top.png) +- [Transparent, bottom](verification/screenshots/transparent-bottom.png) +- [Transparent scroll recording](verification/videos/transparent-scroll.mp4) +- [Opaque, top](verification/screenshots/opaque-top.png) +- [Opaque, bottom](verification/screenshots/opaque-bottom.png) +- [Opaque scroll recording](verification/videos/opaque-scroll.mp4) + +The top/bottom screenshots above were refreshed from the final remediated binary on 2026-09-03. Additional compatibility evidence from the same simulator covers the adversarial-review findings: + +- [Custom background, top](verification/compatibility/custom-background-top.png) and [bottom](verification/compatibility/custom-background-bottom.png) +- Opaque minimize behavior: [expanded](verification/compatibility/opaque-minimize-expanded.png), [collapsed](verification/compatibility/opaque-minimize-collapsed.png), and [restored](verification/compatibility/opaque-minimize-restored.png) +- Opaque hide/show: [shown](verification/compatibility/opaque-hide-shown.png), [hidden](verification/compatibility/opaque-hide-hidden.png), and [restored](verification/compatibility/opaque-hide-restored.png) +- Dynamic appearance: [dark](verification/compatibility/opaque-dark.png) and [light restored](verification/compatibility/opaque-light-restored.png) +- [`translucent={false}`](verification/compatibility/translucent-false.png) +- [Custom tab bar](verification/compatibility/custom-tabbar.png) + +## Validation + +- iOS simulator build: Xcode 27.0, iOS 27.0 SDK, deployment target iOS 15.1 — passed +- `yarn lint` — passed with three pre-existing warnings and no errors +- `yarn typecheck` — passed +- `yarn build` — passed +- `RCT_NEW_ARCH_ENABLED=1 yarn build:ios` — passed +- `node ../../node_modules/jest/bin/jest.js src/__tests__/index.test.tsx --runInBand` from the core package — passed (the repository currently contains one todo test) +- `git diff --check` — passed +- Device workflow: open, interactive snapshot, navigate, capture top, record and scroll, explicitly verify bottom content, capture bottom, close — passed + +The adversarial-review findings and the exact remaining runtime verification are recorded in [review/dispositions.md](review/dispositions.md). The successful Fable JSON is preserved unchanged at [review/fable-review.json](review/fable-review.json). diff --git a/artifacts/issue-532/baseline/screenshots/opaque-bottom.png b/artifacts/issue-532/baseline/screenshots/opaque-bottom.png new file mode 100644 index 00000000..04346acc Binary files /dev/null and b/artifacts/issue-532/baseline/screenshots/opaque-bottom.png differ diff --git a/artifacts/issue-532/baseline/screenshots/opaque-top.png b/artifacts/issue-532/baseline/screenshots/opaque-top.png new file mode 100644 index 00000000..ecd6e743 Binary files /dev/null and b/artifacts/issue-532/baseline/screenshots/opaque-top.png differ diff --git a/artifacts/issue-532/baseline/screenshots/transparent-bottom.png b/artifacts/issue-532/baseline/screenshots/transparent-bottom.png new file mode 100644 index 00000000..3cdff056 Binary files /dev/null and b/artifacts/issue-532/baseline/screenshots/transparent-bottom.png differ diff --git a/artifacts/issue-532/baseline/screenshots/transparent-top.png b/artifacts/issue-532/baseline/screenshots/transparent-top.png new file mode 100644 index 00000000..d86922b0 Binary files /dev/null and b/artifacts/issue-532/baseline/screenshots/transparent-top.png differ diff --git a/artifacts/issue-532/baseline/videos/opaque-scroll.gesture-telemetry.json b/artifacts/issue-532/baseline/videos/opaque-scroll.gesture-telemetry.json new file mode 100644 index 00000000..a484a4b6 --- /dev/null +++ b/artifacts/issue-532/baseline/videos/opaque-scroll.gesture-telemetry.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "generatedAt": "2026-08-30T20:41:18.880Z", + "events": [ + { + "kind": "scroll", + "tMs": 3850, + "x": 201, + "y": 787, + "x2": 201, + "y2": 87, + "referenceWidth": 402, + "referenceHeight": 874, + "durationMs": 250, + "contentDirection": "down", + "amount": 3, + "pixels": 700 + } + ] +} \ No newline at end of file diff --git a/artifacts/issue-532/baseline/videos/opaque-scroll.mp4 b/artifacts/issue-532/baseline/videos/opaque-scroll.mp4 new file mode 100644 index 00000000..7c2fa00b Binary files /dev/null and b/artifacts/issue-532/baseline/videos/opaque-scroll.mp4 differ diff --git a/artifacts/issue-532/baseline/videos/transparent-scroll.gesture-telemetry.json b/artifacts/issue-532/baseline/videos/transparent-scroll.gesture-telemetry.json new file mode 100644 index 00000000..8a958d8f --- /dev/null +++ b/artifacts/issue-532/baseline/videos/transparent-scroll.gesture-telemetry.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "generatedAt": "2026-08-30T20:40:20.592Z", + "events": [ + { + "kind": "scroll", + "tMs": 150, + "x": 201, + "y": 787, + "x2": 201, + "y2": 87, + "referenceWidth": 402, + "referenceHeight": 874, + "durationMs": 250, + "contentDirection": "down", + "amount": 3, + "pixels": 700 + } + ] +} \ No newline at end of file diff --git a/artifacts/issue-532/baseline/videos/transparent-scroll.mp4 b/artifacts/issue-532/baseline/videos/transparent-scroll.mp4 new file mode 100644 index 00000000..3d408453 Binary files /dev/null and b/artifacts/issue-532/baseline/videos/transparent-scroll.mp4 differ diff --git a/artifacts/issue-532/review/dispositions.md b/artifacts/issue-532/review/dispositions.md new file mode 100644 index 00000000..62f181ab --- /dev/null +++ b/artifacts/issue-532/review/dispositions.md @@ -0,0 +1,55 @@ +# Issue #532 Fable review dispositions + +This file records the single successful Claude Code Fable/High review and the single GPT-5.6-Sol/High remediation pass for the four findings in `fable-review.json`. The review JSON is intentionally unchanged, and Fable was not rerun after remediation. + +## 1. Custom `barTintColor` with default/unconfigured scroll-edge appearance + +**Fixed.** The finding was valid. On iOS 26 and newer, `updateTabBarAppearance` now gives a non-transparent configured `barTintColor` to the tab bar backing even when `scrollEdgeAppearance` is default or unset. The precedence is explicit: + +| Configuration | iOS 26+ tab-bar backing | +| --- | --- | +| `scrollEdgeAppearance="transparent"` | cleared, including when a color was supplied | +| default/unconfigured plus `barTintColor` | supplied color | +| `scrollEdgeAppearance="opaque"` plus `barTintColor` | supplied color | +| `scrollEdgeAppearance="opaque"` without a color | dynamic `systemBackground` | +| `translucent={false}` without a color | dynamic `systemBackground` | +| default/unconfigured, translucent, no color | cleared so UIKit retains its default | + +Repository evidence: `apps/example/src/App.tsx` exposes “Four Tabs - Custom Background Color of Tabs” with `#87CEEB`; `apps/example/src/Examples/FourTabs.tsx` maps that value to `tabBarStyle.backgroundColor`; `packages/react-native-bottom-tabs/src/TabView.tsx` maps it to native `barTintColor`; and `TabViewImpl.swift` now consumes it in the iOS 26+ backing path. Passing the existing `UIColor` object to `UIView.backgroundColor` preserves dynamic colors. The block is compiled only for iOS and runs only on iOS 26+, so pre-iOS-26 behavior and tvOS, visionOS, and macOS behavior remain unchanged. The standard appearance object continues to cover both normal and scroll-edge positions. + +The final remediated binary was verified through the repository's custom-background example at equivalent top and bottom article positions. Both captures show the configured `#87CEEB` backing: [top](../verification/compatibility/custom-background-top.png) and [bottom](../verification/compatibility/custom-background-bottom.png). + +## 2. Minimize, hide, and dark-mode interaction + +**Concretely disproven.** The finding described a possible artifact but provided no reproduction or runtime evidence. The implementation uses the public inherited `UIView.backgroundColor` on the real `UITabBar`; it does not add an overlay, mask, appearance proxy, private API, delayed update, or independently positioned view. Existing hiding is also applied to the real system tab bar through SwiftUI's public `toolbar(.hidden, for: .tabBar)` path on supported OS versions. The remediation preserves dynamic `UIColor.systemBackground`, which is the theme-aware value needed for light/dark changes. + +No speculative transition workaround was added because UIKit exposes no public minimized-state callback in the installed iOS 27 SDK, and changing or disabling the caller's `minimizeBehavior` would violate that public API. + +The primary agent completed the real-app verification on the documented iPhone 17 Pro / iOS 27.0 simulator with the repository Metro bundle and the same public props. Temporary QA-only example wiring was removed before the final diff. The opaque minimize path collapses to the system-managed control without leaving a rectangular band and restores its full backing on scroll-up: [expanded](../verification/compatibility/opaque-minimize-expanded.png), [collapsed](../verification/compatibility/opaque-minimize-collapsed.png), and [restored](../verification/compatibility/opaque-minimize-restored.png). + +Hide/show leaves no backing while hidden and restores cleanly: [shown](../verification/compatibility/opaque-hide-shown.png), [hidden](../verification/compatibility/opaque-hide-hidden.png), and [restored](../verification/compatibility/opaque-hide-restored.png). Dynamic `systemBackground` resolves to black in [dark appearance](../verification/compatibility/opaque-dark.png) and back to white after [restoring light appearance](../verification/compatibility/opaque-light-restored.png). + +The final binary also rechecked default, transparent, and opaque at matching top/bottom positions; verified [`translucent={false}`](../verification/compatibility/translucent-false.png); and verified the repository's [custom tab-bar example](../verification/compatibility/custom-tabbar.png). The lifecycle captures were made immediately before the custom-color-only remediation was installed; that remediation does not alter the opaque condition or value exercised by those captures. The final installed binary then refreshed all default/transparent/opaque screenshots and captured the custom-color, `translucent={false}`, and custom-tab-bar cases. + +## 3. Evidence captured on iOS 27 rather than iOS 26 + +**Concretely disproven as a requirements violation.** The explicit reproduction requirement is iOS 26 or newer, not exactly iOS 26.x. The captured device reports iOS 27.0, which is within that range and executes the `#available(iOS 26.0, *)` branch. The evidence README records the exact simulator, runtime, Xcode beta, and capture date; it does not label the captures as iOS 26. + +The limitation is now explicit in the evidence README: no iOS 26.x runtime is installed, so the branch has no exact-26 capture and none is fabricated. If an iOS 26.x runtime later becomes available, a compatibility run may add confidence about version-specific compositing, but it was not part of the user's `>=26` acceptance requirement. + +## 4. Checked-in binary evidence and missing disposition record + +**Concretely disproven in part and fixed in part.** Repository-size preference cannot override the user's explicit requirement that clear issue-specific screenshots and videos be committed on this branch. All existing media is therefore preserved. The valid incompleteness portion is fixed by this disposition file, and the evidence README now links both this file and the unchanged successful Fable JSON instead of promising a future record. + +## Remediation checks + +- `yarn lint` — passed; the three reported warnings predate this remediation and are unrelated to issue #532. +- `yarn typecheck` — passed. +- `yarn build` — passed. +- `RCT_NEW_ARCH_ENABLED=1 yarn build:ios` — passed. +- Core Jest test (`src/__tests__/index.test.tsx`) — passed with the repository's one existing todo. +- The `react-native-bottom-tabs` CocoaPods scheme was built for the generic iOS device SDK with code signing disabled — passed, including compilation of `TabViewImpl.swift`. +- The complete example workspace was built for the iPhone 17 Pro / iOS 27.0 simulator with code signing disabled — passed. +- The final remediated app was installed and the default, transparent, opaque, custom-color, `translucent={false}`, and custom-tab-bar cases were explicitly verified. Minimize, hide/show, and light/dark lifecycle checks also passed as documented above. +- `git diff --check` — passed. +- `fable-review.json` parsed with all four findings and remained unchanged at SHA-256 `6a57310f6a0f8c9885ae6f3962e5ebbe6f7eb9e2d49b6d9308a93b08aac55942`. diff --git a/artifacts/issue-532/review/fable-review.json b/artifacts/issue-532/review/fable-review.json new file mode 100644 index 00000000..9060a12d --- /dev/null +++ b/artifacts/issue-532/review/fable-review.json @@ -0,0 +1,32 @@ +{ + "findings": [ + { + "file": "packages/react-native-bottom-tabs/ios/TabViewImpl.swift", + "line": 138, + "defect": "The iOS 26 opacity condition (`scrollEdgeAppearance == \"opaque\" || !translucent`) ignores a supplied barTintColor, so the documented `tabBarStyle.backgroundColor` contract (docs/docs/docs/guides/usage-with-react-navigation.mdx:155 and standalone-usage.mdx:209, 'Background color of the tab bar') remains non-functional on iOS 26+ when scrollEdgeAppearance is \"default\" or unset. On iOS <= 18 the same props render the custom color via appearance.backgroundColor (TabViewImpl.swift:193-195); on iOS 26 the new code actively clears tabBar.backgroundColor for that configuration. The fix touches exactly this code path and consumes props.barTintColor only in the opaque branch, leaving the documented API inconsistent across OS versions, and no checked-in evidence exercises a barTintColor route.", + "failure_scenario": "An app (or the repository's own 'Four Tabs - Custom Background Color of Tabs' example, apps/example/src/App.tsx:74-76, which passes backgroundColor '#87CEEB' with default scrollEdgeAppearance) sets only tabBarStyle.backgroundColor — a common React Navigation configuration. On iOS 18 the tab bar shows the custom color; on iOS 26 the color is silently ignored and the plain Liquid Glass bar renders, reproducing the same class of 'appearance prop has no effect on iOS 26' bug this branch claims to fix.", + "severity": "medium" + }, + { + "file": "packages/react-native-bottom-tabs/ios/TabViewImpl.swift", + "line": 139, + "defect": "Setting the UITabBar view's own UIView.backgroundColor paints an unmanaged opaque layer under the Liquid Glass bar instead of configuring the bar's background, and its interaction with iOS-26-only features the library itself exposes is unverified. With tabBarMinimizeBehavior (TabViewImpl.swift:47, 528) the system collapses the bar into a floating pill during scroll, and a full-frame view background is not part of the system-managed transition; toolbar(.hidden) tab-bar hiding transitions and dark-mode rendering of the new opaque strip are likewise untested. The checked-in evidence covers only static, light-mode captures of the default/transparent/opaque routes with no minimize behavior, no hide transition, and no dark appearance.", + "failure_scenario": "A user combines scrollEdgeAppearance=\"opaque\" with tabBarMinimizeBehavior=\"onScrollDown\" on iOS 26: while the system animates the bar down to its minimized pill, the UITabBar view's full-frame opaque backgroundColor persists or animates as a solid band that does not match the minimized Liquid Glass presentation, producing a visible rectangle artifact over scrolled content. Nothing in the branch's evidence or tests would catch this before release.", + "severity": "medium" + }, + { + "file": "artifacts/issue-532/README.md", + "line": 19, + "defect": "All baseline and verification evidence was captured on an iOS 27.0 beta simulator runtime with Xcode 27.0 Beta 4, but the code gate is #available(iOS 26.0, *), the changeset claims 'Fix scrollEdgeAppearance on iOS 26 and newer', and issue #532 reports released iOS 26 behavior. No capture on any iOS 26.x runtime exists, so the checked-in visual evidence does not prove the stated behavior on the OS version the fix targets; Liquid Glass handling of a raw UITabBar view backgroundColor can differ between released iOS 26.x and a later beta.", + "failure_scenario": "The patch ships with the changeset's iOS 26 claim, but on devices running released iOS 26.x the raw view backgroundColor renders differently than on the iOS 27 beta (e.g., clipped by the glass container or not composited as an opaque strip), leaving the originally reported transparent-vs-opaque bug unfixed or introducing a new artifact for the exact user population that filed issue #532.", + "severity": "medium" + }, + { + "file": "artifacts/issue-532/README.md", + "line": 65, + "defect": "The branch commits ~32 MB of binary evidence (six .mp4 recordings, ten .png screenshots; 23 MB in verification/videos alone) into the library repository under artifacts/issue-532/, a directory with no precedent in the repo, permanently bloating git history for every consumer clone; this evidence belongs on the PR/issue, not in the package repository. Additionally, this line promises that 'final automated checks and adversarial-review disposition are recorded alongside this evidence', but no such record exists in the tree, leaving the evidence document self-referentially incomplete.", + "failure_scenario": "Every future clone, CI checkout, and fork of react-native-bottom-tabs downloads 32 MB of one-off issue videos forever (git history retains them even if later deleted), and reviewers relying on the README's promised checks/disposition record find it missing, undermining the evidentiary value the artifacts were committed to provide.", + "severity": "low" + } + ] +} diff --git a/artifacts/issue-532/verification/compatibility/custom-background-bottom.png b/artifacts/issue-532/verification/compatibility/custom-background-bottom.png new file mode 100644 index 00000000..ed9b22ae Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/custom-background-bottom.png differ diff --git a/artifacts/issue-532/verification/compatibility/custom-background-top.png b/artifacts/issue-532/verification/compatibility/custom-background-top.png new file mode 100644 index 00000000..59307ef1 Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/custom-background-top.png differ diff --git a/artifacts/issue-532/verification/compatibility/custom-tabbar.png b/artifacts/issue-532/verification/compatibility/custom-tabbar.png new file mode 100644 index 00000000..49f6760a Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/custom-tabbar.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-dark.png b/artifacts/issue-532/verification/compatibility/opaque-dark.png new file mode 100644 index 00000000..53d22a14 Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-dark.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-hide-hidden.png b/artifacts/issue-532/verification/compatibility/opaque-hide-hidden.png new file mode 100644 index 00000000..c2154cf3 Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-hide-hidden.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-hide-restored.png b/artifacts/issue-532/verification/compatibility/opaque-hide-restored.png new file mode 100644 index 00000000..c217e69c Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-hide-restored.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-hide-shown.png b/artifacts/issue-532/verification/compatibility/opaque-hide-shown.png new file mode 100644 index 00000000..886e32b7 Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-hide-shown.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-light-restored.png b/artifacts/issue-532/verification/compatibility/opaque-light-restored.png new file mode 100644 index 00000000..f8c68e42 Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-light-restored.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-minimize-collapsed.png b/artifacts/issue-532/verification/compatibility/opaque-minimize-collapsed.png new file mode 100644 index 00000000..2fdc16dd Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-minimize-collapsed.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-minimize-expanded.png b/artifacts/issue-532/verification/compatibility/opaque-minimize-expanded.png new file mode 100644 index 00000000..696fedc8 Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-minimize-expanded.png differ diff --git a/artifacts/issue-532/verification/compatibility/opaque-minimize-restored.png b/artifacts/issue-532/verification/compatibility/opaque-minimize-restored.png new file mode 100644 index 00000000..46ea0dac Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/opaque-minimize-restored.png differ diff --git a/artifacts/issue-532/verification/compatibility/translucent-false.png b/artifacts/issue-532/verification/compatibility/translucent-false.png new file mode 100644 index 00000000..72b87973 Binary files /dev/null and b/artifacts/issue-532/verification/compatibility/translucent-false.png differ diff --git a/artifacts/issue-532/verification/screenshots/default-bottom.png b/artifacts/issue-532/verification/screenshots/default-bottom.png new file mode 100644 index 00000000..4c1d57f8 Binary files /dev/null and b/artifacts/issue-532/verification/screenshots/default-bottom.png differ diff --git a/artifacts/issue-532/verification/screenshots/default-top.png b/artifacts/issue-532/verification/screenshots/default-top.png new file mode 100644 index 00000000..a062fed2 Binary files /dev/null and b/artifacts/issue-532/verification/screenshots/default-top.png differ diff --git a/artifacts/issue-532/verification/screenshots/opaque-bottom.png b/artifacts/issue-532/verification/screenshots/opaque-bottom.png new file mode 100644 index 00000000..e64221c5 Binary files /dev/null and b/artifacts/issue-532/verification/screenshots/opaque-bottom.png differ diff --git a/artifacts/issue-532/verification/screenshots/opaque-top.png b/artifacts/issue-532/verification/screenshots/opaque-top.png new file mode 100644 index 00000000..75cf4cc8 Binary files /dev/null and b/artifacts/issue-532/verification/screenshots/opaque-top.png differ diff --git a/artifacts/issue-532/verification/screenshots/transparent-bottom.png b/artifacts/issue-532/verification/screenshots/transparent-bottom.png new file mode 100644 index 00000000..e1e01241 Binary files /dev/null and b/artifacts/issue-532/verification/screenshots/transparent-bottom.png differ diff --git a/artifacts/issue-532/verification/screenshots/transparent-top.png b/artifacts/issue-532/verification/screenshots/transparent-top.png new file mode 100644 index 00000000..26c7ae03 Binary files /dev/null and b/artifacts/issue-532/verification/screenshots/transparent-top.png differ diff --git a/artifacts/issue-532/verification/videos/default-scroll.gesture-telemetry.json b/artifacts/issue-532/verification/videos/default-scroll.gesture-telemetry.json new file mode 100644 index 00000000..8b13ee9f --- /dev/null +++ b/artifacts/issue-532/verification/videos/default-scroll.gesture-telemetry.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "generatedAt": "2026-08-31T18:52:17.764Z", + "events": [ + { + "kind": "scroll", + "tMs": 105, + "x": 201, + "y": 787, + "x2": 201, + "y2": 87, + "referenceWidth": 402, + "referenceHeight": 874, + "durationMs": 250, + "contentDirection": "down", + "amount": 3, + "pixels": 700 + } + ] +} \ No newline at end of file diff --git a/artifacts/issue-532/verification/videos/default-scroll.mp4 b/artifacts/issue-532/verification/videos/default-scroll.mp4 new file mode 100644 index 00000000..7ee97d8f Binary files /dev/null and b/artifacts/issue-532/verification/videos/default-scroll.mp4 differ diff --git a/artifacts/issue-532/verification/videos/opaque-scroll.gesture-telemetry.json b/artifacts/issue-532/verification/videos/opaque-scroll.gesture-telemetry.json new file mode 100644 index 00000000..abe1c3e2 --- /dev/null +++ b/artifacts/issue-532/verification/videos/opaque-scroll.gesture-telemetry.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "generatedAt": "2026-08-31T18:53:08.107Z", + "events": [ + { + "kind": "scroll", + "tMs": 102, + "x": 201, + "y": 787, + "x2": 201, + "y2": 87, + "referenceWidth": 402, + "referenceHeight": 874, + "durationMs": 250, + "contentDirection": "down", + "amount": 3, + "pixels": 700 + } + ] +} \ No newline at end of file diff --git a/artifacts/issue-532/verification/videos/opaque-scroll.mp4 b/artifacts/issue-532/verification/videos/opaque-scroll.mp4 new file mode 100644 index 00000000..88f0e093 Binary files /dev/null and b/artifacts/issue-532/verification/videos/opaque-scroll.mp4 differ diff --git a/artifacts/issue-532/verification/videos/transparent-scroll.gesture-telemetry.json b/artifacts/issue-532/verification/videos/transparent-scroll.gesture-telemetry.json new file mode 100644 index 00000000..df2dccab --- /dev/null +++ b/artifacts/issue-532/verification/videos/transparent-scroll.gesture-telemetry.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "generatedAt": "2026-08-31T18:52:41.806Z", + "events": [ + { + "kind": "scroll", + "tMs": 106, + "x": 201, + "y": 787, + "x2": 201, + "y2": 87, + "referenceWidth": 402, + "referenceHeight": 874, + "durationMs": 250, + "contentDirection": "down", + "amount": 3, + "pixels": 700 + } + ] +} \ No newline at end of file diff --git a/artifacts/issue-532/verification/videos/transparent-scroll.mp4 b/artifacts/issue-532/verification/videos/transparent-scroll.mp4 new file mode 100644 index 00000000..6a558e07 Binary files /dev/null and b/artifacts/issue-532/verification/videos/transparent-scroll.mp4 differ diff --git a/packages/react-native-bottom-tabs/ios/TabViewImpl.swift b/packages/react-native-bottom-tabs/ios/TabViewImpl.swift index 68053e1f..28155eaa 100644 --- a/packages/react-native-bottom-tabs/ios/TabViewImpl.swift +++ b/packages/react-native-bottom-tabs/ios/TabViewImpl.swift @@ -133,6 +133,19 @@ struct TabViewImpl: View { tabBar.isHidden = props.tabBarHidden + #if os(iOS) + if #available(iOS 26.0, *) { + if props.scrollEdgeAppearance == "transparent" { + tabBar.backgroundColor = nil + } else if let barTintColor = props.barTintColor { + tabBar.backgroundColor = barTintColor + } else { + let isOpaque = props.scrollEdgeAppearance == "opaque" || !props.translucent + tabBar.backgroundColor = isOpaque ? .systemBackground : nil + } + } + #endif + if props.scrollEdgeAppearance == "transparent" { configureTransparentAppearance(tabBar: tabBar, props: props) return