import React, { FC, ReactNode, useEffect, useRef, useState } from 'react' import { useMultiSelect } from '~/hooks/useSelect' import { Value, Option, FilterSelectBadge, FilterSelectMoreBadge, } from '~/components/Overlay' import { IconChevronDown } from '~/components/Icons' import { Text } from '~/components/Text' import { Color, StitchedCSS, styled } from '~/theme' import { PositionProps } from '~/types' import { deepEqual } from '@saulx/utils' import { SelectLabel, StyledSelect } from './StyledSelect' export type MultiSelectProps = { values?: Value[] options: (Option | Value)[] onChange: (values: Value[]) => void color?: Color filterable?: boolean | 'create' placeholder?: string label?: string overlay?: PositionProps css?: StitchedCSS } const StyledBadgeContainer = styled('div', { display: 'flex', alignItems: 'center', }) const StyledLabelContainer = styled('div', { display: 'flex', width: '100%', justifyContent: 'space-between', alignItems: 'center', }) export const MultiSelect: FC = ({ options, values = [], onChange, css, filterable, color = '$TextPrimary', placeholder = 'Select options', overlay, label, }) => { const ref = useRef() // if these values update force update on the dropdown const [currentValues, open, setValues] = useMultiSelect(options, values, { variant: 'over', filterable, placement: 'left', width: 'target', ...overlay, }) const [displayIndex, setDisplayIndex] = useState(values?.length || 0) useEffect(() => { if (!deepEqual(currentValues, values)) { onChange(currentValues) } setDisplayIndex(currentValues.length) let handle: any const correctIt = (time = 0, cnt = 0) => { clearTimeout(handle) handle = setTimeout(() => { // @ts-ignore if (ref.current.children[0]?.children?.length) { // @ts-ignore const { width } = ref.current.getBoundingClientRect() // @ts-ignore const innerWidth = ref.current.children[0].clientWidth if (innerWidth > width - 80) { // width - 60 let targetW = innerWidth for ( // @ts-ignore let i = ref.current.children[0].children.length - 1; i >= 0; i-- ) { // @ts-ignore const child = ref.current.children[0].children[i] if (!child.getAttribute('data-aviato-select-more')) { targetW -= child.getBoundingClientRect().width + 8 if (targetW <= width - 80) { setDisplayIndex(i) correctIt(25) break } } } } else { for ( let i = 0; // @ts-ignore i < ref.current.children[0].children.length; i++ ) { // @ts-ignore const child = ref.current.children[0].children[i] child.style.opacity = 1 } } if (cnt < 3) { correctIt(25, ++cnt) } } }, time) } correctIt() return () => { clearTimeout(handle) } }, [currentValues, ref]) let optionsBadges: ReactNode if (!currentValues?.length) { optionsBadges = {placeholder} } else { const c = [] const len = Math.min(displayIndex, currentValues.length) for (let i = 0; i < len; i++) { const v = currentValues[i] const opt = options.find((opt) => { if (typeof opt === 'object' && opt.value === v) { return true } return false }) c.push( { const newValues = currentValues.filter((val) => val !== v) setValues(newValues) onChange(newValues) }} /> ) } if (displayIndex < currentValues.length) { c.push( ) } optionsBadges = {c} } if (label) { return ( {optionsBadges} ) } return ( {optionsBadges} ) }