Image editor mobile layout update (#613)
* Image editor mobile layout update * Minor viewport fixzio/stable
parent
aa786068cf
commit
e2055dfb78
|
@ -52,16 +52,14 @@ export class GalleryModel {
|
|||
}
|
||||
|
||||
async edit(image: ImageModel) {
|
||||
if (!isNative) {
|
||||
if (isNative) {
|
||||
this.crop(image)
|
||||
} else {
|
||||
this.rootStore.shell.openModal({
|
||||
name: 'edit-image',
|
||||
image,
|
||||
gallery: this,
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
this.crop(image)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@ import {compressAndResizeImageForPost} from 'lib/media/manip'
|
|||
// Cases to consider: ExternalEmbed
|
||||
|
||||
export interface ImageManipulationAttributes {
|
||||
aspectRatio?: '4:3' | '1:1' | '3:4' | 'None'
|
||||
rotate?: number
|
||||
scale?: number
|
||||
position?: Position
|
||||
flipHorizontal?: boolean
|
||||
flipVertical?: boolean
|
||||
aspectRatio?: '4:3' | '1:1' | '3:4' | 'None'
|
||||
}
|
||||
|
||||
export class ImageModel implements RNImage {
|
||||
|
@ -34,14 +34,14 @@ export class ImageModel implements RNImage {
|
|||
scaledHeight: number = POST_IMG_MAX.height
|
||||
|
||||
// Web manipulation
|
||||
aspectRatio?: ImageManipulationAttributes['aspectRatio']
|
||||
position?: Position = undefined
|
||||
prev?: RNImage = undefined
|
||||
rotation?: number = 0
|
||||
scale?: number = 1
|
||||
flipHorizontal?: boolean = false
|
||||
flipVertical?: boolean = false
|
||||
|
||||
prev?: RNImage
|
||||
attributes: ImageManipulationAttributes = {
|
||||
aspectRatio: '1:1',
|
||||
scale: 1,
|
||||
flipHorizontal: false,
|
||||
flipVertical: false,
|
||||
rotate: 0,
|
||||
}
|
||||
prevAttributes: ImageManipulationAttributes = {}
|
||||
|
||||
constructor(public rootStore: RootStoreModel, image: RNImage) {
|
||||
|
@ -65,6 +65,25 @@ export class ImageModel implements RNImage {
|
|||
// : MAX_IMAGE_SIZE_IN_BYTES / this.size
|
||||
// }
|
||||
|
||||
setRatio(aspectRatio: ImageManipulationAttributes['aspectRatio']) {
|
||||
this.attributes.aspectRatio = aspectRatio
|
||||
}
|
||||
|
||||
setRotate(degrees: number) {
|
||||
this.attributes.rotate = degrees
|
||||
this.manipulate({})
|
||||
}
|
||||
|
||||
flipVertical() {
|
||||
this.attributes.flipVertical = !this.attributes.flipVertical
|
||||
this.manipulate({})
|
||||
}
|
||||
|
||||
flipHorizontal() {
|
||||
this.attributes.flipHorizontal = !this.attributes.flipHorizontal
|
||||
this.manipulate({})
|
||||
}
|
||||
|
||||
get ratioMultipliers() {
|
||||
return {
|
||||
'4:3': 4 / 3,
|
||||
|
@ -162,33 +181,19 @@ export class ImageModel implements RNImage {
|
|||
crop?: ActionCrop['crop']
|
||||
} & ImageManipulationAttributes,
|
||||
) {
|
||||
const {aspectRatio, crop, flipHorizontal, flipVertical, rotate, scale} =
|
||||
attributes
|
||||
const {aspectRatio, crop, position, scale} = attributes
|
||||
const modifiers = []
|
||||
|
||||
if (flipHorizontal !== undefined) {
|
||||
this.flipHorizontal = flipHorizontal
|
||||
}
|
||||
|
||||
if (flipVertical !== undefined) {
|
||||
this.flipVertical = flipVertical
|
||||
}
|
||||
|
||||
if (this.flipHorizontal) {
|
||||
if (this.attributes.flipHorizontal) {
|
||||
modifiers.push({flip: FlipType.Horizontal})
|
||||
}
|
||||
|
||||
if (this.flipVertical) {
|
||||
if (this.attributes.flipVertical) {
|
||||
modifiers.push({flip: FlipType.Vertical})
|
||||
}
|
||||
|
||||
// TODO: Fix rotation -- currently not functional
|
||||
if (rotate !== undefined) {
|
||||
this.rotation = rotate
|
||||
}
|
||||
|
||||
if (this.rotation !== undefined) {
|
||||
modifiers.push({rotate: this.rotation})
|
||||
if (this.attributes.rotate !== undefined) {
|
||||
modifiers.push({rotate: this.attributes.rotate})
|
||||
}
|
||||
|
||||
if (crop !== undefined) {
|
||||
|
@ -203,18 +208,21 @@ export class ImageModel implements RNImage {
|
|||
}
|
||||
|
||||
if (scale !== undefined) {
|
||||
this.scale = scale
|
||||
this.attributes.scale = scale
|
||||
}
|
||||
|
||||
if (position !== undefined) {
|
||||
this.attributes.position = position
|
||||
}
|
||||
|
||||
if (aspectRatio !== undefined) {
|
||||
this.aspectRatio = aspectRatio
|
||||
this.attributes.aspectRatio = aspectRatio
|
||||
}
|
||||
|
||||
const ratioMultiplier = this.ratioMultipliers[this.aspectRatio ?? '1:1']
|
||||
const ratioMultiplier =
|
||||
this.ratioMultipliers[this.attributes.aspectRatio ?? '1:1']
|
||||
|
||||
// TODO: Ollie - should support up to 2000 but smaller images that scale
|
||||
// up need an updated compression factor calculation. Use 1000 for now.
|
||||
const MAX_SIDE = 1000
|
||||
const MAX_SIDE = 2000
|
||||
|
||||
const result = await ImageManipulator.manipulateAsync(
|
||||
this.path,
|
||||
|
@ -223,7 +231,7 @@ export class ImageModel implements RNImage {
|
|||
{resize: ratioMultiplier > 1 ? {width: MAX_SIDE} : {height: MAX_SIDE}},
|
||||
],
|
||||
{
|
||||
compress: 0.7, // TODO: revisit compression calculation
|
||||
compress: 0.9,
|
||||
format: SaveFormat.JPEG,
|
||||
},
|
||||
)
|
||||
|
@ -238,16 +246,12 @@ export class ImageModel implements RNImage {
|
|||
})
|
||||
}
|
||||
|
||||
resetCompressed() {
|
||||
this.manipulate({})
|
||||
}
|
||||
|
||||
previous() {
|
||||
this.compressed = this.prev
|
||||
|
||||
const {flipHorizontal, flipVertical, rotate, position, scale} =
|
||||
this.prevAttributes
|
||||
|
||||
this.scale = scale
|
||||
this.rotation = rotate
|
||||
this.flipHorizontal = flipHorizontal
|
||||
this.flipVertical = flipVertical
|
||||
this.position = position
|
||||
this.attributes = this.prevAttributes
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,148 +18,114 @@ import {Slider} from '@miblanchard/react-native-slider'
|
|||
import {MaterialIcons} from '@expo/vector-icons'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {getKeys} from 'lib/type-assertions'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
export const snapPoints = ['80%']
|
||||
|
||||
const RATIOS = {
|
||||
'4:3': {
|
||||
Icon: RectWideIcon,
|
||||
},
|
||||
'1:1': {
|
||||
Icon: SquareIcon,
|
||||
},
|
||||
'3:4': {
|
||||
Icon: RectTallIcon,
|
||||
},
|
||||
None: {
|
||||
label: 'None',
|
||||
Icon: MaterialIcons,
|
||||
name: 'do-not-disturb-alt',
|
||||
},
|
||||
} as const
|
||||
|
||||
type AspectRatio = keyof typeof RATIOS
|
||||
|
||||
interface Props {
|
||||
image: ImageModel
|
||||
gallery: GalleryModel
|
||||
}
|
||||
|
||||
// This is only used for desktop web
|
||||
export const Component = observer(function ({image, gallery}: Props) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {shell} = store
|
||||
const theme = useTheme()
|
||||
const winDim = useWindowDimensions()
|
||||
const store = useStores()
|
||||
const windowDimensions = useWindowDimensions()
|
||||
|
||||
const [altText, setAltText] = useState(image.altText)
|
||||
const [aspectRatio, setAspectRatio] = useState<AspectRatio>(
|
||||
image.aspectRatio ?? 'None',
|
||||
)
|
||||
const [flipHorizontal, setFlipHorizontal] = useState<boolean>(
|
||||
image.flipHorizontal ?? false,
|
||||
)
|
||||
const [flipVertical, setFlipVertical] = useState<boolean>(
|
||||
image.flipVertical ?? false,
|
||||
)
|
||||
const {
|
||||
aspectRatio,
|
||||
// rotate = 0
|
||||
} = image.attributes
|
||||
|
||||
// TODO: doesn't seem to be working correctly with crop
|
||||
// const [rotation, setRotation] = useState(image.rotation ?? 0)
|
||||
const [scale, setScale] = useState<number>(image.scale ?? 1)
|
||||
const [position, setPosition] = useState<Position>()
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
const editorRef = useRef<ImageEditor>(null)
|
||||
|
||||
const imgEditorStyles = useMemo(() => {
|
||||
const dim = Math.min(425, winDim.width - 24)
|
||||
return {width: dim, height: dim}
|
||||
}, [winDim.width])
|
||||
|
||||
const manipulationAttributes = useMemo(
|
||||
() => ({
|
||||
// TODO: doesn't seem to be working correctly with crop
|
||||
// ...(rotation !== undefined ? {rotate: rotation} : {}),
|
||||
...(flipHorizontal !== undefined ? {flipHorizontal} : {}),
|
||||
...(flipVertical !== undefined ? {flipVertical} : {}),
|
||||
}),
|
||||
[flipHorizontal, flipVertical],
|
||||
const [scale, setScale] = useState<number>(image.attributes.scale ?? 1)
|
||||
const [position, setPosition] = useState<Position | undefined>(
|
||||
image.attributes.position,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const manipulateImage = async () => {
|
||||
await image.manipulate(manipulationAttributes)
|
||||
}
|
||||
|
||||
manipulateImage()
|
||||
}, [image, manipulationAttributes])
|
||||
|
||||
const ratios = useMemo(
|
||||
() =>
|
||||
({
|
||||
'4:3': {
|
||||
hint: 'Sets image aspect ratio to wide',
|
||||
Icon: RectWideIcon,
|
||||
},
|
||||
'1:1': {
|
||||
hint: 'Sets image aspect ratio to square',
|
||||
Icon: SquareIcon,
|
||||
},
|
||||
'3:4': {
|
||||
hint: 'Sets image aspect ratio to tall',
|
||||
Icon: RectTallIcon,
|
||||
},
|
||||
None: {
|
||||
label: 'None',
|
||||
hint: 'Sets image aspect ratio to tall',
|
||||
Icon: MaterialIcons,
|
||||
name: 'do-not-disturb-alt',
|
||||
},
|
||||
} as const),
|
||||
[],
|
||||
)
|
||||
|
||||
type AspectRatio = keyof typeof ratios
|
||||
const [altText, setAltText] = useState('')
|
||||
|
||||
const onFlipHorizontal = useCallback(() => {
|
||||
setFlipHorizontal(!flipHorizontal)
|
||||
image.manipulate({flipHorizontal})
|
||||
}, [flipHorizontal, image])
|
||||
image.flipHorizontal()
|
||||
}, [image])
|
||||
|
||||
const onFlipVertical = useCallback(() => {
|
||||
setFlipVertical(!flipVertical)
|
||||
image.manipulate({flipVertical})
|
||||
}, [flipVertical, image])
|
||||
image.flipVertical()
|
||||
}, [image])
|
||||
|
||||
// const onSetRotate = useCallback(
|
||||
// (direction: 'left' | 'right') => {
|
||||
// const rotation = (rotate + 90 * (direction === 'left' ? -1 : 1)) % 360
|
||||
// image.setRotate(rotation)
|
||||
// },
|
||||
// [rotate, image],
|
||||
// )
|
||||
|
||||
const onSetRatio = useCallback(
|
||||
(ratio: AspectRatio) => {
|
||||
image.setRatio(ratio)
|
||||
},
|
||||
[image],
|
||||
)
|
||||
|
||||
const adjustments = useMemo(
|
||||
() =>
|
||||
[
|
||||
() => [
|
||||
// {
|
||||
// name: 'rotate-left',
|
||||
// name: 'rotate-left' as const,
|
||||
// label: 'Rotate left',
|
||||
// hint: 'Rotate image left',
|
||||
// onPress: () => {
|
||||
// const rotate = (rotation - 90) % 360
|
||||
// setRotation(rotate)
|
||||
// image.manipulate({rotate})
|
||||
// onSetRotate('left')
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'rotate-right',
|
||||
// name: 'rotate-right' as const,
|
||||
// label: 'Rotate right',
|
||||
// hint: 'Rotate image right',
|
||||
// onPress: () => {
|
||||
// const rotate = (rotation + 90) % 360
|
||||
// setRotation(rotate)
|
||||
// image.manipulate({rotate})
|
||||
// onSetRotate('right')
|
||||
// },
|
||||
// },
|
||||
{
|
||||
name: 'flip',
|
||||
name: 'flip' as const,
|
||||
label: 'Flip horizontal',
|
||||
hint: 'Flip image horizontally',
|
||||
onPress: onFlipHorizontal,
|
||||
},
|
||||
{
|
||||
name: 'flip',
|
||||
name: 'flip' as const,
|
||||
label: 'Flip vertically',
|
||||
hint: 'Flip image vertically',
|
||||
onPress: onFlipVertical,
|
||||
},
|
||||
] as const,
|
||||
],
|
||||
[onFlipHorizontal, onFlipVertical],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
image.prev = image.compressed
|
||||
setIsEditing(true)
|
||||
image.prevAttributes = image.attributes
|
||||
image.resetCompressed()
|
||||
}, [image])
|
||||
|
||||
const onCloseModal = useCallback(() => {
|
||||
shell.closeModal()
|
||||
setIsEditing(false)
|
||||
}, [shell])
|
||||
store.shell.closeModal()
|
||||
}, [store.shell])
|
||||
|
||||
const onPressCancel = useCallback(async () => {
|
||||
await gallery.previous(image)
|
||||
|
@ -184,25 +150,12 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
...(position !== undefined ? {position} : {}),
|
||||
}
|
||||
: {}),
|
||||
...manipulationAttributes,
|
||||
aspectRatio,
|
||||
})
|
||||
|
||||
image.prevAttributes = manipulationAttributes
|
||||
image.prev = image.compressed
|
||||
image.prevAttributes = image.attributes
|
||||
onCloseModal()
|
||||
}, [
|
||||
altText,
|
||||
aspectRatio,
|
||||
image,
|
||||
manipulationAttributes,
|
||||
position,
|
||||
scale,
|
||||
onCloseModal,
|
||||
])
|
||||
|
||||
const onPressRatio = useCallback((as: AspectRatio) => {
|
||||
setAspectRatio(as)
|
||||
}, [])
|
||||
}, [altText, image, position, scale, onCloseModal])
|
||||
|
||||
const getLabelIconSize = useCallback((as: AspectRatio) => {
|
||||
switch (as) {
|
||||
|
@ -220,26 +173,35 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
return null
|
||||
}
|
||||
|
||||
const {width, height} = image.getDisplayDimensions(
|
||||
aspectRatio,
|
||||
imgEditorStyles.width,
|
||||
)
|
||||
const computedWidth =
|
||||
windowDimensions.width > 500 ? 410 : windowDimensions.width - 80
|
||||
const sideLength = isDesktopWeb ? 300 : computedWidth
|
||||
|
||||
const dimensions = image.getDisplayDimensions(aspectRatio, sideLength)
|
||||
const imgContainerStyles = {width: sideLength, height: sideLength}
|
||||
|
||||
const imgControlStyles = {
|
||||
alignItems: 'center' as const,
|
||||
flexDirection: isDesktopWeb ? ('row' as const) : ('column' as const),
|
||||
gap: isDesktopWeb ? 5 : 0,
|
||||
}
|
||||
|
||||
return (
|
||||
<View testID="editImageModal" style={[pal.view, styles.container, s.flex1]}>
|
||||
<Text style={[styles.title, pal.text]}>Edit image</Text>
|
||||
<View style={[styles.gap18, s.flexRow]}>
|
||||
<View>
|
||||
<View style={[styles.imgContainer, imgEditorStyles, pal.borderDark]}>
|
||||
<View
|
||||
style={[styles.imgContainer, pal.borderDark, imgContainerStyles]}>
|
||||
<ImageEditor
|
||||
ref={editorRef}
|
||||
style={styles.imgEditor}
|
||||
image={isEditing ? image.compressed.path : image.path}
|
||||
width={width}
|
||||
height={height}
|
||||
image={image.compressed.path}
|
||||
scale={scale}
|
||||
border={0}
|
||||
position={position}
|
||||
onPositionChange={setPosition}
|
||||
{...dimensions}
|
||||
/>
|
||||
</View>
|
||||
<Slider
|
||||
|
@ -250,10 +212,16 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
minimumValue={1}
|
||||
maximumValue={3}
|
||||
/>
|
||||
<View style={[s.flexRow, styles.gap18]}>
|
||||
<View style={styles.imgControls}>
|
||||
{getKeys(ratios).map(ratio => {
|
||||
const {hint, Icon, ...props} = ratios[ratio]
|
||||
</View>
|
||||
<View>
|
||||
{isDesktopWeb ? (
|
||||
<Text type="sm-bold" style={pal.text}>
|
||||
Ratios
|
||||
</Text>
|
||||
) : null}
|
||||
<View style={imgControlStyles}>
|
||||
{getKeys(RATIOS).map(ratio => {
|
||||
const {Icon, ...props} = RATIOS[ratio]
|
||||
const labelIconSize = getLabelIconSize(ratio)
|
||||
const isSelected = aspectRatio === ratio
|
||||
|
||||
|
@ -261,10 +229,10 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
<Pressable
|
||||
key={ratio}
|
||||
onPress={() => {
|
||||
onPressRatio(ratio)
|
||||
onSetRatio(ratio)
|
||||
}}
|
||||
accessibilityLabel={ratio}
|
||||
accessibilityHint={hint}>
|
||||
accessibilityHint="">
|
||||
<Icon
|
||||
size={labelIconSize}
|
||||
style={[styles.imgControl, isSelected ? s.blue3 : pal.text]}
|
||||
|
@ -281,18 +249,22 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
)
|
||||
})}
|
||||
</View>
|
||||
<View style={[styles.verticalSep, pal.border]} />
|
||||
<View style={styles.imgControls}>
|
||||
{adjustments.map(({label, hint, name, onPress}) => (
|
||||
{isDesktopWeb ? (
|
||||
<Text type="sm-bold" style={[pal.text, styles.subsection]}>
|
||||
Transformations
|
||||
</Text>
|
||||
) : null}
|
||||
<View style={imgControlStyles}>
|
||||
{adjustments.map(({label, name, onPress}) => (
|
||||
<Pressable
|
||||
key={label}
|
||||
onPress={onPress}
|
||||
accessibilityLabel={label}
|
||||
accessibilityHint={hint}
|
||||
accessibilityHint=""
|
||||
style={styles.flipBtn}>
|
||||
<MaterialIcons
|
||||
name={name}
|
||||
size={label.startsWith('Flip') ? 22 : 24}
|
||||
size={label?.startsWith('Flip') ? 22 : 24}
|
||||
style={[
|
||||
pal.text,
|
||||
label === 'Flip vertically'
|
||||
|
@ -305,7 +277,10 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={[styles.gap18]}>
|
||||
<View style={[styles.gap18, styles.bottomSection, pal.border]}>
|
||||
<Text type="sm-bold" style={pal.text} nativeID="alt-text">
|
||||
Accessibility
|
||||
</Text>
|
||||
<TextInput
|
||||
testID="altTextImageInput"
|
||||
style={[styles.textArea, pal.border, pal.text]}
|
||||
|
@ -313,11 +288,9 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
multiline
|
||||
value={altText}
|
||||
onChangeText={text => setAltText(enforceLen(text, MAX_ALT_TEXT))}
|
||||
placeholder="Image description"
|
||||
placeholderTextColor={pal.colors.textLight}
|
||||
accessibilityLabel="Image alt text"
|
||||
accessibilityHint="Sets image alt text for screenreaders"
|
||||
accessibilityLabelledBy="imageAltText"
|
||||
accessibilityLabel="Alt text"
|
||||
accessibilityHint=""
|
||||
accessibilityLabelledBy="alt-text"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.btns}>
|
||||
|
@ -345,30 +318,16 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
gap: 18,
|
||||
paddingVertical: 18,
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: isDesktopWeb ? undefined : 16,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
},
|
||||
gap18: {
|
||||
gap: 18,
|
||||
},
|
||||
|
||||
subsection: {marginTop: 12},
|
||||
gap18: {gap: 18},
|
||||
title: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 24,
|
||||
},
|
||||
|
||||
textArea: {
|
||||
borderWidth: 1,
|
||||
borderRadius: 6,
|
||||
paddingTop: 10,
|
||||
paddingHorizontal: 12,
|
||||
fontSize: 16,
|
||||
height: 100,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
|
||||
btns: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
|
@ -379,28 +338,12 @@ const styles = StyleSheet.create({
|
|||
paddingVertical: 8,
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
|
||||
verticalSep: {
|
||||
borderLeftWidth: 1,
|
||||
},
|
||||
|
||||
imgControls: {
|
||||
flexDirection: 'row',
|
||||
gap: 5,
|
||||
},
|
||||
imgControl: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: 40,
|
||||
},
|
||||
flipVertical: {
|
||||
transform: [{rotate: '90deg'}],
|
||||
},
|
||||
flipBtn: {
|
||||
paddingHorizontal: 4,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
imgEditor: {
|
||||
maxWidth: '100%',
|
||||
},
|
||||
|
@ -408,11 +351,29 @@ const styles = StyleSheet.create({
|
|||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: 425,
|
||||
width: 425,
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
borderStyle: 'solid',
|
||||
overflow: 'hidden',
|
||||
marginBottom: 4,
|
||||
},
|
||||
flipVertical: {
|
||||
transform: [{rotate: '90deg'}],
|
||||
},
|
||||
flipBtn: {
|
||||
paddingHorizontal: 4,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
textArea: {
|
||||
borderWidth: 1,
|
||||
borderRadius: 6,
|
||||
paddingTop: 10,
|
||||
paddingHorizontal: 12,
|
||||
fontSize: 16,
|
||||
height: 100,
|
||||
textAlignVertical: 'top',
|
||||
maxHeight: isDesktopWeb ? undefined : 50,
|
||||
},
|
||||
bottomSection: {
|
||||
borderTopWidth: 1,
|
||||
paddingTop: 18,
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue