|
|
@ -6,13 +6,16 @@ import { useStyles2 } from '../../themes'; |
|
|
|
import { Checkbox } from '../Forms/Checkbox'; |
|
|
|
import { Checkbox } from '../Forms/Checkbox'; |
|
|
|
import { Box } from '../Layout/Box/Box'; |
|
|
|
import { Box } from '../Layout/Box/Box'; |
|
|
|
import { Portal } from '../Portal/Portal'; |
|
|
|
import { Portal } from '../Portal/Portal'; |
|
|
|
|
|
|
|
import { ScrollContainer } from '../ScrollContainer/ScrollContainer'; |
|
|
|
import { Text } from '../Text/Text'; |
|
|
|
import { Text } from '../Text/Text'; |
|
|
|
import { Tooltip } from '../Tooltip'; |
|
|
|
import { Tooltip } from '../Tooltip'; |
|
|
|
|
|
|
|
|
|
|
|
import { ComboboxOption, ComboboxBaseProps, AutoSizeConditionals, itemToString } from './Combobox'; |
|
|
|
import { ComboboxOption, ComboboxBaseProps, AutoSizeConditionals, itemToString } from './Combobox'; |
|
|
|
import { OptionListItem } from './OptionListItem'; |
|
|
|
import { OptionListItem } from './OptionListItem'; |
|
|
|
import { ValuePill } from './ValuePill'; |
|
|
|
import { ValuePill } from './ValuePill'; |
|
|
|
|
|
|
|
import { getComboboxStyles } from './getComboboxStyles'; |
|
|
|
import { getMultiComboboxStyles } from './getMultiComboboxStyles'; |
|
|
|
import { getMultiComboboxStyles } from './getMultiComboboxStyles'; |
|
|
|
|
|
|
|
import { useComboboxFloat } from './useComboboxFloat'; |
|
|
|
import { useMeasureMulti } from './useMeasureMulti'; |
|
|
|
import { useMeasureMulti } from './useMeasureMulti'; |
|
|
|
|
|
|
|
|
|
|
|
interface MultiComboboxBaseProps<T extends string | number> extends Omit<ComboboxBaseProps<T>, 'value' | 'onChange'> { |
|
|
|
interface MultiComboboxBaseProps<T extends string | number> extends Omit<ComboboxBaseProps<T>, 'value' | 'onChange'> { |
|
|
@ -35,9 +38,13 @@ export const MultiCombobox = <T extends string | number>(props: MultiComboboxPro |
|
|
|
return getSelectedItemsFromValue<T>(value, options); |
|
|
|
return getSelectedItemsFromValue<T>(value, options); |
|
|
|
}, [value, options, isAsync]); |
|
|
|
}, [value, options, isAsync]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const styles = useStyles2(getComboboxStyles); |
|
|
|
|
|
|
|
|
|
|
|
const [items, _baseSetItems] = useState(isAsync ? [] : options); |
|
|
|
const [items, _baseSetItems] = useState(isAsync ? [] : options); |
|
|
|
const [isOpen, setIsOpen] = useState(false); |
|
|
|
const [isOpen, setIsOpen] = useState(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { inputRef: containerRef, floatingRef, floatStyles, scrollRef } = useComboboxFloat(items, isOpen); |
|
|
|
|
|
|
|
|
|
|
|
const multiStyles = useStyles2(getMultiComboboxStyles, isOpen); |
|
|
|
const multiStyles = useStyles2(getMultiComboboxStyles, isOpen); |
|
|
|
|
|
|
|
|
|
|
|
const { measureRef, suffixMeasureRef, shownItems } = useMeasureMulti(selectedItems, width); |
|
|
|
const { measureRef, suffixMeasureRef, shownItems } = useMeasureMulti(selectedItems, width); |
|
|
@ -124,7 +131,7 @@ export const MultiCombobox = <T extends string | number>(props: MultiComboboxPro |
|
|
|
const visibleItems = isOpen ? selectedItems : selectedItems.slice(0, shownItems); |
|
|
|
const visibleItems = isOpen ? selectedItems : selectedItems.slice(0, shownItems); |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div> |
|
|
|
<div ref={containerRef}> |
|
|
|
<div |
|
|
|
<div |
|
|
|
style={{ width: width === 'auto' ? undefined : width }} |
|
|
|
style={{ width: width === 'auto' ? undefined : width }} |
|
|
|
className={multiStyles.wrapper} |
|
|
|
className={multiStyles.wrapper} |
|
|
@ -175,31 +182,37 @@ export const MultiCombobox = <T extends string | number>(props: MultiComboboxPro |
|
|
|
/> |
|
|
|
/> |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div {...getMenuProps()}> |
|
|
|
<Portal> |
|
|
|
<Portal> |
|
|
|
<div |
|
|
|
|
|
|
|
className={cx(styles.menu, !isOpen && styles.menuClosed)} |
|
|
|
|
|
|
|
style={{ ...floatStyles }} |
|
|
|
|
|
|
|
{...getMenuProps({ ref: floatingRef })} |
|
|
|
|
|
|
|
> |
|
|
|
{isOpen && ( |
|
|
|
{isOpen && ( |
|
|
|
<div> |
|
|
|
<ScrollContainer showScrollIndicators maxHeight="inherit" ref={scrollRef}> |
|
|
|
{items.map((item, index) => { |
|
|
|
<ul> |
|
|
|
const itemProps = getItemProps({ item, index }); |
|
|
|
{items.map((item, index) => { |
|
|
|
const isSelected = isOptionSelected(item); |
|
|
|
const itemProps = getItemProps({ item, index }); |
|
|
|
const id = 'multicombobox-option-' + item.value.toString(); |
|
|
|
const isSelected = isOptionSelected(item); |
|
|
|
return ( |
|
|
|
const id = 'multicombobox-option-' + item.value.toString(); |
|
|
|
<li |
|
|
|
return ( |
|
|
|
key={item.value} |
|
|
|
<li |
|
|
|
{...itemProps} |
|
|
|
key={item.value} |
|
|
|
style={highlightedIndex === index ? { backgroundColor: 'blue' } : {}} |
|
|
|
{...itemProps} |
|
|
|
> |
|
|
|
style={highlightedIndex === index ? { backgroundColor: 'blue' } : {}} |
|
|
|
{' '} |
|
|
|
> |
|
|
|
{/* Add styling with virtualization */} |
|
|
|
{' '} |
|
|
|
<Checkbox key={id} value={isSelected} aria-labelledby={id} /> |
|
|
|
{/* Add styling with virtualization */} |
|
|
|
<OptionListItem option={item} id={id} /> |
|
|
|
<Checkbox key={id} value={isSelected} aria-labelledby={id} /> |
|
|
|
</li> |
|
|
|
<OptionListItem option={item} id={id} /> |
|
|
|
); |
|
|
|
</li> |
|
|
|
})} |
|
|
|
); |
|
|
|
</div> |
|
|
|
})} |
|
|
|
|
|
|
|
</ul> |
|
|
|
|
|
|
|
</ScrollContainer> |
|
|
|
)} |
|
|
|
)} |
|
|
|
</Portal> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Portal> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|