Skip to content

Autocomplete text input component #4587

Open
@Sami-21

Description

@Sami-21

Is your feature request related to a problem? Please describe.
I have been using native paper for different projects and I came across a problem several times where I needed an autocomplete component, I tried 2 packages but I would love to have a component from the native paper so that my UI remains consistent

Describe the solution you'd like
I implemented an autocomplete component with the use of TextInput + Menu component from native paper

interface Props<T extends Record<string, any>> {
  theme?: AppTheme;
  value: {
    origValue: string | undefined;
  };
  label: string;
  data: T[];
  displayKey: keyof T;
  containerStyle?: StyleProp<ViewStyle>;
  onChange: (text: string) => void;
  leadingIcon?: IconSource;
  trailingIcon?: IconSource;
  textInputstyle?: StyleProp<TextStyle>;
  menuStyle?: StyleProp<ViewStyle>;
  textInputRight?: ReactNode;
  textInputLeft?: ReactNode;
}

const Autocomplete = <T extends Record<string, any>>({
  theme = lightTheme,
  value: propValue,
  label,
  data,
  displayKey,
  containerStyle = {},
  onChange: originOnChange,
  textInputstyle = {},
  leadingIcon = "",
  trailingIcon = "",
  menuStyle = {},
  textInputRight = null,
  textInputLeft = null,
}: Props<T>) => {
  const [value, setValue] = useState<string | undefined>(propValue.origValue);
  const [menuVisible, setMenuVisible] = useState<boolean>(false);

  return (
    <View
      style={
        containerStyle,
      }
    >
      <TextInput
        theme={theme}
        mode="outlined"
        onFocus={() => {
          if (value || value?.length === 0) {
            setMenuVisible(true);
          }
        }}
        outlineStyle={
          menuVisible
            ? {
                borderBottomRightRadius: 0,
                borderBottomLeftRadius: 0,
              }
            : {}
        }
        onBlur={() => setMenuVisible(false)}
        label={label}
        {...(textInputRight ? { right: textInputRight } : {})}
        {...(textInputLeft ? { left: textInputLeft } : {})}
        style={textInputstyle}
        onChangeText={(text) => {
          originOnChange(text);
          setMenuVisible(true);
          setValue(text);
        }}
        value={value}
      />
      {menuVisible && (
        <View
          style={{
            flex: 1,
            width: "100%",
            backgroundColor: "white",
            borderWidth: 1,
            borderColor: theme.colors.primary,
            borderBottomRightRadius: 4,
            borderBottomLeftRadius: 4,
            flexDirection: "column",
            position: "absolute",
            top: "100%",
            left: 0,
            zIndex: 10,
          }}
        >
          {data.length === 0 && (
            <Text style={{ padding: 10 }}>
              <Text style={{ textAlign: "center" }}>
                No result found
              </Text>
            </Text>
          )}
          {data.map((item, index) => (
            <Menu.Item
              key={index}
              style={ menuStyle}
              leadingIcon={leadingIcon}
              trailingIcon={trailingIcon}
              onPress={() => {
                const selectedValue = String(item[displayKey]);
                console.log(selectedValue);

                setValue(selectedValue);
                setMenuVisible(false);
                originOnChange(selectedValue);
              }}
              title={String(item[displayKey])}
            />
          ))}
        </View>
      )}
    </View>
  );
};

Describe alternatives you've considered
I have tried two alternatives:
react-native-autocomplete-dropdown and react-native-autocomplete-input
I dropped those packages out of fear since they were backed only by one contributor.

Additional context
N/A

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions