Improvements to the alt text behaviors in the composer (#910)
* Add an image preview in the alt modal * Composer: add info about alt text and a green checkmark when done * Shrink the alt visual indicator a bit so it doesnt obscure the image * Fix typo * Fix: avoid requiring multiple tabs to save alt text * update react-native-screens * Improve the alt text help tip * Remove redundant hints --------- Co-authored-by: Ansh Nanda <anshnanda10@gmail.com>zio/stable
parent
25b3e14926
commit
bfaa6d73f3
|
@ -126,7 +126,7 @@
|
||||||
"react-native-reanimated": "^3.3.0",
|
"react-native-reanimated": "^3.3.0",
|
||||||
"react-native-root-siblings": "^4.1.1",
|
"react-native-root-siblings": "^4.1.1",
|
||||||
"react-native-safe-area-context": "^4.4.1",
|
"react-native-safe-area-context": "^4.4.1",
|
||||||
"react-native-screens": "^3.13.1",
|
"react-native-screens": "^3.20.0",
|
||||||
"react-native-splash-screen": "^3.3.0",
|
"react-native-splash-screen": "^3.3.0",
|
||||||
"react-native-svg": "13.4.0",
|
"react-native-svg": "13.4.0",
|
||||||
"react-native-url-polyfill": "^1.3.0",
|
"react-native-url-polyfill": "^1.3.0",
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import React, {useCallback} from 'react'
|
import React from 'react'
|
||||||
import {ImageStyle, Keyboard} from 'react-native'
|
import {ImageStyle, Keyboard} from 'react-native'
|
||||||
import {GalleryModel} from 'state/models/media/gallery'
|
import {GalleryModel} from 'state/models/media/gallery'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
import {ImageModel} from 'state/models/media/image'
|
|
||||||
import {Image} from 'expo-image'
|
import {Image} from 'expo-image'
|
||||||
import {Text} from 'view/com/util/text/Text'
|
import {Text} from 'view/com/util/text/Text'
|
||||||
import {isDesktopWeb} from 'platform/detection'
|
import {isDesktopWeb} from 'platform/detection'
|
||||||
import {openAltTextModal} from 'lib/media/alt-text'
|
import {openAltTextModal} from 'lib/media/alt-text'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
gallery: GalleryModel
|
gallery: GalleryModel
|
||||||
|
@ -18,67 +18,39 @@ interface Props {
|
||||||
|
|
||||||
export const Gallery = observer(function ({gallery}: Props) {
|
export const Gallery = observer(function ({gallery}: Props) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const getImageStyle = useCallback(() => {
|
const pal = usePalette('default')
|
||||||
let side: number
|
|
||||||
|
|
||||||
if (gallery.size === 1) {
|
let side: number
|
||||||
side = 250
|
|
||||||
} else {
|
|
||||||
side = (isDesktopWeb ? 560 : 350) / gallery.size
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
if (gallery.size === 1) {
|
||||||
height: side,
|
side = 250
|
||||||
width: side,
|
} else {
|
||||||
}
|
side = (isDesktopWeb ? 560 : 350) / gallery.size
|
||||||
}, [gallery])
|
}
|
||||||
|
|
||||||
const imageStyle = getImageStyle()
|
const imageStyle = {
|
||||||
const handleAddImageAltText = useCallback(
|
height: side,
|
||||||
(image: ImageModel) => {
|
width: side,
|
||||||
Keyboard.dismiss()
|
}
|
||||||
openAltTextModal(store, image)
|
|
||||||
},
|
|
||||||
[store],
|
|
||||||
)
|
|
||||||
const handleRemovePhoto = useCallback(
|
|
||||||
(image: ImageModel) => {
|
|
||||||
gallery.remove(image)
|
|
||||||
},
|
|
||||||
[gallery],
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleEditPhoto = useCallback(
|
|
||||||
(image: ImageModel) => {
|
|
||||||
gallery.edit(image)
|
|
||||||
},
|
|
||||||
[gallery],
|
|
||||||
)
|
|
||||||
|
|
||||||
const isOverflow = !isDesktopWeb && gallery.size > 2
|
const isOverflow = !isDesktopWeb && gallery.size > 2
|
||||||
|
|
||||||
const imageControlLabelStyle = {
|
const altTextControlStyle = isOverflow
|
||||||
borderRadius: 5,
|
? {
|
||||||
paddingHorizontal: 10,
|
left: 4,
|
||||||
position: 'absolute' as const,
|
bottom: 4,
|
||||||
zIndex: 1,
|
}
|
||||||
...(isOverflow
|
: isDesktopWeb && gallery.size < 3
|
||||||
? {
|
? {
|
||||||
left: 4,
|
left: 8,
|
||||||
bottom: 4,
|
top: 8,
|
||||||
}
|
}
|
||||||
: isDesktopWeb && gallery.size < 3
|
: {
|
||||||
? {
|
left: 4,
|
||||||
left: 8,
|
top: 4,
|
||||||
top: 8,
|
}
|
||||||
}
|
|
||||||
: {
|
|
||||||
left: 4,
|
|
||||||
top: 4,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
const imageControlsSubgroupStyle = {
|
const imageControlsStyle = {
|
||||||
display: 'flex' as const,
|
display: 'flex' as const,
|
||||||
flexDirection: 'row' as const,
|
flexDirection: 'row' as const,
|
||||||
position: 'absolute' as const,
|
position: 'absolute' as const,
|
||||||
|
@ -103,63 +75,90 @@ export const Gallery = observer(function ({gallery}: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return !gallery.isEmpty ? (
|
return !gallery.isEmpty ? (
|
||||||
<View testID="selectedPhotosView" style={styles.gallery}>
|
<>
|
||||||
{gallery.images.map(image => (
|
<View testID="selectedPhotosView" style={styles.gallery}>
|
||||||
<View key={`selected-image-${image.path}`} style={[imageStyle]}>
|
{gallery.images.map(image => (
|
||||||
<TouchableOpacity
|
<View key={`selected-image-${image.path}`} style={[imageStyle]}>
|
||||||
testID="altTextButton"
|
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel="Add alt text"
|
|
||||||
accessibilityHint=""
|
|
||||||
onPress={() => {
|
|
||||||
handleAddImageAltText(image)
|
|
||||||
}}
|
|
||||||
style={imageControlLabelStyle}>
|
|
||||||
<Text style={styles.imageControlTextContent}>ALT</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<View style={imageControlsSubgroupStyle}>
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="editPhotoButton"
|
testID="altTextButton"
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel="Edit image"
|
accessibilityLabel="Add alt text"
|
||||||
accessibilityHint=""
|
accessibilityHint=""
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
handleEditPhoto(image)
|
Keyboard.dismiss()
|
||||||
|
openAltTextModal(store, image)
|
||||||
}}
|
}}
|
||||||
style={styles.imageControl}>
|
style={[styles.altTextControl, altTextControlStyle]}>
|
||||||
<FontAwesomeIcon
|
<Text style={styles.altTextControlLabel}>ALT</Text>
|
||||||
icon="pen"
|
{image.altText.length > 0 ? (
|
||||||
size={12}
|
<FontAwesomeIcon
|
||||||
style={{color: colors.white}}
|
icon="check"
|
||||||
/>
|
size={10}
|
||||||
|
style={{color: colors.green3}}
|
||||||
|
/>
|
||||||
|
) : undefined}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
<View style={imageControlsStyle}>
|
||||||
|
<TouchableOpacity
|
||||||
|
testID="editPhotoButton"
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel="Edit image"
|
||||||
|
accessibilityHint=""
|
||||||
|
onPress={() => gallery.edit(image)}
|
||||||
|
style={styles.imageControl}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="pen"
|
||||||
|
size={12}
|
||||||
|
style={{color: colors.white}}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
testID="removePhotoButton"
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel="Remove image"
|
||||||
|
accessibilityHint=""
|
||||||
|
onPress={() => gallery.remove(image)}
|
||||||
|
style={styles.imageControl}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="xmark"
|
||||||
|
size={16}
|
||||||
|
style={{color: colors.white}}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="removePhotoButton"
|
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel="Remove image"
|
accessibilityLabel="Add alt text"
|
||||||
accessibilityHint=""
|
accessibilityHint=""
|
||||||
onPress={() => handleRemovePhoto(image)}
|
onPress={() => {
|
||||||
style={styles.imageControl}>
|
Keyboard.dismiss()
|
||||||
<FontAwesomeIcon
|
openAltTextModal(store, image)
|
||||||
icon="xmark"
|
}}
|
||||||
size={16}
|
style={styles.altTextHiddenRegion}
|
||||||
style={{color: colors.white}}
|
/>
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Image
|
<Image
|
||||||
testID="selectedPhotoImage"
|
testID="selectedPhotoImage"
|
||||||
style={[styles.image, imageStyle] as ImageStyle}
|
style={[styles.image, imageStyle] as ImageStyle}
|
||||||
source={{
|
source={{
|
||||||
uri: image.cropped?.path ?? image.path,
|
uri: image.cropped?.path ?? image.path,
|
||||||
}}
|
}}
|
||||||
accessible={true}
|
accessible={true}
|
||||||
accessibilityIgnoresInvertColors
|
accessibilityIgnoresInvertColors
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
<View style={[styles.reminder]}>
|
||||||
|
<View style={[styles.infoIcon, pal.viewLight]}>
|
||||||
|
<FontAwesomeIcon icon="info" size={12} color={pal.colors.text} />
|
||||||
</View>
|
</View>
|
||||||
))}
|
<Text type="sm" style={[pal.textLight, s.flex1]}>
|
||||||
</View>
|
Alt text describes images for blind and low-vision users, and helps
|
||||||
|
give context to everyone.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
) : null
|
) : null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -179,19 +178,46 @@ const styles = StyleSheet.create({
|
||||||
height: 24,
|
height: 24,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
borderWidth: 0.5,
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
imageControlTextContent: {
|
altTextControl: {
|
||||||
|
position: 'absolute',
|
||||||
|
zIndex: 1,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
paddingVertical: 3,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
altTextControlLabel: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
},
|
||||||
borderWidth: 0.5,
|
altTextHiddenRegion: {
|
||||||
paddingHorizontal: 10,
|
position: 'absolute',
|
||||||
paddingVertical: 3,
|
left: 4,
|
||||||
|
right: 4,
|
||||||
|
bottom: 4,
|
||||||
|
top: 30,
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
reminder: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
borderRadius: 8,
|
||||||
|
paddingVertical: 14,
|
||||||
|
},
|
||||||
|
infoIcon: {
|
||||||
|
width: 22,
|
||||||
|
height: 22,
|
||||||
|
borderRadius: 12,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
import React, {useCallback, useState} from 'react'
|
import React, {useMemo, useCallback, useState} from 'react'
|
||||||
import {StyleSheet, TextInput, TouchableOpacity, View} from 'react-native'
|
import {
|
||||||
|
ImageStyle,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
useWindowDimensions,
|
||||||
|
} from 'react-native'
|
||||||
|
import {Image} from 'expo-image'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {gradients, s} from 'lib/styles'
|
import {gradients, s} from 'lib/styles'
|
||||||
import {enforceLen} from 'lib/strings/helpers'
|
import {enforceLen} from 'lib/strings/helpers'
|
||||||
|
@ -8,7 +18,7 @@ import {useTheme} from 'lib/ThemeContext'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {isDesktopWeb} from 'platform/detection'
|
import {isDesktopWeb, isAndroid} from 'platform/detection'
|
||||||
import {ImageModel} from 'state/models/media/image'
|
import {ImageModel} from 'state/models/media/image'
|
||||||
|
|
||||||
export const snapPoints = ['fullscreen']
|
export const snapPoints = ['fullscreen']
|
||||||
|
@ -22,6 +32,24 @@ export function Component({image}: Props) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const [altText, setAltText] = useState(image.altText)
|
const [altText, setAltText] = useState(image.altText)
|
||||||
|
const windim = useWindowDimensions()
|
||||||
|
|
||||||
|
const imageStyles = useMemo<ImageStyle>(() => {
|
||||||
|
const maxWidth = isDesktopWeb ? 450 : windim.width
|
||||||
|
if (image.height > image.width) {
|
||||||
|
return {
|
||||||
|
resizeMode: 'contain',
|
||||||
|
width: '100%',
|
||||||
|
aspectRatio: 1,
|
||||||
|
borderRadius: 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
width: '100%',
|
||||||
|
height: (maxWidth / image.width) * image.height,
|
||||||
|
borderRadius: 8,
|
||||||
|
}
|
||||||
|
}, [image, windim])
|
||||||
|
|
||||||
const onPressSave = useCallback(() => {
|
const onPressSave = useCallback(() => {
|
||||||
image.setAltText(altText)
|
image.setAltText(altText)
|
||||||
|
@ -33,69 +61,94 @@ export function Component({image}: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<KeyboardAvoidingView
|
||||||
testID="altTextImageModal"
|
behavior={isAndroid ? 'height' : 'padding'}
|
||||||
style={[pal.view, styles.container, s.flex1]}
|
style={[pal.view, styles.container]}>
|
||||||
nativeID="imageAltText">
|
<ScrollView
|
||||||
<Text style={[styles.title, pal.text]}>Add alt text</Text>
|
testID="altTextImageModal"
|
||||||
<TextInput
|
style={styles.scrollContainer}
|
||||||
testID="altTextImageInput"
|
keyboardShouldPersistTaps="always"
|
||||||
style={[styles.textArea, pal.border, pal.text]}
|
nativeID="imageAltText">
|
||||||
keyboardAppearance={theme.colorScheme}
|
<View style={styles.scrollInner}>
|
||||||
multiline
|
<View style={[pal.viewLight, styles.imageContainer]}>
|
||||||
value={altText}
|
<Image
|
||||||
onChangeText={text => setAltText(enforceLen(text, MAX_ALT_TEXT))}
|
testID="selectedPhotoImage"
|
||||||
accessibilityLabel="Image alt text"
|
style={imageStyles}
|
||||||
accessibilityHint="Sets image alt text for screenreaders"
|
source={{
|
||||||
accessibilityLabelledBy="imageAltText"
|
uri: image.cropped?.path ?? image.path,
|
||||||
/>
|
}}
|
||||||
<View style={styles.buttonControls}>
|
accessible={true}
|
||||||
<TouchableOpacity
|
accessibilityIgnoresInvertColors
|
||||||
testID="altTextImageSaveBtn"
|
/>
|
||||||
onPress={onPressSave}
|
|
||||||
accessibilityLabel="Save alt text"
|
|
||||||
accessibilityHint={`Saves alt text, which reads: ${altText}`}
|
|
||||||
accessibilityRole="button">
|
|
||||||
<LinearGradient
|
|
||||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
|
||||||
start={{x: 0, y: 0}}
|
|
||||||
end={{x: 1, y: 1}}
|
|
||||||
style={[styles.button]}>
|
|
||||||
<Text type="button-lg" style={[s.white, s.bold]}>
|
|
||||||
Save
|
|
||||||
</Text>
|
|
||||||
</LinearGradient>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity
|
|
||||||
testID="altTextImageCancelBtn"
|
|
||||||
onPress={onPressCancel}
|
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel="Cancel add image alt text"
|
|
||||||
accessibilityHint="Exits adding alt text to image"
|
|
||||||
onAccessibilityEscape={onPressCancel}>
|
|
||||||
<View style={[styles.button]}>
|
|
||||||
<Text type="button-lg" style={[pal.textLight]}>
|
|
||||||
Cancel
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
<TextInput
|
||||||
</View>
|
testID="altTextImageInput"
|
||||||
</View>
|
style={[styles.textArea, pal.border, pal.text]}
|
||||||
|
keyboardAppearance={theme.colorScheme}
|
||||||
|
multiline
|
||||||
|
placeholder="Add alt text"
|
||||||
|
placeholderTextColor={pal.colors.textLight}
|
||||||
|
value={altText}
|
||||||
|
onChangeText={text => setAltText(enforceLen(text, MAX_ALT_TEXT))}
|
||||||
|
accessibilityLabel="Image alt text"
|
||||||
|
accessibilityHint=""
|
||||||
|
accessibilityLabelledBy="imageAltText"
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
<View style={styles.buttonControls}>
|
||||||
|
<TouchableOpacity
|
||||||
|
testID="altTextImageSaveBtn"
|
||||||
|
onPress={onPressSave}
|
||||||
|
accessibilityLabel="Save alt text"
|
||||||
|
accessibilityHint={`Saves alt text, which reads: ${altText}`}
|
||||||
|
accessibilityRole="button">
|
||||||
|
<LinearGradient
|
||||||
|
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||||
|
start={{x: 0, y: 0}}
|
||||||
|
end={{x: 1, y: 1}}
|
||||||
|
style={[styles.button]}>
|
||||||
|
<Text type="button-lg" style={[s.white, s.bold]}>
|
||||||
|
Save
|
||||||
|
</Text>
|
||||||
|
</LinearGradient>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
testID="altTextImageCancelBtn"
|
||||||
|
onPress={onPressCancel}
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel="Cancel add image alt text"
|
||||||
|
accessibilityHint=""
|
||||||
|
onAccessibilityEscape={onPressCancel}>
|
||||||
|
<View style={[styles.button]}>
|
||||||
|
<Text type="button-lg" style={[pal.textLight]}>
|
||||||
|
Cancel
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</KeyboardAvoidingView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
gap: 18,
|
flex: 1,
|
||||||
paddingVertical: isDesktopWeb ? 0 : 18,
|
|
||||||
paddingHorizontal: isDesktopWeb ? 0 : 12,
|
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
paddingVertical: isDesktopWeb ? 0 : 18,
|
||||||
},
|
},
|
||||||
title: {
|
scrollContainer: {
|
||||||
textAlign: 'center',
|
flex: 1,
|
||||||
fontWeight: 'bold',
|
height: '100%',
|
||||||
fontSize: 24,
|
paddingHorizontal: isDesktopWeb ? 0 : 12,
|
||||||
|
},
|
||||||
|
scrollInner: {
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
imageContainer: {
|
||||||
|
borderRadius: 8,
|
||||||
},
|
},
|
||||||
textArea: {
|
textArea: {
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
|
|
|
@ -45,23 +45,28 @@ export const GalleryItem: FC<GalleryItemProps> = ({
|
||||||
accessibilityIgnoresInvertColors
|
accessibilityIgnoresInvertColors
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
{image.alt === '' ? null : <Text style={styles.alt}>ALT</Text>}
|
{image.alt === '' ? null : (
|
||||||
|
<View style={styles.altContainer}>
|
||||||
|
<Text style={styles.alt}>ALT</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
alt: {
|
altContainer: {
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
color: 'white',
|
paddingHorizontal: 6,
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
letterSpacing: 1,
|
|
||||||
paddingHorizontal: 10,
|
|
||||||
paddingVertical: 3,
|
paddingVertical: 3,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 6,
|
left: 6,
|
||||||
bottom: 6,
|
bottom: 6,
|
||||||
},
|
},
|
||||||
|
alt: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -126,7 +126,11 @@ export function PostEmbeds({
|
||||||
onPress={() => openLightbox(0)}
|
onPress={() => openLightbox(0)}
|
||||||
onPressIn={() => onPressIn(0)}
|
onPressIn={() => onPressIn(0)}
|
||||||
style={styles.singleImage}>
|
style={styles.singleImage}>
|
||||||
{alt === '' ? null : <Text style={styles.alt}>ALT</Text>}
|
{alt === '' ? null : (
|
||||||
|
<View style={styles.altContainer}>
|
||||||
|
<Text style={styles.alt}>ALT</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</AutoSizedImage>
|
</AutoSizedImage>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -201,17 +205,18 @@ const styles = StyleSheet.create({
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
},
|
},
|
||||||
alt: {
|
altContainer: {
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
color: 'white',
|
paddingHorizontal: 6,
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
letterSpacing: 1,
|
|
||||||
paddingHorizontal: 10,
|
|
||||||
paddingVertical: 3,
|
paddingVertical: 3,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 6,
|
left: 6,
|
||||||
bottom: 6,
|
bottom: 6,
|
||||||
},
|
},
|
||||||
|
alt: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -15339,10 +15339,10 @@ react-native-safe-area-context@^4.4.1:
|
||||||
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.5.3.tgz#e98eb1a73a6b3846d296545fe74760754dbaaa69"
|
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.5.3.tgz#e98eb1a73a6b3846d296545fe74760754dbaaa69"
|
||||||
integrity sha512-ihYeGDEBSkYH+1aWnadNhVtclhppVgd/c0tm4mj0+HV11FoiWJ8N6ocnnZnRLvM5Fxc+hUqxR9bm5AXU3rXiyA==
|
integrity sha512-ihYeGDEBSkYH+1aWnadNhVtclhppVgd/c0tm4mj0+HV11FoiWJ8N6ocnnZnRLvM5Fxc+hUqxR9bm5AXU3rXiyA==
|
||||||
|
|
||||||
react-native-screens@^3.13.1:
|
react-native-screens@^3.20.0:
|
||||||
version "3.20.0"
|
version "3.22.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.20.0.tgz#4d154177395e5541387d9a05bc2e12e54d2fb5b1"
|
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.22.0.tgz#7d892baf964fddb642b5eec71a09e2aeb501e578"
|
||||||
integrity sha512-joWUKWAVHxymP3mL9gYApFHAsbd9L6ZcmpoZa6Sl3W/82bvvNVMqcfP7MeNqVCg73qZ8yL4fW+J/syusHleUgg==
|
integrity sha512-csLypBSXIt/egh37YJmokETptZJCtZdoZBsZNLR9n31GesDyVogprT+MM22dEPDuxPxt/mFWq+lSpVwk7khuTw==
|
||||||
dependencies:
|
dependencies:
|
||||||
react-freeze "^1.0.0"
|
react-freeze "^1.0.0"
|
||||||
warn-once "^0.1.0"
|
warn-once "^0.1.0"
|
||||||
|
|
Loading…
Reference in New Issue