Composer UI fixes (#6065)
* Fix close button overlap * Make footer actually sticky on web * Special toast for thread * Only stick to bottom for last post
This commit is contained in:
@@ -443,7 +443,9 @@ export const ComposePost = ({
|
|||||||
}
|
}
|
||||||
onClose()
|
onClose()
|
||||||
Toast.show(
|
Toast.show(
|
||||||
replyTo
|
thread.posts.length > 1
|
||||||
|
? _(msg`Your posts have been published`)
|
||||||
|
: replyTo
|
||||||
? _(msg`Your reply has been published`)
|
? _(msg`Your reply has been published`)
|
||||||
: _(msg`Your post has been published`),
|
: _(msg`Your post has been published`),
|
||||||
)
|
)
|
||||||
@@ -523,6 +525,7 @@ export const ComposePost = ({
|
|||||||
}
|
}
|
||||||
}, [composerState])
|
}, [composerState])
|
||||||
|
|
||||||
|
const isLastThreadedPost = thread.posts.length > 1 && nextPost === undefined
|
||||||
const {
|
const {
|
||||||
scrollHandler,
|
scrollHandler,
|
||||||
onScrollViewContentSizeChange,
|
onScrollViewContentSizeChange,
|
||||||
@@ -531,7 +534,7 @@ export const ComposePost = ({
|
|||||||
bottomBarAnimatedStyle,
|
bottomBarAnimatedStyle,
|
||||||
} = useScrollTracker({
|
} = useScrollTracker({
|
||||||
scrollViewRef,
|
scrollViewRef,
|
||||||
stickyBottom: true,
|
stickyBottom: isLastThreadedPost,
|
||||||
})
|
})
|
||||||
|
|
||||||
const keyboardVerticalOffset = useKeyboardVerticalOffset()
|
const keyboardVerticalOffset = useKeyboardVerticalOffset()
|
||||||
@@ -564,7 +567,7 @@ export const ComposePost = ({
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
const isFooterSticky = !isNative && thread.posts.length > 1
|
const isWebFooterSticky = !isNative && thread.posts.length > 1
|
||||||
return (
|
return (
|
||||||
<BottomSheetPortalProvider>
|
<BottomSheetPortalProvider>
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
@@ -615,6 +618,7 @@ export const ComposePost = ({
|
|||||||
dispatch={composerDispatch}
|
dispatch={composerDispatch}
|
||||||
textInput={post.id === activePost.id ? textInput : null}
|
textInput={post.id === activePost.id ? textInput : null}
|
||||||
isFirstPost={index === 0}
|
isFirstPost={index === 0}
|
||||||
|
isPartOfThread={thread.posts.length > 1}
|
||||||
isReply={index > 0 || !!replyTo}
|
isReply={index > 0 || !!replyTo}
|
||||||
isActive={post.id === activePost.id}
|
isActive={post.id === activePost.id}
|
||||||
canRemovePost={thread.posts.length > 1}
|
canRemovePost={thread.posts.length > 1}
|
||||||
@@ -624,11 +628,13 @@ export const ComposePost = ({
|
|||||||
onPublish={onComposerPostPublish}
|
onPublish={onComposerPostPublish}
|
||||||
onError={setError}
|
onError={setError}
|
||||||
/>
|
/>
|
||||||
{isFooterSticky && post.id === activePost.id && footer}
|
{isWebFooterSticky && post.id === activePost.id && (
|
||||||
|
<View style={styles.stickyFooterWeb}>{footer}</View>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</Animated.ScrollView>
|
</Animated.ScrollView>
|
||||||
{!isFooterSticky && footer}
|
{!isWebFooterSticky && footer}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Prompt.Basic
|
<Prompt.Basic
|
||||||
@@ -651,6 +657,7 @@ let ComposerPost = React.memo(function ComposerPost({
|
|||||||
isActive,
|
isActive,
|
||||||
isReply,
|
isReply,
|
||||||
isFirstPost,
|
isFirstPost,
|
||||||
|
isPartOfThread,
|
||||||
canRemovePost,
|
canRemovePost,
|
||||||
canRemoveQuote,
|
canRemoveQuote,
|
||||||
onClearVideo,
|
onClearVideo,
|
||||||
@@ -664,6 +671,7 @@ let ComposerPost = React.memo(function ComposerPost({
|
|||||||
isActive: boolean
|
isActive: boolean
|
||||||
isReply: boolean
|
isReply: boolean
|
||||||
isFirstPost: boolean
|
isFirstPost: boolean
|
||||||
|
isPartOfThread: boolean
|
||||||
canRemovePost: boolean
|
canRemovePost: boolean
|
||||||
canRemoveQuote: boolean
|
canRemoveQuote: boolean
|
||||||
onClearVideo: (postId: string) => void
|
onClearVideo: (postId: string) => void
|
||||||
@@ -743,6 +751,8 @@ let ComposerPost = React.memo(function ComposerPost({
|
|||||||
placeholder={selectTextInputPlaceholder}
|
placeholder={selectTextInputPlaceholder}
|
||||||
autoFocus
|
autoFocus
|
||||||
webForceMinHeight={forceMinHeight}
|
webForceMinHeight={forceMinHeight}
|
||||||
|
// To avoid overlap with the close button:
|
||||||
|
hasRightPadding={isPartOfThread}
|
||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
setRichText={rt => {
|
setRichText={rt => {
|
||||||
dispatchPost({type: 'update_richtext', richtext: rt})
|
dispatchPost({type: 'update_richtext', richtext: rt})
|
||||||
@@ -1395,6 +1405,11 @@ const styles = StyleSheet.create({
|
|||||||
paddingVertical: 6,
|
paddingVertical: 6,
|
||||||
marginLeft: 12,
|
marginLeft: 12,
|
||||||
},
|
},
|
||||||
|
stickyFooterWeb: {
|
||||||
|
// @ts-ignore web-only
|
||||||
|
position: 'sticky',
|
||||||
|
bottom: 0,
|
||||||
|
},
|
||||||
errorLine: {
|
errorLine: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ interface TextInputProps extends ComponentProps<typeof RNTextInput> {
|
|||||||
richtext: RichText
|
richtext: RichText
|
||||||
placeholder: string
|
placeholder: string
|
||||||
webForceMinHeight: boolean
|
webForceMinHeight: boolean
|
||||||
|
hasRightPadding: boolean
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
setRichText: (v: RichText) => void
|
setRichText: (v: RichText) => void
|
||||||
onPhotoPasted: (uri: string) => void
|
onPhotoPasted: (uri: string) => void
|
||||||
@@ -61,6 +62,7 @@ export const TextInput = forwardRef(function TextInputImpl(
|
|||||||
{
|
{
|
||||||
richtext,
|
richtext,
|
||||||
placeholder,
|
placeholder,
|
||||||
|
hasRightPadding,
|
||||||
setRichText,
|
setRichText,
|
||||||
onPhotoPasted,
|
onPhotoPasted,
|
||||||
onNewLink,
|
onNewLink,
|
||||||
@@ -232,7 +234,7 @@ export const TextInput = forwardRef(function TextInputImpl(
|
|||||||
}, [t, richtext, inputTextStyle])
|
}, [t, richtext, inputTextStyle])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.flex_1, a.pl_md]}>
|
<View style={[a.flex_1, a.pl_md, hasRightPadding && a.pr_4xl]}>
|
||||||
<PasteInput
|
<PasteInput
|
||||||
testID="composerTextInput"
|
testID="composerTextInput"
|
||||||
ref={textInput}
|
ref={textInput}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ interface TextInputProps {
|
|||||||
placeholder: string
|
placeholder: string
|
||||||
suggestedLinks: Set<string>
|
suggestedLinks: Set<string>
|
||||||
webForceMinHeight: boolean
|
webForceMinHeight: boolean
|
||||||
|
hasRightPadding: boolean
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
setRichText: (v: RichText | ((v: RichText) => RichText)) => void
|
setRichText: (v: RichText | ((v: RichText) => RichText)) => void
|
||||||
onPhotoPasted: (uri: string) => void
|
onPhotoPasted: (uri: string) => void
|
||||||
@@ -56,6 +57,7 @@ export const TextInput = React.forwardRef(function TextInputImpl(
|
|||||||
richtext,
|
richtext,
|
||||||
placeholder,
|
placeholder,
|
||||||
webForceMinHeight,
|
webForceMinHeight,
|
||||||
|
hasRightPadding,
|
||||||
isActive,
|
isActive,
|
||||||
setRichText,
|
setRichText,
|
||||||
onPhotoPasted,
|
onPhotoPasted,
|
||||||
@@ -307,7 +309,7 @@ export const TextInput = React.forwardRef(function TextInputImpl(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View style={styles.container}>
|
<View style={[styles.container, hasRightPadding && styles.rightPadding]}>
|
||||||
{/* @ts-ignore inputStyle is fine */}
|
{/* @ts-ignore inputStyle is fine */}
|
||||||
<EditorContent editor={editor} style={inputStyle} />
|
<EditorContent editor={editor} style={inputStyle} />
|
||||||
</View>
|
</View>
|
||||||
@@ -373,6 +375,9 @@ const styles = StyleSheet.create({
|
|||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
},
|
},
|
||||||
|
rightPadding: {
|
||||||
|
paddingRight: 32,
|
||||||
|
},
|
||||||
dropContainer: {
|
dropContainer: {
|
||||||
backgroundColor: '#0007',
|
backgroundColor: '#0007',
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
|
|||||||
Reference in New Issue
Block a user