react-tailwindcss-select icon indicating copy to clipboard operation
react-tailwindcss-select copied to clipboard

some idea of label styles (highlighting searchinput value) with preview sceenshot

Open cha2hyun opened this issue 1 year ago β€’ 7 comments

Hi there πŸ‘‹ Thanks for woderful components. I have some idea for label styles. (highlight searchinput value) If you like it, i will make a PR

Preview

before

image

highlight

image

Some Code

Item.tsx

import React, { useCallback, useMemo } from 'react';

import DisabledItem from './DisabledItem';
import { useSelectContext } from './SelectProvider';
import { Option } from './type';
import { COLORS, DEFAULT_THEME, THEME_DATA } from '../constants';

interface ItemProps {
  item: Option;
  primaryColor: string;
  searchInput?: string;
}

const Item: React.FC<ItemProps> = ({ item, primaryColor, searchInput }) => {
  const { classNames, value, handleValueChange, formatOptionLabel } =
    useSelectContext();

  const isSelected = useMemo(() => {
    return (
      value !== null && !Array.isArray(value) && value.value === item.value
    );
  }, [item.value, value]);

  const textHoverColor = useMemo(() => {
    if (COLORS.includes(primaryColor)) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      return THEME_DATA.textHover[primaryColor];
    }
    return THEME_DATA.textHover[DEFAULT_THEME];
  }, [primaryColor]);

  const bgColor = useMemo(() => {
    if (COLORS.includes(primaryColor)) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      return THEME_DATA.bg[primaryColor];
    }
    return THEME_DATA.bg[DEFAULT_THEME];
  }, [primaryColor]);

  const bgHoverColor = useMemo(() => {
    if (COLORS.includes(primaryColor)) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      return THEME_DATA.bgHover[primaryColor];
    }
    return THEME_DATA.bgHover[DEFAULT_THEME];
  }, [primaryColor]);

  const getItemClass = useCallback(() => {
    const baseClass =
      'block transition duration-200 px-2 py-2 pl-5 cursor-pointer select-none truncate rounded';
    const selectedClass = isSelected
      ? `text-white ${bgColor}`
      : `text-gray-500 ${bgHoverColor} ${textHoverColor}`;

    return classNames && classNames.listItem
      ? classNames.listItem({ isSelected })
      : `${baseClass} ${selectedClass}`;
  }, [bgColor, bgHoverColor, classNames, isSelected, textHoverColor]);

// HEREπŸ‘‡πŸ‘‡πŸ‘‡
  const getItemLabelWithColor = () => {
    if (searchInput) {
      const upperSearchInput = searchInput?.toUpperCase();
      const start = item.label.indexOf(upperSearchInput);
      const end = start + searchInput.length;
      const labelArray = item.label.split('');
      return labelArray.map((label, idx) => {
        if (idx >= start && idx < end) {
            <span className={`font-bold text-${primaryColor}-500`}>
              {label}
            </span>
        } else {
          return <span>{label}</span>;
        }
      });
    } else {
      return item.label;
    }
  };
// 

  return (
    <>
      {formatOptionLabel ? (
        <div onClick={() => handleValueChange(item)}>
          {formatOptionLabel({ ...item, isSelected })}
        </div>
      ) : (
        <>
          {item.disabled ? (
            <DisabledItem>{item.label}</DisabledItem>
          ) : (
            <li
              aria-selected={isSelected}
              role='option'
              onClick={() => handleValueChange(item)}
              className={getItemClass()}
            >
              {/* {item.label} */}πŸ‘‡πŸ‘‡πŸ‘‡
              {getItemLabelWithColor()}
            </li>
          )}
        </>
      )}
    </>
  );
};

export default Item;

cha2hyun avatar Feb 25 '23 06:02 cha2hyun