mirror of
https://github.com/apache/superset.git
synced 2026-04-07 10:31:50 +00:00
fix(Select): Prevent closing the select when clicking on a tag (#35487)
This commit is contained in:
committed by
GitHub
parent
821173f6c4
commit
d39c55e941
@@ -779,6 +779,38 @@ test('Renders only an overflow tag if dropdown is open in oneLine mode', async (
|
||||
expect(withinSelector.getByText('+ 2 ...')).toBeVisible();
|
||||
});
|
||||
|
||||
// Test for checking the issue described in: https://github.com/apache/superset/issues/35132
|
||||
test('Maintains stable maxTagCount to prevent click target disappearing in oneLine mode', async () => {
|
||||
render(
|
||||
<Select
|
||||
{...defaultProps}
|
||||
value={[OPTIONS[0], OPTIONS[1], OPTIONS[2]]}
|
||||
mode="multiple"
|
||||
oneLine
|
||||
/>,
|
||||
);
|
||||
|
||||
const withinSelector = within(getElementByClassName('.ant-select-selector'));
|
||||
expect(withinSelector.getByText(OPTIONS[0].label)).toBeVisible();
|
||||
expect(withinSelector.getByText('+ 2 ...')).toBeVisible();
|
||||
|
||||
await userEvent.click(getSelect());
|
||||
expect(withinSelector.getByText(OPTIONS[0].label)).toBeVisible();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
withinSelector.queryByText(OPTIONS[0].label),
|
||||
).not.toBeInTheDocument();
|
||||
expect(withinSelector.getByText('+ 3 ...')).toBeVisible();
|
||||
});
|
||||
|
||||
// Close dropdown
|
||||
await type('{esc}');
|
||||
|
||||
expect(await withinSelector.findByText(OPTIONS[0].label)).toBeVisible();
|
||||
expect(withinSelector.getByText('+ 2 ...')).toBeVisible();
|
||||
});
|
||||
|
||||
test('does not render "Select all" when there are 0 or 1 options', async () => {
|
||||
const { rerender } = render(
|
||||
<Select {...defaultProps} options={[]} mode="multiple" allowNewOptions />,
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
useMemo,
|
||||
useState,
|
||||
useCallback,
|
||||
useRef,
|
||||
ClipboardEvent,
|
||||
Ref,
|
||||
ReactElement,
|
||||
@@ -143,6 +144,32 @@ const Select = forwardRef(
|
||||
: 1
|
||||
: (propsMaxTagCount ?? MAX_TAG_COUNT);
|
||||
|
||||
// Prevent maxTagCount change during click events to avoid click target disappearing
|
||||
const [stableMaxTagCount, setStableMaxTagCount] = useState(maxTagCount);
|
||||
const isOpeningRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (oneLine) {
|
||||
if (isDropdownVisible && !isOpeningRef.current) {
|
||||
// Mark that we're in the opening process
|
||||
isOpeningRef.current = true;
|
||||
// Use requestAnimationFrame to ensure DOM has settled after the click
|
||||
requestAnimationFrame(() => {
|
||||
setStableMaxTagCount(0);
|
||||
isOpeningRef.current = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!isDropdownVisible) {
|
||||
// When closing, immediately show the first tag
|
||||
setStableMaxTagCount(1);
|
||||
isOpeningRef.current = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
setStableMaxTagCount(maxTagCount);
|
||||
}, [maxTagCount, isDropdownVisible, oneLine]);
|
||||
|
||||
const mappedMode = isSingleMode ? undefined : 'multiple';
|
||||
|
||||
const sortSelectedFirst = useCallback(
|
||||
@@ -599,16 +626,16 @@ const Select = forwardRef(
|
||||
|
||||
const omittedCount = useMemo(() => {
|
||||
const num_selected = ensureIsArray(selectValue).length;
|
||||
const num_shown = maxTagCount as number;
|
||||
const num_shown = stableMaxTagCount as number;
|
||||
return num_selected - num_shown - (selectAllMode ? 1 : 0);
|
||||
}, [maxTagCount, selectAllMode, selectValue]);
|
||||
}, [stableMaxTagCount, selectAllMode, selectValue]);
|
||||
|
||||
const customMaxTagPlaceholder = () =>
|
||||
`+ ${omittedCount > 0 ? omittedCount : 1} ...`;
|
||||
|
||||
// We can't remove the + tag so when Select All
|
||||
// is the only item omitted, we subtract one from maxTagCount
|
||||
let actualMaxTagCount = maxTagCount;
|
||||
let actualMaxTagCount = stableMaxTagCount;
|
||||
if (
|
||||
actualMaxTagCount !== 'responsive' &&
|
||||
omittedCount === 0 &&
|
||||
|
||||
Reference in New Issue
Block a user