* Add alt text support and rework image layout * Add additional BottomSheet implementation to account for nested Composer modal * Use mobile gallery layout on mobile web * Missing key * Fix lint * Move altimage modal into the standard modal system * Fix overflow wrapping of images * Fixes to the alt-image modal * Remove unnecessary switch * Restore old imagelayoutgrid code --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>
104 lines
2.2 KiB
TypeScript
104 lines
2.2 KiB
TypeScript
import React from 'react'
|
|
import {
|
|
StyleProp,
|
|
StyleSheet,
|
|
TouchableOpacity,
|
|
View,
|
|
ViewStyle,
|
|
} from 'react-native'
|
|
import {Image} from 'expo-image'
|
|
import {clamp} from 'lib/numbers'
|
|
import {useStores} from 'state/index'
|
|
import {Dimensions} from 'lib/media/types'
|
|
|
|
export const DELAY_PRESS_IN = 500
|
|
const MIN_ASPECT_RATIO = 0.33 // 1/3
|
|
const MAX_ASPECT_RATIO = 5 // 5/1
|
|
|
|
interface Props {
|
|
alt?: string
|
|
uri: string
|
|
onPress?: () => void
|
|
onLongPress?: () => void
|
|
onPressIn?: () => void
|
|
style?: StyleProp<ViewStyle>
|
|
children?: React.ReactNode
|
|
}
|
|
|
|
export function AutoSizedImage({
|
|
alt,
|
|
uri,
|
|
onPress,
|
|
onLongPress,
|
|
onPressIn,
|
|
style,
|
|
children = null,
|
|
}: Props) {
|
|
const store = useStores()
|
|
const [dim, setDim] = React.useState<Dimensions | undefined>(
|
|
store.imageSizes.get(uri),
|
|
)
|
|
const [aspectRatio, setAspectRatio] = React.useState<number>(
|
|
dim ? calc(dim) : 1,
|
|
)
|
|
React.useEffect(() => {
|
|
let aborted = false
|
|
if (dim) {
|
|
return
|
|
}
|
|
store.imageSizes.fetch(uri).then(newDim => {
|
|
if (aborted) {
|
|
return
|
|
}
|
|
setDim(newDim)
|
|
setAspectRatio(calc(newDim))
|
|
})
|
|
}, [dim, setDim, setAspectRatio, store, uri])
|
|
|
|
if (onPress || onLongPress || onPressIn) {
|
|
return (
|
|
<TouchableOpacity
|
|
onPress={onPress}
|
|
onLongPress={onLongPress}
|
|
onPressIn={onPressIn}
|
|
delayPressIn={DELAY_PRESS_IN}
|
|
style={[styles.container, style]}>
|
|
<Image
|
|
style={[styles.image, {aspectRatio}]}
|
|
source={uri}
|
|
accessible={true} // Must set for `accessibilityLabel` to work
|
|
accessibilityLabel={alt}
|
|
/>
|
|
{children}
|
|
</TouchableOpacity>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<View style={[styles.container, style]}>
|
|
<Image
|
|
style={[styles.image, {aspectRatio}]}
|
|
source={{uri}}
|
|
accessible={true} // Must set for `accessibilityLabel` to work
|
|
accessibilityLabel={alt}
|
|
/>
|
|
{children}
|
|
</View>
|
|
)
|
|
}
|
|
|
|
function calc(dim: Dimensions) {
|
|
if (dim.width === 0 || dim.height === 0) {
|
|
return 1
|
|
}
|
|
return clamp(dim.width / dim.height, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
overflow: 'hidden',
|
|
},
|
|
image: {
|
|
width: '100%',
|
|
},
|
|
})
|