Skip to content

Commit

Permalink
Select: handle self-closing popover when tapping outside
Browse files Browse the repository at this point in the history
  • Loading branch information
Tai-DucTran committed Sep 18, 2024
1 parent 0630581 commit 935ab31
Showing 1 changed file with 84 additions and 54 deletions.
138 changes: 84 additions & 54 deletions src/@next/Select/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { isEmpty } from 'lodash-es';
import { Option, Section } from '../Menu';
import { Popover } from '../Popover';
Expand Down Expand Up @@ -101,6 +101,9 @@ export const Select = ({
isPlaceholderFloating,
}: SelectProps) => {
const [popoverActive, setPopoverActive] = useState(false);
const selectRef = useRef<HTMLDivElement>(null);
const popoverRef = useRef<HTMLDivElement>(null);

const [optionListHeight, setOptionListHeight] = useState('');
const [menuOptions, setMenuOptions] = useState([]);
const { length: optionsLength } = options;
Expand All @@ -126,6 +129,28 @@ export const Select = ({
setMenuOptions(newState);
};

const handleClickOutside = useCallback((event: MouseEvent) => {
const selectElement = selectRef.current;
const popoverElement = popoverRef.current;
const target = event.target as Node;

if (
selectElement &&
popoverElement &&
!selectElement.contains(target) &&
!popoverElement.contains(target)
) {
setPopoverActive(false);
}
}, []);

useEffect(() => {
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [handleClickOutside]);

const handleClose = () => {
setPopoverActive(false);
onClose?.();
Expand All @@ -147,7 +172,10 @@ export const Select = ({
};

const handleSelectClick = () => {
setPopoverActive(!popoverActive);
if (!disabled) {
setPopoverActive(true);
}
onSelectClick?.();
};

useEffect(
Expand Down Expand Up @@ -246,57 +274,59 @@ export const Select = ({
};

return (
<Popover
active={popoverActive}
activator={
<ActivatorWrapper width={width}>
{label && !isPlaceholderFloating && <Label>{label}</Label>}
{activator()}
{helpText && (
<HelpTextContainer>
<Typography
as="span"
variant="subtitle2"
color={disabled ? Neutral.B85 : Neutral.B40}
>
{helpText}
</Typography>
</HelpTextContainer>
)}
</ActivatorWrapper>
}
onClose={handleClose}
autofocusTarget="none"
preventFocusOnClose
preferredAlignment="left"
preferredPosition="below"
fullWidth
fitContent={optionListFitContent}
zIndexOverride={zIndexOverride}
>
{!disabled && (
<Popover.Pane height={optionListHeight}>
<OptionList
loading={loadingOptions}
menuOptions={menuOptions}
allowMultiple={allowMultiple}
onSelect={onSelect}
sections={sections}
selectedValues={selectedValues}
width={width}
onMenuClose={handleClose}
noOptionsMessage={
optionsPlaceholderProps &&
(!inputValue
? optionsPlaceholderProps.idle
: optionsPlaceholderProps.noResult)
}
updateSearchableSelectState={newState =>
updateSearchableSelectState(newState)
}
/>
</Popover.Pane>
)}
</Popover>
<div ref={selectRef}>
<Popover
active={popoverActive}
activator={
<ActivatorWrapper width={width} onClick={handleSelectClick}>
{label && !isPlaceholderFloating && <Label>{label}</Label>}
{activator()}
{helpText && (
<HelpTextContainer>
<Typography
as="span"
variant="subtitle2"
color={disabled ? Neutral.B85 : Neutral.B40}
>
{helpText}
</Typography>
</HelpTextContainer>
)}
</ActivatorWrapper>
}
onClose={handleClose}
autofocusTarget="none"
preventFocusOnClose
preferredAlignment="left"
preferredPosition="below"
fullWidth
fitContent={optionListFitContent}
zIndexOverride={zIndexOverride}
>
{!disabled && (
<Popover.Pane height={optionListHeight}>
<OptionList
loading={loadingOptions}
menuOptions={menuOptions}
allowMultiple={allowMultiple}
onSelect={onSelect}
sections={sections}
selectedValues={selectedValues}
width={width}
onMenuClose={handleClose}
noOptionsMessage={
optionsPlaceholderProps &&
(!inputValue
? optionsPlaceholderProps.idle
: optionsPlaceholderProps.noResult)
}
updateSearchableSelectState={newState =>
updateSearchableSelectState(newState)
}
/>
</Popover.Pane>
)}
</Popover>
</div>
);
};

0 comments on commit 935ab31

Please sign in to comment.