forked from Ivasoft/mattermost-mobile
MM-33993 Allow apps form and interactive dialogs to clear select fields (#5398)
* allow apps form and int dialogs to clear select fields * don't show x if the field is disabled * change down chevron to right chevron * increase padding around close x to increase touch area * positioning * remove chevron and divider * use hitSlop instead of padding. fix position of x * lint * types * update type * lint * make onClear optional * optional chaining * set multiselect value to empty array on clear * include null in type * useCallback improvement * fix clearing multi-selected items state issue * fix clearing multi-selected items state issue * lint Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
@@ -32,12 +32,13 @@ type Props = {
|
||||
placeholder?: string;
|
||||
dataSource?: string;
|
||||
options?: DialogOption[];
|
||||
selected?: DialogOption | DialogOption[];
|
||||
selected?: DialogOption | DialogOption[] | null;
|
||||
optional?: boolean;
|
||||
showRequiredAsterisk?: boolean;
|
||||
teammateNameDisplay?: string;
|
||||
theme: Theme;
|
||||
onSelected?: ((item: DialogOption) => void) | ((item: DialogOption[]) => void);
|
||||
onClear?: () => void;
|
||||
helpText?: string;
|
||||
errorText?: string;
|
||||
roundedBorders?: boolean;
|
||||
@@ -47,7 +48,7 @@ type Props = {
|
||||
|
||||
type State = {
|
||||
selectedText: string;
|
||||
selected?: DialogOption | DialogOption[];
|
||||
selected?: DialogOption | DialogOption[] | null;
|
||||
}
|
||||
|
||||
export default class AutocompleteSelector extends PureComponent<Props, State> {
|
||||
@@ -70,7 +71,15 @@ export default class AutocompleteSelector extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: Props, state: State) {
|
||||
if (!props.selected || props.selected === state.selected) {
|
||||
if (props.selected === state.selected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!props.selected) {
|
||||
if (state.selected) {
|
||||
return {selected: props.selected};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -99,6 +108,11 @@ export default class AutocompleteSelector extends PureComponent<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
handleClear = () => {
|
||||
this.setState({selectedText: ''});
|
||||
this.props.onClear?.();
|
||||
};
|
||||
|
||||
handleSelect = (selected: Selection) => {
|
||||
if (!selected) {
|
||||
return;
|
||||
@@ -230,14 +244,14 @@ export default class AutocompleteSelector extends PureComponent<Props, State> {
|
||||
showRequiredAsterisk,
|
||||
roundedBorders,
|
||||
disabled,
|
||||
selected,
|
||||
onClear,
|
||||
} = this.props;
|
||||
const {selectedText} = this.state;
|
||||
const style = getStyleSheet(theme);
|
||||
const textStyles = getMarkdownTextStyles(theme);
|
||||
const blockStyles = getMarkdownBlockStyles(theme);
|
||||
|
||||
const chevron = Platform.select({ios: 'chevron-right', default: 'chevron-down'});
|
||||
|
||||
let text = placeholder || intl.formatMessage({id: 'mobile.action_menu.select', defaultMessage: 'Select an option'});
|
||||
let selectedStyle = style.dropdownPlaceholder;
|
||||
|
||||
@@ -326,11 +340,21 @@ export default class AutocompleteSelector extends PureComponent<Props, State> {
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
<CompassIcon
|
||||
name={chevron}
|
||||
color={changeOpacity(theme.centerChannelColor, 0.32)}
|
||||
style={style.icon}
|
||||
/>
|
||||
{!disabled && onClear && selected && (
|
||||
<TouchableWithFeedback
|
||||
type={'opacity'}
|
||||
onPress={this.handleClear}
|
||||
disabled={disabled}
|
||||
style={style.clearx}
|
||||
hitSlop={clearXHitSlop}
|
||||
>
|
||||
<CompassIcon
|
||||
name='close-circle'
|
||||
color={changeOpacity(theme.centerChannelColor, 0.5)}
|
||||
size={20}
|
||||
/>
|
||||
</TouchableWithFeedback>
|
||||
)}
|
||||
</View>
|
||||
</TouchableWithFeedback>
|
||||
{helpTextContent}
|
||||
@@ -366,18 +390,21 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
dropdownPlaceholder: {
|
||||
top: 3,
|
||||
marginLeft: 5,
|
||||
paddingRight: 55,
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
},
|
||||
dropdownSelected: {
|
||||
top: 3,
|
||||
marginLeft: 5,
|
||||
paddingRight: 55,
|
||||
color: theme.centerChannelColor,
|
||||
},
|
||||
icon: {
|
||||
clearx: {
|
||||
position: 'absolute',
|
||||
top: 6,
|
||||
right: 12,
|
||||
fontSize: 28,
|
||||
top: 1,
|
||||
right: 5,
|
||||
padding: 8,
|
||||
marginRight: 7,
|
||||
},
|
||||
labelContainer: {
|
||||
flexDirection: 'row',
|
||||
@@ -419,3 +446,10 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const clearXHitSlop = {
|
||||
left: 30,
|
||||
right: 20,
|
||||
top: 20,
|
||||
bottom: 20,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import React, {useCallback} from 'react';
|
||||
|
||||
import AutocompleteSelector from '@components/autocomplete_selector';
|
||||
import {PostActionOption} from '@mm-redux/types/integration_actions';
|
||||
@@ -28,13 +28,13 @@ const ActionMenu = ({dataSource, defaultOption, disabled, id, name, options, pos
|
||||
isSelected = selected;
|
||||
}
|
||||
|
||||
const handleSelect = (selectedItem?: PostActionOption) => {
|
||||
const handleSelect = useCallback((selectedItem?: PostActionOption) => {
|
||||
if (!selectedItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectAttachmentMenuAction(postId, id, selectedItem.text, selectedItem.value);
|
||||
};
|
||||
}, [postId, id]);
|
||||
|
||||
return (
|
||||
<AutocompleteSelector
|
||||
|
||||
@@ -150,7 +150,7 @@ export type AppForm = {
|
||||
depends_on?: string[];
|
||||
};
|
||||
|
||||
export type AppFormValue = string | AppSelectOption | boolean | null;
|
||||
export type AppFormValue = string | AppSelectOption | AppSelectOption[] | boolean | null;
|
||||
export type AppFormValues = {[name: string]: AppFormValue};
|
||||
|
||||
export type AppSelectOption = {
|
||||
|
||||
@@ -26,12 +26,12 @@ export type Props = {
|
||||
theme: Theme;
|
||||
|
||||
value: AppFormValue;
|
||||
onChange: (name: string, value: string | AppSelectOption | AppSelectOption[] | boolean) => void;
|
||||
onChange: (name: string, value: AppFormValue) => void;
|
||||
performLookup: (name: string, userInput: string) => Promise<AppSelectOption[]>;
|
||||
}
|
||||
|
||||
type State = {
|
||||
selected?: DialogOption | DialogOption[];
|
||||
selected?: DialogOption | DialogOption[] | null;
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
@@ -100,6 +100,15 @@ export default class AppsFormField extends React.PureComponent<Props, State> {
|
||||
this.props.onChange(field.name, selectedOption);
|
||||
};
|
||||
|
||||
handleClear = () => {
|
||||
const {field, onChange} = this.props;
|
||||
|
||||
const selected = null;
|
||||
|
||||
this.setState({selected});
|
||||
onChange(field.name, selected);
|
||||
};
|
||||
|
||||
handleMultioptionAutocompleteSelect = (selected: DialogOption[]) => {
|
||||
if (!selected) {
|
||||
return;
|
||||
@@ -237,6 +246,7 @@ export default class AppsFormField extends React.PureComponent<Props, State> {
|
||||
dataSource={dataSource}
|
||||
options={options}
|
||||
optional={!field.is_required}
|
||||
onClear={this.handleClear}
|
||||
onSelected={field.multiselect ? this.handleMultioptionAutocompleteSelect : this.handleAutocompleteSelect}
|
||||
getDynamicOptions={this.getDynamicOptions}
|
||||
helpText={field.description}
|
||||
|
||||
@@ -54,6 +54,13 @@ export default class DialogElement extends PureComponent {
|
||||
onChange(name, newValue);
|
||||
};
|
||||
|
||||
handleClear = () => {
|
||||
const {name, onChange} = this.props;
|
||||
|
||||
this.setState({selected: null});
|
||||
onChange(name, null);
|
||||
};
|
||||
|
||||
handleAutocompleteSelect = (selected) => {
|
||||
if (!selected) {
|
||||
return;
|
||||
@@ -134,6 +141,7 @@ export default class DialogElement extends PureComponent {
|
||||
options={options}
|
||||
optional={optional}
|
||||
onSelected={this.handleAutocompleteSelect}
|
||||
onClear={this.handleClear}
|
||||
helpText={helpText}
|
||||
errorText={errorText}
|
||||
placeholder={placeholder}
|
||||
|
||||
Reference in New Issue
Block a user