Fix iOS sheet keyboard handling using native scrollview features (#9959)
This commit is contained in:
@@ -18,7 +18,7 @@ import {BottomSheetSnapPoint} from '../../../modules/bottom-sheet/src/BottomShee
|
|||||||
|
|
||||||
export const Context = createContext<DialogContextProps>({
|
export const Context = createContext<DialogContextProps>({
|
||||||
close: () => {},
|
close: () => {},
|
||||||
IS_NATIVEDialog: false,
|
isNativeDialog: false,
|
||||||
nativeSnapPoint: BottomSheetSnapPoint.Hidden,
|
nativeSnapPoint: BottomSheetSnapPoint.Hidden,
|
||||||
disableDrag: false,
|
disableDrag: false,
|
||||||
setDisableDrag: () => {},
|
setDisableDrag: () => {},
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
import React, {useImperativeHandle} from 'react'
|
import React, {useImperativeHandle} from 'react'
|
||||||
import {
|
import {
|
||||||
|
type LayoutChangeEvent,
|
||||||
type NativeScrollEvent,
|
type NativeScrollEvent,
|
||||||
type NativeSyntheticEvent,
|
type NativeSyntheticEvent,
|
||||||
Pressable,
|
Pressable,
|
||||||
type ScrollView,
|
ScrollView,
|
||||||
type StyleProp,
|
type StyleProp,
|
||||||
TextInput,
|
TextInput,
|
||||||
View,
|
View,
|
||||||
type ViewStyle,
|
type ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {
|
import {useReanimatedKeyboardAnimation} from 'react-native-keyboard-controller'
|
||||||
KeyboardAwareScrollView,
|
|
||||||
type KeyboardAwareScrollViewRef,
|
|
||||||
useKeyboardHandler,
|
|
||||||
useReanimatedKeyboardAnimation,
|
|
||||||
} from 'react-native-keyboard-controller'
|
|
||||||
import Animated, {
|
import Animated, {
|
||||||
runOnJS,
|
runOnJS,
|
||||||
type ScrollEvent,
|
type ScrollEvent,
|
||||||
@@ -29,7 +25,7 @@ import {logger} from '#/logger'
|
|||||||
import {useA11y} from '#/state/a11y'
|
import {useA11y} from '#/state/a11y'
|
||||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||||
import {List, type ListMethods, type ListProps} from '#/view/com/util/List'
|
import {List, type ListMethods, type ListProps} from '#/view/com/util/List'
|
||||||
import {atoms as a, ios, platform, tokens, useTheme} from '#/alf'
|
import {android, atoms as a, ios, platform, tokens, useTheme} from '#/alf'
|
||||||
import {useThemeName} from '#/alf/util/useColorModeTheme'
|
import {useThemeName} from '#/alf/util/useColorModeTheme'
|
||||||
import {Context, useDialogContext} from '#/components/Dialog/context'
|
import {Context, useDialogContext} from '#/components/Dialog/context'
|
||||||
import {
|
import {
|
||||||
@@ -154,7 +150,7 @@ export function Outer({
|
|||||||
const context = React.useMemo(
|
const context = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
close,
|
close,
|
||||||
IS_NATIVEDialog: true,
|
isNativeDialog: true,
|
||||||
nativeSnapPoint: snapPoint,
|
nativeSnapPoint: snapPoint,
|
||||||
disableDrag,
|
disableDrag,
|
||||||
setDisableDrag,
|
setDisableDrag,
|
||||||
@@ -212,33 +208,17 @@ export const ScrollableInner = React.forwardRef<ScrollView, DialogInnerProps>(
|
|||||||
) {
|
) {
|
||||||
const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext()
|
const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext()
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
|
const isAtMaxSnapPoint = nativeSnapPoint === BottomSheetSnapPoint.Full
|
||||||
const [keyboardHeight, setKeyboardHeight] = React.useState(0)
|
|
||||||
|
|
||||||
// note: iOS-only. keyboard-controller doesn't seem to work inside the sheets on Android
|
|
||||||
useKeyboardHandler(
|
|
||||||
{
|
|
||||||
onEnd: e => {
|
|
||||||
'worklet'
|
|
||||||
runOnJS(setKeyboardHeight)(e.height)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
|
|
||||||
let paddingBottom = 0
|
let paddingBottom = 0
|
||||||
if (IS_IOS) {
|
if (IS_IOS) {
|
||||||
paddingBottom += keyboardHeight / 4
|
paddingBottom = tokens.space._2xl
|
||||||
if (nativeSnapPoint === BottomSheetSnapPoint.Full) {
|
|
||||||
paddingBottom += insets.bottom + tokens.space.md
|
|
||||||
}
|
|
||||||
paddingBottom = Math.max(paddingBottom, tokens.space._2xl)
|
|
||||||
} else {
|
} else {
|
||||||
if (nativeSnapPoint === BottomSheetSnapPoint.Full) {
|
paddingBottom =
|
||||||
|
Math.max(insets.bottom, tokens.space._5xl) + tokens.space._2xl
|
||||||
|
if (isAtMaxSnapPoint) {
|
||||||
paddingBottom += insets.top
|
paddingBottom += insets.top
|
||||||
}
|
}
|
||||||
paddingBottom +=
|
|
||||||
Math.max(insets.bottom, tokens.space._5xl) + tokens.space._2xl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||||
@@ -254,18 +234,21 @@ export const ScrollableInner = React.forwardRef<ScrollView, DialogInnerProps>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardAwareScrollView
|
<ScrollView
|
||||||
contentContainerStyle={[
|
contentContainerStyle={[
|
||||||
a.pt_2xl,
|
a.pt_2xl,
|
||||||
IS_LIQUID_GLASS ? a.px_2xl : a.px_xl,
|
IS_LIQUID_GLASS ? a.px_2xl : a.px_xl,
|
||||||
{paddingBottom},
|
{paddingBottom},
|
||||||
contentContainerStyle,
|
contentContainerStyle,
|
||||||
]}
|
]}
|
||||||
ref={ref as React.Ref<KeyboardAwareScrollViewRef>}
|
ref={ref}
|
||||||
showsVerticalScrollIndicator={IS_ANDROID ? false : undefined}
|
showsVerticalScrollIndicator={IS_ANDROID ? false : undefined}
|
||||||
|
contentInsetAdjustmentBehavior={
|
||||||
|
isAtMaxSnapPoint ? 'automatic' : 'never'
|
||||||
|
}
|
||||||
|
automaticallyAdjustKeyboardInsets={isAtMaxSnapPoint}
|
||||||
{...props}
|
{...props}
|
||||||
bounces={nativeSnapPoint === BottomSheetSnapPoint.Full}
|
bounces={isAtMaxSnapPoint}
|
||||||
bottomOffset={30}
|
|
||||||
scrollEventThrottle={50}
|
scrollEventThrottle={50}
|
||||||
onScroll={IS_ANDROID ? onScroll : undefined}
|
onScroll={IS_ANDROID ? onScroll : undefined}
|
||||||
keyboardShouldPersistTaps="handled"
|
keyboardShouldPersistTaps="handled"
|
||||||
@@ -275,7 +258,7 @@ export const ScrollableInner = React.forwardRef<ScrollView, DialogInnerProps>(
|
|||||||
stickyHeaderIndices={ios(header ? [0] : undefined)}>
|
stickyHeaderIndices={ios(header ? [0] : undefined)}>
|
||||||
{header}
|
{header}
|
||||||
{children}
|
{children}
|
||||||
</KeyboardAwareScrollView>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -287,10 +270,15 @@ export const InnerFlatList = React.forwardRef<
|
|||||||
webInnerContentContainerStyle?: StyleProp<ViewStyle>
|
webInnerContentContainerStyle?: StyleProp<ViewStyle>
|
||||||
footer?: React.ReactNode
|
footer?: React.ReactNode
|
||||||
}
|
}
|
||||||
>(function InnerFlatList({footer, style, ...props}, ref) {
|
>(function InnerFlatList(
|
||||||
|
{headerOffset, footer, style, contentContainerStyle, ...props},
|
||||||
|
ref,
|
||||||
|
) {
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext()
|
const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext()
|
||||||
|
|
||||||
|
const isAtMaxSnapPoint = nativeSnapPoint === BottomSheetSnapPoint.Full
|
||||||
|
|
||||||
const onScroll = (e: ScrollEvent) => {
|
const onScroll = (e: ScrollEvent) => {
|
||||||
'worklet'
|
'worklet'
|
||||||
if (!IS_ANDROID) {
|
if (!IS_ANDROID) {
|
||||||
@@ -308,19 +296,36 @@ export const InnerFlatList = React.forwardRef<
|
|||||||
<ScrollProvider onScroll={onScroll}>
|
<ScrollProvider onScroll={onScroll}>
|
||||||
<List
|
<List
|
||||||
keyboardShouldPersistTaps="handled"
|
keyboardShouldPersistTaps="handled"
|
||||||
bounces={nativeSnapPoint === BottomSheetSnapPoint.Full}
|
contentInsetAdjustmentBehavior={
|
||||||
ListFooterComponent={<View style={{height: insets.bottom + 100}} />}
|
isAtMaxSnapPoint ? 'automatic' : 'never'
|
||||||
|
}
|
||||||
|
automaticallyAdjustKeyboardInsets={isAtMaxSnapPoint}
|
||||||
|
scrollIndicatorInsets={{top: headerOffset}}
|
||||||
|
bounces={isAtMaxSnapPoint}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
showsVerticalScrollIndicator={IS_ANDROID ? false : undefined}
|
showsVerticalScrollIndicator={IS_ANDROID ? false : undefined}
|
||||||
{...props}
|
{...props}
|
||||||
style={[a.h_full, style]}
|
style={[a.h_full, style]}
|
||||||
|
contentContainerStyle={[
|
||||||
|
{paddingTop: headerOffset},
|
||||||
|
android({
|
||||||
|
paddingBottom: insets.top + insets.bottom + tokens.space.xl,
|
||||||
|
}),
|
||||||
|
contentContainerStyle,
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
{footer}
|
{footer}
|
||||||
</ScrollProvider>
|
</ScrollProvider>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export function FlatListFooter({children}: {children: React.ReactNode}) {
|
export function FlatListFooter({
|
||||||
|
children,
|
||||||
|
onLayout,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
onLayout?: (event: LayoutChangeEvent) => void
|
||||||
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {top, bottom} = useSafeAreaInsets()
|
const {top, bottom} = useSafeAreaInsets()
|
||||||
const {height} = useReanimatedKeyboardAnimation()
|
const {height} = useReanimatedKeyboardAnimation()
|
||||||
@@ -334,6 +339,7 @@ export function FlatListFooter({children}: {children: React.ReactNode}) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
|
onLayout={onLayout}
|
||||||
style={[
|
style={[
|
||||||
a.absolute,
|
a.absolute,
|
||||||
a.bottom_0,
|
a.bottom_0,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
FlatList,
|
FlatList,
|
||||||
type FlatListProps,
|
type FlatListProps,
|
||||||
type GestureResponderEvent,
|
type GestureResponderEvent,
|
||||||
|
type LayoutChangeEvent,
|
||||||
Pressable,
|
Pressable,
|
||||||
type StyleProp,
|
type StyleProp,
|
||||||
View,
|
View,
|
||||||
@@ -98,7 +99,7 @@ export function Outer({
|
|||||||
const context = React.useMemo(
|
const context = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
close,
|
close,
|
||||||
IS_NATIVEDialog: false,
|
isNativeDialog: false,
|
||||||
nativeSnapPoint: 0,
|
nativeSnapPoint: 0,
|
||||||
disableDrag: false,
|
disableDrag: false,
|
||||||
setDisableDrag: () => {},
|
setDisableDrag: () => {},
|
||||||
@@ -253,11 +254,18 @@ export const InnerFlatList = React.forwardRef<
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export function FlatListFooter({children}: {children: React.ReactNode}) {
|
export function FlatListFooter({
|
||||||
|
children,
|
||||||
|
onLayout,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
onLayout?: (event: LayoutChangeEvent) => void
|
||||||
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
|
onLayout={onLayout}
|
||||||
style={[
|
style={[
|
||||||
a.absolute,
|
a.absolute,
|
||||||
a.bottom_0,
|
a.bottom_0,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export type DialogControlProps = DialogControlRefProps & {
|
|||||||
|
|
||||||
export type DialogContextProps = {
|
export type DialogContextProps = {
|
||||||
close: DialogControlProps['close']
|
close: DialogControlProps['close']
|
||||||
IS_NATIVEDialog: boolean
|
isNativeDialog: boolean
|
||||||
nativeSnapPoint: BottomSheetSnapPoint
|
nativeSnapPoint: BottomSheetSnapPoint
|
||||||
disableDrag: boolean
|
disableDrag: boolean
|
||||||
setDisableDrag: React.Dispatch<React.SetStateAction<boolean>>
|
setDisableDrag: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {type Language, LANGUAGES, LANGUAGES_MAP_CODE2} from '#/locale/languages'
|
|||||||
import {useLanguagePrefs} from '#/state/preferences/languages'
|
import {useLanguagePrefs} from '#/state/preferences/languages'
|
||||||
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
|
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
|
||||||
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
||||||
import {atoms as a, useTheme, web} from '#/alf'
|
import {atoms as a, tokens, useTheme, web} from '#/alf'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
import {SearchInput} from '#/components/forms/SearchInput'
|
import {SearchInput} from '#/components/forms/SearchInput'
|
||||||
@@ -84,6 +84,7 @@ export function DialogInner({
|
|||||||
}) {
|
}) {
|
||||||
const control = Dialog.useDialogContext()
|
const control = Dialog.useDialogContext()
|
||||||
const [headerHeight, setHeaderHeight] = useState(0)
|
const [headerHeight, setHeaderHeight] = useState(0)
|
||||||
|
const [footerHeight, setFooterHeight] = useState(0)
|
||||||
|
|
||||||
const allowedLanguages = useMemo(() => {
|
const allowedLanguages = useMemo(() => {
|
||||||
const uniqueLanguagesMap = LANGUAGES.filter(lang => !!lang.code2).reduce(
|
const uniqueLanguagesMap = LANGUAGES.filter(lang => !!lang.code2).reduce(
|
||||||
@@ -249,6 +250,8 @@ export function DialogInner({
|
|||||||
...displayedLanguages.all.map(lang => ({type: 'item', lang})),
|
...displayedLanguages.all.map(lang => ({type: 'item', lang})),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const numItems = flatListData.length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Toggle.Group
|
<Toggle.Group
|
||||||
values={checkedLanguagesCode2}
|
values={checkedLanguagesCode2}
|
||||||
@@ -261,9 +264,12 @@ export function DialogInner({
|
|||||||
data={flatListData}
|
data={flatListData}
|
||||||
ListHeaderComponent={listHeader}
|
ListHeaderComponent={listHeader}
|
||||||
stickyHeaderIndices={[0]}
|
stickyHeaderIndices={[0]}
|
||||||
contentContainerStyle={[a.gap_0]}
|
contentContainerStyle={[
|
||||||
style={[IS_NATIVE && a.px_lg, web({paddingBottom: 120})]}
|
a.gap_0,
|
||||||
scrollIndicatorInsets={{top: headerHeight}}
|
IS_NATIVE && {paddingBottom: footerHeight + tokens.space.xl},
|
||||||
|
]}
|
||||||
|
style={[IS_NATIVE && a.px_lg, IS_WEB && {paddingBottom: 120}]}
|
||||||
|
scrollIndicatorInsets={{top: headerHeight, bottom: footerHeight}}
|
||||||
renderItem={({item, index}) => {
|
renderItem={({item, index}) => {
|
||||||
if (item.type === 'header') {
|
if (item.type === 'header') {
|
||||||
return (
|
return (
|
||||||
@@ -283,6 +289,8 @@ export function DialogInner({
|
|||||||
}
|
}
|
||||||
const lang = item.lang
|
const lang = item.lang
|
||||||
|
|
||||||
|
const isLastItem = index === numItems - 1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Toggle.Item
|
<Toggle.Item
|
||||||
key={lang.code2}
|
key={lang.code2}
|
||||||
@@ -290,7 +298,7 @@ export function DialogInner({
|
|||||||
label={languageName(lang, langPrefs.appLanguage)}
|
label={languageName(lang, langPrefs.appLanguage)}
|
||||||
style={[
|
style={[
|
||||||
t.atoms.border_contrast_low,
|
t.atoms.border_contrast_low,
|
||||||
a.border_b,
|
!isLastItem && a.border_b,
|
||||||
a.rounded_0,
|
a.rounded_0,
|
||||||
a.px_0,
|
a.px_0,
|
||||||
a.py_md,
|
a.py_md,
|
||||||
@@ -303,7 +311,8 @@ export function DialogInner({
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
footer={
|
footer={
|
||||||
<Dialog.FlatListFooter>
|
<Dialog.FlatListFooter
|
||||||
|
onLayout={evt => setFooterHeight(evt.nativeEvent.layout.height)}>
|
||||||
<Button
|
<Button
|
||||||
label={_(msg`Close dialog`)}
|
label={_(msg`Close dialog`)}
|
||||||
onPress={handleClose}
|
onPress={handleClose}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import {useMemo, useState} from 'react'
|
||||||
import {type ImageStyle, useWindowDimensions, View} from 'react-native'
|
import {type ImageStyle, useWindowDimensions, View} from 'react-native'
|
||||||
import {Image} from 'expo-image'
|
import {Image} from 'expo-image'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {msg} from '@lingui/core/macro'
|
||||||
@@ -10,14 +10,14 @@ import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible'
|
|||||||
import {enforceLen} from '#/lib/strings/helpers'
|
import {enforceLen} from '#/lib/strings/helpers'
|
||||||
import {type ComposerImage} from '#/state/gallery'
|
import {type ComposerImage} from '#/state/gallery'
|
||||||
import {AltTextCounterWrapper} from '#/view/com/composer/AltTextCounterWrapper'
|
import {AltTextCounterWrapper} from '#/view/com/composer/AltTextCounterWrapper'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, tokens, useTheme} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
import {type DialogControlProps} from '#/components/Dialog'
|
import {type DialogControlProps} from '#/components/Dialog'
|
||||||
import * as TextField from '#/components/forms/TextField'
|
import * as TextField from '#/components/forms/TextField'
|
||||||
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {IS_ANDROID, IS_WEB} from '#/env'
|
import {IS_ANDROID, IS_LIQUID_GLASS, IS_WEB} from '#/env'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
control: Dialog.DialogOuterProps['control']
|
control: Dialog.DialogOuterProps['control']
|
||||||
@@ -31,7 +31,7 @@ export const ImageAltTextDialog = ({
|
|||||||
onChange,
|
onChange,
|
||||||
}: Props): React.ReactNode => {
|
}: Props): React.ReactNode => {
|
||||||
const {height: minHeight} = useWindowDimensions()
|
const {height: minHeight} = useWindowDimensions()
|
||||||
const [altText, setAltText] = React.useState(image.alt)
|
const [altText, setAltText] = useState(image.alt)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.Outer
|
<Dialog.Outer
|
||||||
@@ -67,12 +67,15 @@ const ImageAltTextInner = ({
|
|||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_, i18n} = useLingui()
|
const {_, i18n} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const windim = useWindowDimensions()
|
const {width: screenWidth} = useWindowDimensions()
|
||||||
|
|
||||||
const [isKeyboardVisible] = useIsKeyboardVisible()
|
const [isKeyboardVisible] = useIsKeyboardVisible()
|
||||||
|
|
||||||
const imageStyle = React.useMemo<ImageStyle>(() => {
|
const imageStyle = useMemo<ImageStyle>(() => {
|
||||||
const maxWidth = IS_WEB ? 450 : windim.width
|
const maxWidth = IS_WEB
|
||||||
|
? 450
|
||||||
|
: screenWidth - // account for dialog padding
|
||||||
|
2 * (IS_LIQUID_GLASS ? tokens.space._2xl : tokens.space.xl)
|
||||||
const source = image.transformed ?? image.source
|
const source = image.transformed ?? image.source
|
||||||
|
|
||||||
if (source.height > source.width) {
|
if (source.height > source.width) {
|
||||||
@@ -88,16 +91,20 @@ const ImageAltTextInner = ({
|
|||||||
height: (maxWidth / source.width) * source.height,
|
height: (maxWidth / source.width) * source.height,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
}
|
}
|
||||||
}, [image, windim])
|
}, [image, screenWidth])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.ScrollableInner label={_(msg`Add alt text`)}>
|
<Dialog.ScrollableInner label={_(msg`Add alt text`)}>
|
||||||
<Dialog.Close />
|
<Dialog.Close />
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
<Text style={[a.text_2xl, a.font_semi_bold, a.leading_tight, a.pb_sm]}>
|
{/* vertical space is too precious - gets scrolled out of the way anyway */}
|
||||||
<Trans>Add alt text</Trans>
|
{IS_WEB && (
|
||||||
</Text>
|
<Text
|
||||||
|
style={[a.text_2xl, a.font_semi_bold, a.leading_tight, a.pb_sm]}>
|
||||||
|
<Trans>Add alt text</Trans>
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
<View style={[t.atoms.bg_contrast_50, a.rounded_sm, a.overflow_hidden]}>
|
<View style={[t.atoms.bg_contrast_50, a.rounded_sm, a.overflow_hidden]}>
|
||||||
<Image
|
<Image
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export function SubtitleDialogBtn(props: Props) {
|
|||||||
)}
|
)}
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
<Dialog.Outer control={control}>
|
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
|
||||||
<Dialog.Handle />
|
<Dialog.Handle />
|
||||||
<SubtitleDialogInner {...props} />
|
<SubtitleDialogInner {...props} />
|
||||||
</Dialog.Outer>
|
</Dialog.Outer>
|
||||||
|
|||||||
Reference in New Issue
Block a user