import React, { useRef, useState, useEffect, useMemo } from 'react'; import Select from '@/_ui/Select'; import { components } from 'react-select'; import defaultStyles from '@/_ui/Select/styles'; import SolidIcon from '@/_ui/Icon/SolidIcons'; import { Checkbox } from '@/_ui/CheckBox/CheckBox'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import { isArray, isString } from 'lodash'; const { MenuList } = components; const SCALING_FACTOR = 0.6; const FONT_SIZE = 12; const PADDING = 12; const MARGIN = 10; // including left and right side export const CustomSelect = ({ options, value, onChange, fuzzySearch = false, placeholder, disabled, className, darkMode, defaultOptionsList, textColor = '', isMulti, containerWidth, optionsLoadingState = false, horizontalAlignment = 'left', isEditable, isMaxRowHeightAuto, }) => { const containerRef = useRef(null); const inputRef = useRef(null); // Ref for the input search box const [isFocused, setIsFocused] = useState(false); useEffect(() => { const handleDocumentClick = (event) => { if (isMulti && !containerRef.current?.contains(event.target)) { setIsFocused(false); } }; document.addEventListener('mousedown', handleDocumentClick); return () => { document.removeEventListener('mousedown', handleDocumentClick); }; }, []); useEffect(() => { // Focus the input search box when the menu list is open and the component is focused if (isFocused && inputRef.current) { inputRef.current.focus(); } }, [isFocused]); const customStyles = { ...defaultStyles(darkMode, '100%'), ...(isMulti && { multiValue: (provided) => ({ ...provided, display: 'inline-block', // Display selected options inline marginRight: '4px', // Add some space between options }), }), valueContainer: (provided) => ({ ...provided, ...(isMulti && { marginBottom: '0', display: 'flex', flexWrap: 'no-wrap', overflow: 'hidden', flexDirection: 'row', }), justifyContent: horizontalAlignment, }), menuList: (base) => ({ ...base, backgroundColor: 'var(--surfaces-surface-01) ', color: 'var(--text-primary)', cursor: 'pointer', overflow: 'auto', }), multiValueLabel: (provided) => ({ ...provided, padding: '2px 6px', background: 'var(--surfaces-surface-03)', margin: '0 5px', borderRadius: '6px', color: textColor || 'var(--text-primary)', fontSize: '12px', }), singleValue: (provided) => ({ ...provided, padding: '2px 6px', background: 'var(--surfaces-surface-03)', margin: '0 5px', borderRadius: '6px', color: textColor || 'var(--text-primary)', fontSize: '12px', }), }; const customComponents = { MenuList: (props) => , Option: CustomMultiSelectOption, DropdownIndicator: isEditable ? DropdownIndicator : null, ...(isMulti && { MultiValueRemove, MultiValueContainer: CustomMultiValueContainer, }), }; const defaultValue = useMemo(() => { if (defaultOptionsList.length >= 1) { return !isMulti ? defaultOptionsList[defaultOptionsList.length - 1] : defaultOptionsList; } }, [isMulti, defaultOptionsList]); const _value = useMemo(() => { // Return null to show default value if (!value) { return null; } if (isMulti && value?.length) { if (isArray(value)) { return options?.filter((option) => value?.find((val) => { if (val.hasOwnProperty('value')) { return option.value === val.value; } else return option.value === val; }) ); } else { return []; // Return empty array to not show default value in case of wrong value to be set } } else { // Condition for single select return options?.find((option) => option.value === value) || []; } }, [options, value, isMulti]); const calculateIfPopoverRequired = (value, containerWidth) => { let totalWidth = 0; // // Calculate total width of all span elements for (const option of value) { const valueWidth = option.label.length * FONT_SIZE * SCALING_FACTOR + PADDING + MARGIN; // Check if max row height is auto and then if any of the options width exceeds container width, return true if (isMaxRowHeightAuto) { if (valueWidth > containerWidth) { return true; } } else { totalWidth += valueWidth + 4; // Adding 4px to be safe } } return totalWidth > containerWidth; // Return based on total width comparison }; return ( ) } trigger={ isMulti && !isFocused && calculateIfPopoverRequired(_value ? _value : defaultValue, containerWidth - 40) && ['hover', 'focus'] } //container width -24 -16 gives that select container size rootClose={true} >
onInputChange(e.currentTarget.value, { action: 'input-change', }) } onMouseDown={(e) => { e.stopPropagation(); e.target.focus(); }} onTouchEnd={(e) => { e.stopPropagation(); e.target.focus(); }} onFocus={onMenuInputFocus} placeholder="Search..." className="table-select-column-type-search-box" ref={inputRef} // Assign the ref to the input search box />
{optionsLoadingState ? (
) : ( children )}
); }; const CustomMultiSelectOption = ({ innerRef, innerProps, children, isSelected, ...props }) => { return (
{props.isMulti ? ( e.stopPropagation()} key="" value={children} /> ) : (
e.stopPropagation()} key="" value={children} />
)} {children}
); }; const MultiValueRemove = (props) => { const { innerProps } = props; return
; }; const CustomMultiValueContainer = (props) => { return (
{props.children}
); }; const getOverlay = (value, containerWidth, darkMode) => { const getLabel = (option) => { if (option?.hasOwnProperty('label')) { return option.label; } else if (isString(option)) { return option; } else return ''; }; return Array.isArray(value) ? (
{value?.map((option) => { return ( {getLabel(option)} ); })}
) : (
); }; const DropdownIndicator = (props) => { return (
{/* Your custom SVG */} {props.selectProps.menuIsOpen ? ( ) : ( )}
); };