Add several UX fixes to set command screen on playbooks (#9136)
* Add several UX fixes to set command screen on playbooks * Update app/products/playbooks/screens/edit_command/edit_command.test.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update app/components/autocomplete/autocomplete.test.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix keyboard overlap --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
a4e495a2a6
commit
62aba308f1
6 changed files with 62 additions and 20 deletions
|
|
@ -120,4 +120,36 @@ describe('Autocomplete', () => {
|
|||
expect(getByTestId('slash-suggestion-mock')).toBeTruthy();
|
||||
expect(getByTestId('app-slash-suggestion-mock')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render with the correct horizontal padding', () => {
|
||||
const props = getBaseProps();
|
||||
const {getByTestId, rerender} = render(<Autocomplete {...props}/>);
|
||||
|
||||
// Default horizontal padding is 8
|
||||
expect(getByTestId('autocomplete')).toHaveStyle({left: 8, right: 8});
|
||||
|
||||
// Set horizontal padding to 20
|
||||
props.horizontalPadding = 20;
|
||||
rerender(<Autocomplete {...props}/>);
|
||||
|
||||
expect(getByTestId('autocomplete')).toHaveStyle({left: 20, right: 20});
|
||||
});
|
||||
|
||||
it('should set the correct max height by default', () => {
|
||||
const props = getBaseProps();
|
||||
props.availableSpace = {value: 1000} as SharedValue<number>;
|
||||
const {getByTestId} = render(<Autocomplete {...props}/>);
|
||||
|
||||
// Default max height is 230
|
||||
expect(getByTestId('autocomplete')).toHaveStyle({maxHeight: 230});
|
||||
});
|
||||
|
||||
it('should set the correct max height when useAllAvailableSpace is true', () => {
|
||||
const props = getBaseProps();
|
||||
props.availableSpace = {value: 1000} as SharedValue<number>;
|
||||
props.useAllAvailableSpace = true;
|
||||
const {getByTestId} = render(<Autocomplete {...props}/>);
|
||||
|
||||
expect(getByTestId('autocomplete')).toHaveStyle({maxHeight: 1000});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ import AppSlashSuggestion from './slash_suggestion/app_slash_suggestion/';
|
|||
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
base: {
|
||||
left: 8,
|
||||
right: 8,
|
||||
position: 'absolute',
|
||||
},
|
||||
borders: {
|
||||
|
|
@ -65,6 +63,8 @@ type Props = {
|
|||
teamId?: string;
|
||||
containerStyle?: StyleProp<ViewStyle>;
|
||||
autocompleteProviders?: AutocompleteProviders;
|
||||
useAllAvailableSpace?: boolean;
|
||||
horizontalPadding?: number;
|
||||
}
|
||||
|
||||
type AutocompleteProviders = {
|
||||
|
|
@ -99,6 +99,8 @@ const Autocomplete = ({
|
|||
containerStyle,
|
||||
teamId,
|
||||
autocompleteProviders = defaultAutocompleteProviders,
|
||||
useAllAvailableSpace = false,
|
||||
horizontalPadding = 8,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const isTablet = useIsTablet();
|
||||
|
|
@ -121,8 +123,8 @@ const Autocomplete = ({
|
|||
const maxHeightAdjust = (isTablet && isLandscape) ? MAX_LIST_TABLET_DIFF : 0;
|
||||
const defaultMaxHeight = MAX_LIST_HEIGHT - maxHeightAdjust;
|
||||
const maxHeight = useDerivedValue(() => {
|
||||
return Math.min(availableSpace.value, defaultMaxHeight);
|
||||
}, [defaultMaxHeight]);
|
||||
return useAllAvailableSpace ? availableSpace.value : Math.min(availableSpace.value, defaultMaxHeight);
|
||||
}, [defaultMaxHeight, useAllAvailableSpace, availableSpace]);
|
||||
|
||||
const containerAnimatedStyle = useAnimatedStyle(() => {
|
||||
return growDown ?
|
||||
|
|
@ -131,7 +133,7 @@ const Autocomplete = ({
|
|||
}, [growDown, position]);
|
||||
|
||||
const containerStyles = useMemo(() => {
|
||||
const s: StyleProp<ViewStyle> = [style.base, containerAnimatedStyle];
|
||||
const s: StyleProp<ViewStyle> = [style.base, {left: horizontalPadding, right: horizontalPadding}, containerAnimatedStyle];
|
||||
if (hasElements) {
|
||||
s.push(style.borders);
|
||||
}
|
||||
|
|
@ -142,7 +144,7 @@ const Autocomplete = ({
|
|||
s.push(containerStyle);
|
||||
}
|
||||
return s;
|
||||
}, [hasElements, style, containerStyle, containerAnimatedStyle]);
|
||||
}, [style.base, style.borders, style.shadow, horizontalPadding, containerAnimatedStyle, hasElements, containerStyle]);
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
|
|
|
|||
|
|
@ -58,13 +58,13 @@ describe('EditCommand', () => {
|
|||
expect(editCommandForm.props.channelId).toBe(props.channelId);
|
||||
});
|
||||
|
||||
it('renders correctly without saved command', () => {
|
||||
it('renders correctly without saved command, adding a slash automatically', () => {
|
||||
const props = getBaseProps();
|
||||
props.savedCommand = undefined;
|
||||
const {getByTestId} = renderWithEverything(<EditCommand {...props}/>, {database});
|
||||
|
||||
const editCommandForm = getByTestId('edit-command-form');
|
||||
expect(editCommandForm.props.command).toBe('');
|
||||
expect(editCommandForm.props.command).toBe('/');
|
||||
});
|
||||
|
||||
it('sets up navigation buttons correctly', () => {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const CreateOrEditChannel = ({
|
|||
const theme = useTheme();
|
||||
|
||||
const [canSave, setCanSave] = useState(false);
|
||||
const [command, setCommand] = useState<string>(savedCommand || '');
|
||||
const [command, setCommand] = useState<string>(savedCommand || '/');
|
||||
|
||||
const rightButton = useMemo(() => {
|
||||
const base = buildNavigationButton(
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ describe('EditCommandForm', () => {
|
|||
expect(floatingTextInput).toHaveProp('showErrorIcon', false);
|
||||
expect(floatingTextInput).toHaveProp('spellCheck', false);
|
||||
expect(floatingTextInput).toHaveProp('disableFullscreenUI', true);
|
||||
expect(floatingTextInput).toHaveProp('autoFocus', true);
|
||||
|
||||
const autocomplete = getByTestId('autocomplete');
|
||||
expect(autocomplete).toBeTruthy();
|
||||
|
|
@ -78,6 +79,8 @@ describe('EditCommandForm', () => {
|
|||
emoji: false,
|
||||
slash: true,
|
||||
});
|
||||
expect(autocomplete).toHaveProp('useAllAvailableSpace', true);
|
||||
expect(autocomplete).toHaveProp('horizontalPadding', 20);
|
||||
});
|
||||
|
||||
it('calls onCommandChange when text input changes', () => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useState, useCallback} from 'react';
|
||||
import React, {useState, useCallback, useRef} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {
|
||||
type LayoutChangeEvent,
|
||||
View,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import {SafeAreaView, type Edges} from 'react-native-safe-area-context';
|
||||
|
|
@ -15,13 +14,13 @@ import Autocomplete from '@components/autocomplete';
|
|||
import FloatingTextInput from '@components/floating_text_input_label';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useAutocompleteDefaultAnimatedValues} from '@hooks/autocomplete';
|
||||
import {useKeyboardOverlap} from '@hooks/device';
|
||||
import {
|
||||
getKeyboardAppearanceFromTheme,
|
||||
} from '@utils/theme';
|
||||
|
||||
const BOTTOM_AUTOCOMPLETE_SEPARATION = Platform.select({ios: 10, default: 10});
|
||||
const BOTTOM_AUTOCOMPLETE_SEPARATION = 4;
|
||||
const LIST_PADDING = 32;
|
||||
const AUTOCOMPLETE_ADJUST = 5;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
|
@ -60,6 +59,9 @@ export default function EditCommandForm({
|
|||
|
||||
const [commandFieldHeight, setCommandFieldHeight] = useState(0);
|
||||
|
||||
const mainView = useRef<View>(null);
|
||||
const keyboardOverlap = useKeyboardOverlap(mainView, wrapperHeight);
|
||||
|
||||
const labelCommand = formatMessage({id: 'playbooks.edit_command.label', defaultMessage: 'Command'});
|
||||
const placeholderCommand = formatMessage({id: 'playbooks.edit_command.placeholder', defaultMessage: 'Type a command here'});
|
||||
|
||||
|
|
@ -70,14 +72,13 @@ export default function EditCommandForm({
|
|||
setWrapperHeight(e.nativeEvent.layout.height);
|
||||
}, []);
|
||||
|
||||
const spaceOnTop = LIST_PADDING - AUTOCOMPLETE_ADJUST;
|
||||
const spaceOnBottom = (wrapperHeight) - (LIST_PADDING + commandFieldHeight + BOTTOM_AUTOCOMPLETE_SEPARATION);
|
||||
const workingSpace = wrapperHeight - keyboardOverlap;
|
||||
const spaceOnBottom = (workingSpace) - (LIST_PADDING + commandFieldHeight + (BOTTOM_AUTOCOMPLETE_SEPARATION * 2));
|
||||
|
||||
const bottomPosition = (LIST_PADDING + commandFieldHeight);
|
||||
const topPosition = (wrapperHeight + AUTOCOMPLETE_ADJUST) - LIST_PADDING;
|
||||
const autocompletePosition = spaceOnBottom > spaceOnTop ? bottomPosition : topPosition;
|
||||
const autocompleteAvailableSpace = spaceOnBottom > spaceOnTop ? spaceOnBottom : spaceOnTop;
|
||||
const growDown = spaceOnBottom > spaceOnTop;
|
||||
const bottomPosition = (LIST_PADDING + commandFieldHeight + BOTTOM_AUTOCOMPLETE_SEPARATION);
|
||||
const autocompletePosition = bottomPosition;
|
||||
const autocompleteAvailableSpace = spaceOnBottom;
|
||||
const growDown = true;
|
||||
|
||||
const [animatedAutocompletePosition, animatedAutocompleteAvailableSpace] = useAutocompleteDefaultAnimatedValues(autocompletePosition, autocompleteAvailableSpace);
|
||||
|
||||
|
|
@ -87,6 +88,7 @@ export default function EditCommandForm({
|
|||
style={styles.container}
|
||||
testID='playbooks.edit_command.form'
|
||||
onLayout={onLayoutWrapper}
|
||||
ref={mainView}
|
||||
>
|
||||
<View style={styles.mainView}>
|
||||
<FloatingTextInput
|
||||
|
|
@ -103,6 +105,7 @@ export default function EditCommandForm({
|
|||
value={command}
|
||||
theme={theme}
|
||||
onLayout={onLayoutCommand}
|
||||
autoFocus={true}
|
||||
/>
|
||||
</View>
|
||||
<Autocomplete
|
||||
|
|
@ -116,6 +119,8 @@ export default function EditCommandForm({
|
|||
growDown={growDown}
|
||||
channelId={channelId}
|
||||
autocompleteProviders={autocompleteProviders}
|
||||
useAllAvailableSpace={true}
|
||||
horizontalPadding={20}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue