Add iOS 26 fluid zoom transition to alt text dialog (#9970)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-03-05 02:32:08 +00:00
committed by GitHub
parent 7fd218c97d
commit 1782a65174
6 changed files with 33 additions and 4 deletions
@@ -48,6 +48,8 @@ class BottomSheetModule : Module() {
Prop("preventExpansion") { view: BottomSheetView, prop: Boolean -> Prop("preventExpansion") { view: BottomSheetView, prop: Boolean ->
view.preventExpansion = prop view.preventExpansion = prop
} }
Prop("sourceViewTag") { _: BottomSheetView, _: Int? -> }
} }
} }
} }
@@ -42,6 +42,10 @@ public class BottomSheetModule: Module {
Prop("preventExpansion") { (view: SheetView, prop: Bool) in Prop("preventExpansion") { (view: SheetView, prop: Bool) in
view.preventExpansion = prop view.preventExpansion = prop
} }
Prop("sourceViewTag") { (view: SheetView, prop: Int?) in
view.sourceViewTag = prop
}
} }
} }
} }
+10
View File
@@ -26,6 +26,7 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
var preventDismiss = false var preventDismiss = false
var preventExpansion = false var preventExpansion = false
var cornerRadius: CGFloat? var cornerRadius: CGFloat?
var sourceViewTag: Int?
var minHeight = 0.0 var minHeight = 0.0
var maxHeight: CGFloat! { var maxHeight: CGFloat! {
didSet { didSet {
@@ -135,6 +136,15 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
} }
sheetVc.view.addSubview(innerView) sheetVc.view.addSubview(innerView)
if #available(iOS 26.0, *),
let tag = self.sourceViewTag,
let bridge = self.appContext?.reactBridge,
let sourceView = bridge.uiManager.view(forReactTag: NSNumber(value: tag)) {
sheetVc.preferredTransition = .zoom { _ in
return sourceView
}
}
self.sheetVc = sheetVc self.sheetVc = sheetVc
self.isOpening = true self.isOpening = true
@@ -1,5 +1,4 @@
import React from 'react' import {type ColorValue, type NativeSyntheticEvent} from 'react-native'
import {ColorValue, NativeSyntheticEvent} from 'react-native'
export type BottomSheetState = 'closed' | 'closing' | 'open' | 'opening' export type BottomSheetState = 'closed' | 'closing' | 'open' | 'opening'
@@ -25,6 +24,7 @@ export interface BottomSheetViewProps {
backgroundColor?: ColorValue backgroundColor?: ColorValue
containerBackgroundColor?: ColorValue containerBackgroundColor?: ColorValue
disableDrag?: boolean disableDrag?: boolean
sourceViewTag?: number
minHeight?: number minHeight?: number
maxHeight?: number maxHeight?: number
+12 -1
View File
@@ -1,5 +1,6 @@
import React from 'react' import React, {useState} from 'react'
import { import {
findNodeHandle,
type ImageStyle, type ImageStyle,
Keyboard, Keyboard,
type LayoutChangeEvent, type LayoutChangeEvent,
@@ -144,6 +145,14 @@ const GalleryItem = ({
const altTextControl = Dialog.useDialogControl() const altTextControl = Dialog.useDialogControl()
const editControl = Dialog.useDialogControl() const editControl = Dialog.useDialogControl()
const [altBtnViewTag, setAltBtnViewTag] = useState<number>()
const altBtnRef = (node: View | null) => {
if (node) {
const tag = findNodeHandle(node)
if (tag != null) setAltBtnViewTag(tag)
}
}
const onImageEdit = () => { const onImageEdit = () => {
if (IS_NATIVE) { if (IS_NATIVE) {
@@ -162,6 +171,7 @@ const GalleryItem = ({
return ( return (
<View <View
ref={altBtnRef}
style={imageStyle as ViewStyle} style={imageStyle as ViewStyle}
// Fixes ALT and icons appearing with half opacity when the post is inactive // Fixes ALT and icons appearing with half opacity when the post is inactive
renderToHardwareTextureAndroid> renderToHardwareTextureAndroid>
@@ -240,6 +250,7 @@ const GalleryItem = ({
control={altTextControl} control={altTextControl}
image={image} image={image}
onChange={onChange} onChange={onChange}
sourceViewTag={altBtnViewTag}
/> />
<EditImageDialog <EditImageDialog
@@ -23,12 +23,14 @@ type Props = {
control: Dialog.DialogOuterProps['control'] control: Dialog.DialogOuterProps['control']
image: ComposerImage image: ComposerImage
onChange: (next: ComposerImage) => void onChange: (next: ComposerImage) => void
sourceViewTag?: number
} }
export const ImageAltTextDialog = ({ export const ImageAltTextDialog = ({
control, control,
image, image,
onChange, onChange,
sourceViewTag,
}: Props): React.ReactNode => { }: Props): React.ReactNode => {
const {height: minHeight} = useWindowDimensions() const {height: minHeight} = useWindowDimensions()
const [altText, setAltText] = useState(image.alt) const [altText, setAltText] = useState(image.alt)
@@ -42,7 +44,7 @@ export const ImageAltTextDialog = ({
alt: enforceLen(altText, MAX_ALT_TEXT, true), alt: enforceLen(altText, MAX_ALT_TEXT, true),
}) })
}} }}
nativeOptions={{minHeight}}> nativeOptions={{minHeight, sourceViewTag}}>
<Dialog.Handle /> <Dialog.Handle />
<ImageAltTextInner <ImageAltTextInner
control={control} control={control}