mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-30 02:59:04 +08:00
fix: ColorPicker hover boundary issues (#42669)
* fix: fix hover boundary issues * test: fix test case * build: modify dependency scope * Update package.json Co-authored-by: MadCcc <1075746765@qq.com> --------- Co-authored-by: afc163 <afc163@gmail.com> Co-authored-by: MadCcc <1075746765@qq.com>
This commit is contained in:
parent
d3ff73a94f
commit
25883ca53a
@ -5,7 +5,7 @@ import type {
|
||||
import classNames from 'classnames';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import type { CSSProperties } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import genPurePanel from '../_util/PurePanel';
|
||||
import type { ConfigConsumerProps } from '../config-provider/context';
|
||||
import { ConfigContext } from '../config-provider/context';
|
||||
@ -97,8 +97,9 @@ const ColorPicker: CompoundedComponent = (props) => {
|
||||
[`${prefixCls}-rtl`]: direction,
|
||||
});
|
||||
const mergeCls = classNames(mergeRootCls, className, hashId);
|
||||
const popupAllowCloseRef = useRef(true);
|
||||
|
||||
const handleChange = (data: Color, type?: HsbaColorType) => {
|
||||
const handleChange = (data: Color, type?: HsbaColorType, pickColor?: boolean) => {
|
||||
let color: Color = generateColor(data);
|
||||
if (colorCleared) {
|
||||
setColorCleared(false);
|
||||
@ -112,6 +113,10 @@ const ColorPicker: CompoundedComponent = (props) => {
|
||||
if (!value) {
|
||||
setColorValue(color);
|
||||
}
|
||||
// Only for drag-and-drop color picking
|
||||
if (pickColor) {
|
||||
popupAllowCloseRef.current = false;
|
||||
}
|
||||
onChange?.(color, color.toHexString());
|
||||
};
|
||||
|
||||
@ -119,6 +124,10 @@ const ColorPicker: CompoundedComponent = (props) => {
|
||||
setColorCleared(clear);
|
||||
};
|
||||
|
||||
const handleChangeComplete = () => {
|
||||
popupAllowCloseRef.current = true;
|
||||
};
|
||||
|
||||
const popoverProps: PopoverProps = {
|
||||
open: popupOpen,
|
||||
trigger,
|
||||
@ -149,9 +158,18 @@ const ColorPicker: CompoundedComponent = (props) => {
|
||||
return wrapSSR(
|
||||
<Popover
|
||||
style={styles?.popup}
|
||||
onOpenChange={setPopupOpen}
|
||||
onOpenChange={(visible) => {
|
||||
if (popupAllowCloseRef.current) {
|
||||
setPopupOpen(visible);
|
||||
}
|
||||
}}
|
||||
content={
|
||||
<ColorPickerPanel {...colorBaseProps} onChange={handleChange} onClear={handleClear} />
|
||||
<ColorPickerPanel
|
||||
{...colorBaseProps}
|
||||
onChange={handleChange}
|
||||
onChangeComplete={handleChangeComplete}
|
||||
onClear={handleClear}
|
||||
/>
|
||||
}
|
||||
overlayClassName={prefixCls}
|
||||
{...popoverProps}
|
||||
|
@ -10,12 +10,22 @@ import ColorPresets from './components/ColorPresets';
|
||||
import type { ColorPickerBaseProps } from './interface';
|
||||
|
||||
interface ColorPickerPanelProps extends ColorPickerBaseProps {
|
||||
onChange?: (value?: Color, type?: HsbaColorType) => void;
|
||||
onChange?: (value?: Color, type?: HsbaColorType, pickColor?: boolean) => void;
|
||||
onChangeComplete?: (type?: HsbaColorType) => void;
|
||||
onClear?: (clear?: boolean) => void;
|
||||
}
|
||||
|
||||
const ColorPickerPanel: FC<ColorPickerPanelProps> = (props) => {
|
||||
const { prefixCls, allowClear, presets, onChange, onClear, color, ...injectProps } = props;
|
||||
const {
|
||||
prefixCls,
|
||||
allowClear,
|
||||
presets,
|
||||
onChange,
|
||||
onClear,
|
||||
onChangeComplete,
|
||||
color,
|
||||
...injectProps
|
||||
} = props;
|
||||
const colorPickerPanelPrefixCls = `${prefixCls}-inner-panel`;
|
||||
|
||||
const extraPanelRender = (panel: React.ReactNode) => (
|
||||
@ -45,8 +55,9 @@ const ColorPickerPanel: FC<ColorPickerPanelProps> = (props) => {
|
||||
<RcColorPicker
|
||||
prefixCls={prefixCls}
|
||||
value={color?.toHsb()}
|
||||
onChange={onChange}
|
||||
onChange={(colorValue, type) => onChange?.(colorValue, type, true)}
|
||||
panelRender={extraPanelRender}
|
||||
onChangeComplete={onChangeComplete}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import { createEvent, fireEvent, render } from '@testing-library/react';
|
||||
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
@ -6,6 +7,28 @@ import { waitFakeTimer } from '../../../tests/utils';
|
||||
import ColorPicker from '../ColorPicker';
|
||||
import type { Color } from '../color';
|
||||
|
||||
function doMouseMove(
|
||||
container: HTMLElement,
|
||||
start: number,
|
||||
end: number,
|
||||
element = 'ant-color-picker-handler',
|
||||
) {
|
||||
const mouseDown = createEvent.mouseDown(container.getElementsByClassName(element)[0], {
|
||||
pageX: start,
|
||||
pageY: start,
|
||||
});
|
||||
fireEvent(container.getElementsByClassName(element)[0], mouseDown);
|
||||
// Drag
|
||||
const mouseMove: any = new Event('mousemove');
|
||||
mouseMove.pageX = end;
|
||||
mouseMove.pageY = end;
|
||||
|
||||
fireEvent(document, mouseMove);
|
||||
|
||||
const mouseUp = createEvent.mouseUp(document);
|
||||
fireEvent(document, mouseUp);
|
||||
}
|
||||
|
||||
describe('ColorPicker', () => {
|
||||
mountTest(ColorPicker);
|
||||
rtlTest(ColorPicker);
|
||||
@ -257,4 +280,23 @@ describe('ColorPicker', () => {
|
||||
container.querySelector('.ant-color-picker-color-block-inner')?.getAttribute('style'),
|
||||
).toEqual('background: rgb(99, 22, 22);');
|
||||
});
|
||||
|
||||
it('Should fix hover boundary issues', async () => {
|
||||
spyElementPrototypes(HTMLElement, {
|
||||
getBoundingClientRect: () => ({
|
||||
x: 0,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
}),
|
||||
});
|
||||
const { container } = render(<ColorPicker trigger="hover" />);
|
||||
fireEvent.mouseEnter(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
doMouseMove(container, 0, 999);
|
||||
expect(container.querySelector('.ant-popover-hidden')).toBeFalsy();
|
||||
fireEvent.mouseLeave(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-popover-hidden')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -114,7 +114,7 @@
|
||||
"@ant-design/react-slick": "~1.0.0",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@ctrl/tinycolor": "^3.6.0",
|
||||
"@rc-component/color-picker": "~1.1.1",
|
||||
"@rc-component/color-picker": "~1.2.0",
|
||||
"@rc-component/mutate-observer": "^1.0.0",
|
||||
"@rc-component/tour": "~1.8.0",
|
||||
"@rc-component/trigger": "^1.13.0",
|
||||
@ -324,4 +324,4 @@
|
||||
"*.{ts,tsx,js,jsx}": "prettier --ignore-unknown --write",
|
||||
"*.{json,less,md}": "prettier --ignore-unknown --write"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user