Uh oh!
There was an error while loading. Please reload this page.
fix(mobile): replace Callstack glass with Expo glass - #224
Merged
Conversation
Adopted from upstream `pingdotgg/t3code#8862` (`9b2d04317`). Consolidates onto the glass library the app already uses. `expo-glass-effect` was the primary — `GlassSurface` and `native-glass` were built on it — while `@callstack/liquid-glass` survived in only two files. Expo reapplies glass after native layout and window reattachment, where UIKit can otherwise leave the label visible but lose the material behind it. The support predicate swaps to Pylon's existing `NATIVE_LIQUID_GLASS_SUPPORTED`, which is semantically identical: both resolve to "iOS and the native glass API is available". Remaining changes are API renames (`effect` to `glassEffectStyle`, `interactive` to `isInteractive`). Drops the `@callstack/liquid-glass` dependency; no consumers remain.
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
The comment carried over from upstream described GlassView's window
handling while sitting above the withUniwind call, where it reads as if it
justifies the options object. It does not, and the options object is
load-bearing: uniwind treats any prop ending in "Style" as a style prop, so
auto mode would pass glassEffectStyle={[undefined, "regular"]} into a native
enum and lose the effect. The old `effect` prop did not end in "Style",
which is why auto mode was safe before the rename.
Uses the wording Pylon already records at GlassSurface.tsx, so a future
simplification does not drop the options object and silently lose the glass
style.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second of the mobile batch. Adopted from upstream
pingdotgg/t3code#8862(9b2d04317). Depends on #223, which createdfloating-working-control.tsx.What this does
Consolidates onto the glass library the app was already standardised on.
expo-glass-effectwas the primary — bothGlassSurfaceandnative-glassarebuilt on it — while
@callstack/liquid-glasssurvived in only two files. Thisremoves the second library and its native pod.
Upstream's stated reason for the switch: Expo reapplies glass after native layout
and window reattachment, where UIKit can otherwise leave the label visible but
lose the material behind it.
The rest is API renames —
effect→glassEffectStyle,interactive→isInteractive, andisLiquidGlassSupported→ Pylon's existingNATIVE_LIQUID_GLASS_SUPPORTED.Port fidelity
The cherry-pick applied with no conflicts, so I checked for silent drops rather
than trusting that. For both changed components,
diff(upstreamParent, upstream)and
diff(pylon, HEAD)are line-for-line identical — no Pylon divergence waspresent in these files and none was lost.
Two things verified rather than assumed:
version of this description.
@callstackchecks@available(iOS 26)AND theabsence of
UIDesignRequiresCompatibility; Expo'sisGlassEffectAPIAvailablechecks
@available(iOS 26)AND a runtimeUIGlassEffectprobe. Neitherimplies the other, and Expo's other export
isLiquidGlassAvailableis thecloser analogue. This is latent rather than active:
app.config.tsdoes notset
UIDesignRequiresCompatibility, so today the two agree. If it were everset as an iOS 26 escape hatch, headers and tab bars would go legacy while
these two components kept rendering glass. Timing is genuinely equivalent —
both are import-time module constants over OS/build-fixed values.
@callstack/liquid-glassconsumers remainanywhere in
apps/orpackages/.The docs edit stays Pylon-voiced and only widens the sentence to cover the
working timer and scroll-to-end button.
Verification
@t3tools/mobiletypecheck clean, lint clean, 194 mobile thread tests passing.Because this drops a native dependency and CI does not build iOS on this PR,
I regenerated the native project rather than relying on the JS bundle:
expo prebuild --platform iosplus CocoaPods. Confirmed by inspecting the output, notthe exit code —
PylonDev.xcworkspaceexists,Podfile.lockhas zeroliquid-glassreferences and still carriesexpo-glass-effect. A full simulatorbuild against the regenerated project follows.
Worth noting the regenerated workspace is
PylonDev.xcworkspace; the checkouthad a stale
T3CodeDev.xcworkspaceleft from before the Pylon rename.Native build:
** BUILD SUCCEEDED **, zero errors and zeroliquid-glassreferences anywhere in the build log. Read from the log, not the exit code.
Simulator pass (iOS 26.3)
Adversarial review raised a blocking concern worth recording, because it was
specific and testable: the library being removed ships an explicit UIKit
workaround (
contentView.isUserInteractionEnabled = true) for a bug whereUIGlassEffectcan leave a glass view's content non-interactive when childrenmount after
setupView(). Expo'sGlassView.swifthas no such line, andisInteractive— which this PR introduces to Pylon for the first time — wrapsthe only tappable control inside a glass view. Predicted symptom: a dead
scroll-to-end button.
It does not reproduce. Tested on a fresh native build against real seeded
threads, in both code paths:
UniwindGlassViewwithisInteractive(no work running) — tapscrolled the feed to the end and the button correctly disappeared;
GlassContainerwith the working timer — same result.The likely reason: Expo's
GlassView.swiftcarries 7layoutSubviews/didMoveToWindowhooks that re-run setup, whereasGlassContainer.swifthasnone. Also verified visually: both pills render with correct
rounded-fullgeometry, so the unclamped-
borderRadiusconcern does not manifest either.The working-timer branch needs a live turn, so it was exercised by temporarily
forcing
showWorkingControlon and then reverting — no such change is in thediff, and all six gating conditions are intact on the branch.
Reviewed and integrated with Claude Opus 5 in Claude Code.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.