react-native-ui-kitten icon indicating copy to clipboard operation
react-native-ui-kitten copied to clipboard

Autocomplete width resize when active/focus

Open rigorcadiz opened this issue 2 years ago • 17 comments

🐛 Bug Report

After updating from Expo 46 to Expo 48. The Autocomplete component no longer behaves at it is before. I checked the ui-kitten dependencies, and still has the same version, so probably due to update of react-native? from 0.69.9 to 0.71.71

Screenshot_2023-05-06-00-32-51-57_90e51a8aee41f7443aa19cc8cba36488

To Reproduce

Steps to reproduce the behavior:

Expected behavior

The focus box should have the same width as before. The component also blinks when you tap on it, it should not blink same as the other components.

Link to runnable example or repository (highly encouraged)

UI Kitten and Eva version

Package Version
@eva-design/eva 2.2.0
@ui-kitten/components 5.3.1

Environment information


rigorcadiz avatar May 05 '23 16:05 rigorcadiz

@rigorcadiz

Hello there!

Please provide code example for more clear understanding and reproducing your problem.

I also see that you use autocomplete in some kind of drawer, right?

Sincerely, UI Kitten team

bataevvlad avatar May 08 '23 09:05 bataevvlad

@bataevvlad

Here is the sample code. I created a basic app to debug this using the following command:

npx create-expo-app MyApp

Here is the App.json

import { StatusBar } from 'expo-status-bar';
import { StyleSheet, View } from 'react-native';
import * as eva from '@eva-design/eva';
import { ApplicationProvider, Layout, Text, Autocomplete, AutocompleteItem } from '@ui-kitten/components';

export default function App() {
  return (
    <ApplicationProvider {...eva} theme={eva.light}>
      <View style={styles.container}>
        <Text>Open up App.js to start working on your app!</Text>
        <StatusBar style="auto" />
        <View style={{
          width: 300, height: 300, borderWidth: 1, padding: 10
        }}>
          <Autocomplete
            placeholder='Place your Text'
          >
            <AutocompleteItem title='Option 1'/>
            <AutocompleteItem title='Option 2'/>
            <AutocompleteItem title='Option 3'/>
          </Autocomplete>
        </View>
      </View>
    </ApplicationProvider>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

This is my package.json:

{
  "name": "myapp",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@eva-design/eva": "^2.2.0",
    "@ui-kitten/components": "^5.3.1",
    "expo": "~48.0.15",
    "expo-status-bar": "~1.4.4",
    "react": "^18.0.0",
    "react-native": "0.71.7",
    "react-native-svg": "^13.9.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

And I've got the same behavior with the screenshot above.

rigorcadiz avatar May 08 '23 10:05 rigorcadiz

It used to be working normally before the update.

rigorcadiz avatar May 08 '23 10:05 rigorcadiz

We have the same problem. In our case, the problem seems to have something to do with the width property. If I set a fixed width to the autocomplete itself, it does all work. Percentage Values don't....

TPK-MAXEDV avatar May 08 '23 12:05 TPK-MAXEDV

We have the same problem. In our case, the problem seems to have something to do with the width property. If I set a fixed width to the autocomplete itself, it does all work. Percentage Values don't....

Yeah it works with fix width but there is also this other odd behavior that the component blinks/flash when you focus/activate it.. Does it happen on your end too or no?

rigorcadiz avatar May 08 '23 12:05 rigorcadiz

ok thanks @rigorcadiz we will check it out and come back soon!

bataevvlad avatar May 08 '23 14:05 bataevvlad

Do we have an update here?

rigorcadiz avatar May 10 '23 01:05 rigorcadiz

@rigorcadiz I can advise you not to switch to a version above 0.71 react-native, the problem is associated with an update modal component of react-native, we are currently thinking about a solution, the fastest way would be to roll back to the old version 0.69 where you worked, I can not yet say how long it will take a fix

bataevvlad avatar May 12 '23 11:05 bataevvlad

@rigorcadiz I can advise you not to switch to a version above 0.71 react-native, the problem is associated with an update modal component of react-native, we are currently thinking about a solution, the fastest way would be to roll back to the old version 0.69 where you worked, I can not yet say how long it will take a fix

Too bad Apple no longer receive the SDK version on that react-native version that is why I was forced to update.

rigorcadiz avatar May 12 '23 11:05 rigorcadiz

Any updates?

ricardodolnl avatar Jun 30 '23 19:06 ricardodolnl

Can someone give me a status update on this bug? Any time indication for the fix? If it takes to long to fix I'll need to find another solution.

ricardodolnl avatar Jul 07 '23 08:07 ricardodolnl

@bataevvlad Has this been resolved?

I'm using:

"@eva-design/eva": "^2.2.0",
"@ui-kitten/components": "^5.3.1",

and the issue still exists.

Memz98 avatar Sep 28 '23 10:09 Memz98

Also ran into this issue and just general inconsistencies when styling the list of autocomplete items. I took a look at the UI-Kitten code and it looks like the issue has to do with the deprecation of UIManager and its methods that measure the position of elements, which the autocomplete and a few other components use quite a bit.

While the UIManager still works, it doesn't look like it's returning values in relation to the window, which makes putting the popover in the correct position and making it the correct size break. While the menu would show up, I could never get it to expand to the full width of the input element, no matter how creative I got with the styling.

I ended up creating a custom autocomplete component for the one instance where I needed it, and figured I'd share it back here in case it helps.

import { useState, useRef } from 'react';
import { View, StylesSheet } from 'react-native';
import { Input, List, ListItem, useTheme } from '@ui-kitten/components';

const colors = ['red', 'blue', 'yellow', 'green'];
const filterColorsByName = (color, query) => color.toLowerCase().includes(query.toLowerCase());

export const CustomAutocomplete = () => {
  const theme = useTheme();
  const ref = useRef();

  const [colorList, setColorList] = useState(colors);
  const [colorName, setColorName] = useState('');
  const [popoverVisible, setPopoverVisible] = useState(false);
  const [popoverPositions, setPopoverPositions] = useState(null);

  const onOptionSelect = useCallback(
    (color) => () => {
      setColorName(color);
      setPopoverVisible(false);
    },
    [colorList]
  );

  const onChangeText = (query) => {
    if (!popoverVisible && query.trim().length > 0) {
      setPopoverVisible(true);
    }

    setColorName(query);
    setColorList(colors.filter((color) => filterColorsByName(color, query)));
  };

  return (
    <Layout>
      <View
        ref={ref}
        onLayout={() => {
          ref?.current?.measureInWindow((x, y, width, height) => {
            setPopoverPositions({ x, y, width, height });
          });
        }}
      >
        <Input label="Color" value={colorName} onChangeText={onChangeText} />
      </View>
      <List
        style={[
          styles.autocompleteList,
          {
            display: popoverVisible ? 'flex' : 'none',
            borderColor: theme['color-basic-default-border'],
            top: popoverPositions?.y,
            left: popoverPositions?.x,
            width: popoverPositions?.width
          }
        ]}
        data={colorList}
        renderItem={({ item }) => <ListItem title={item} onPress={onOptionSelect(item)} />}
      />
    </Layout>
  );
};

const styles = StyleSheet.create({
  autocompleteList: {
    paddingVertical: 8,
    backgroundColor: 'white',
    borderWidth: 1,
    borderRadius: 4,
    position: 'absolute',
    zIndex: 1000
  }
});

The View wrapping the input with the ref and onLayout methods are the key. I couldn't get it to work with just the Input component and no wrapper. I believe this is because the measureInWindow method is only available for native components.

It's not quite as fancy as the UI-Kitten one without the anchor, but it allowed me to move forward with similar UX. I also ended up adding a debounce for the onChange handler of the Input element to automatically close the popover after 5 seconds of inactivity.

Hope this helps someone!

johnstonbl01 avatar Oct 07 '23 15:10 johnstonbl01

Thanks for sharing @johnstonbl01!

glisom avatar Nov 20 '23 19:11 glisom

Seeing as this is still open... A simple fix for me was:

  1. Wrap the Autocomplete component in a <View>
  2. Give the View a ref
  3. Add style={{ width: ref.current?.offsetWidth }} || 100 to the Autocomplete component. Number 100 here is an arbitrary fallback and can be changed based on your needs

RahulR100 avatar Jan 05 '24 17:01 RahulR100

There is another solution that worked for me using the "onLayout" prop o the View component and keeping the width in a state:

const Component = () => {
    const [ width, setWidth] = useState(400)
    const handleWidth = (event) => {
        const { width } = event.nativeEvent.layout
        setWidth(width)
    }
    return (
          <Layout>
                  <View onLayout={handleWidth}>
                      <Autocomplete
                           style={{ width }}
                         .....>
                         ....
                    </Autocomplete>
          </Layout/>
    )
}

Screenshot from 2024-01-26 00-10-47

rcarvalhocdmx avatar Jan 26 '24 06:01 rcarvalhocdmx

Why is this abandoned? To me it seems significant enough to be fixed already...

sizuf avatar Jun 16 '24 10:06 sizuf