react-component / select

React Select
https://select.react-component.now.sh/
MIT License
892 stars 452 forks source link

Restore Standard Select Controls #974

Open ZachAlanMueller opened 10 months ago

ZachAlanMueller commented 10 months ago

Vanilla HTML Selects standard controls allow for arrow keys up/down to select the previous/next option, and then when a user tabs, it keeps that selected option. This commit implements that functionality into rc-select.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select#technical_summary

This functionality has been asked for by the community for Ant Design over the years, see issue here: close https://github.com/ant-design/ant-design/issues/26876

Please forgive me if I've done this PR incorrectly, I'm unfamiliar with the procedure, and if I did anything wrong, please let me know so that I can do better next time.

vercel[bot] commented 10 months ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
select ❌ Failed (Inspect) Aug 14, 2023 4:00pm
yoyo837 commented 10 months ago

Please add some test case for it.

ZachAlanMueller commented 10 months ago

Thank you for your feedback. I understand that you would like me to add some test cases for the new feature. I apologize for not knowing how to do this, as I am still new to unit testing.

I would like to learn how to add test cases, so that I can be more helpful in the future. Would you be able to provide me with some resources or training on unit testing?

yoyo837 commented 10 months ago

FYI: https://github.com/react-component/select/blob/master/tests/OptionList.test.tsx https://jestjs.io/

sixwinds commented 10 months ago

I have a temp fall back implementation, the idea is that find the active option dom node when blur:

// libs
import { useRef } from 'react';
import { Select } from 'antd';
// utils
import isFunction from '@/utils/isFunction';

// this func is based on antd version 4, you can customized it on your antd version
const getActiveOpitonContentElement = (rootElement) => {
  if (rootElement) {
    const activeOptionElement = rootElement.getElementsByClassName(
      'ant-select-item-option-active',
    )?.[0];
    if (activeOptionElement) {
      const optionContentElement = activeOptionElement.getElementsByClassName(
        'ant-select-item-option-content',
      )?.[0];
      return optionContentElement;
    }
  }
  return void 0;
};

const MySelect = (props) => {
  const {
    options,
    optionFilterProp,
    dropdownRender,
    onBlur,
    onChange,
    ...restProps
  } = props;

  const dropdownWrapperElementRef = useRef();

  return (
    <Select
      {...restProps}
      onChange={onChange}
      optionFilterProp={optionFilterProp}
      options={options}
      dropdownRender={(originNode) => {
        if (isFunction(dropdownRender)) {
          return (
            <div ref={dropdownWrapperElementRef}>
              {dropdownRender(originNode)}
            </div>
          )
        }
        return (
          <div ref={dropdownWrapperElementRef}>
            {originNode}
          </div>
        );
      }}
      onBlur={(...args) => {
        // ---- [implementation of tabbing to select active option] start -----
        const activeOptionContentElement = getActiveOpitonContentElement(
          dropdownWrapperElementRef.current,
        );
        if (
          activeOptionContentElement &&
          Array.isArray(options) &&
          options.length > 0
        ) {
          const activeOption = options.find((el) => {
            return (
              el[optionFilterProp ?? 'value'] ===
              activeOptionContentElement.innerText
            );
          });
          if (activeOption && isFunction(onChange)) {
            onChange(activeOption.value);
          }
        }
        // ---- [implementation of tabbing to select active option] end -----

        if (isFunction(onBlur)) {
          onBlur(...args);
        }
      }}
    />
  );
};

It is based on antd version 4, but I think developer can customized the implementation.