Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Tooltip on disabled button #4865

Merged
merged 4 commits into from Feb 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion components/button/__tests__/index.test.js
@@ -1,5 +1,5 @@
import React from 'react';
import { render } from 'enzyme';
import { render, mount } from 'enzyme';
import { renderToJson } from 'enzyme-to-json';
import Button from '..';

Expand All @@ -17,4 +17,12 @@ describe('Button', () => {
);
expect(renderToJson(wrapper)).toMatchSnapshot();
});

it('have static perperty for type detecting', () => {
const wrapper = mount(
<Button>Button Text</Button>
);
// eslint-disable-next-line
expect(wrapper.type().__ANT_BUTTON).toBe(true);
});
});
1 change: 1 addition & 0 deletions components/button/button.tsx
Expand Up @@ -46,6 +46,7 @@ export interface ButtonProps {

export default class Button extends React.Component<ButtonProps, any> {
static Group: any;
static __ANT_BUTTON = true;

static defaultProps = {
prefixCls: 'ant-btn',
Expand Down
64 changes: 64 additions & 0 deletions components/tooltip/__tests__/tooltip.test.js
@@ -1,6 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import Tooltip from '..';
import Button from '../../button';

describe('Tooltip', () => {
it('check `onVisibleChange` arguments', () => {
Expand Down Expand Up @@ -49,4 +50,67 @@ describe('Tooltip', () => {
expect(onVisibleChange.mock.calls.length).toBe(lastCount); // no change with lastCount
expect(wrapper.ref('tooltip').prop('visible')).toBe(false);
});

it('should hide when mouse leave native disabled button', () => {
const onVisibleChange = jest.fn();
const wrapper = mount(
<Tooltip
title="xxxxx"
mouseEnterDelay={0}
mouseLeaveDelay={0}
onVisibleChange={onVisibleChange}
>
<button disabled>Hello world!</button>
</Tooltip>
);

expect(wrapper.find('span')).toHaveLength(1);
const button = wrapper.find('span').at(0);
button.simulate('mouseenter');
expect(onVisibleChange).toBeCalledWith(true);
expect(wrapper.ref('tooltip').prop('visible')).toBe(true);

button.simulate('mouseleave');
expect(onVisibleChange).toBeCalledWith(false);
expect(wrapper.ref('tooltip').prop('visible')).toBe(false);
});

it('should hide when mouse leave antd disabled Button', () => {
const onVisibleChange = jest.fn();
const wrapper = mount(
<Tooltip
title="xxxxx"
mouseEnterDelay={0}
mouseLeaveDelay={0}
onVisibleChange={onVisibleChange}
>
<Button disabled>Hello world!</Button>
</Tooltip>
);

expect(wrapper.getDOMNode().tagName).toBe('SPAN');
const button = wrapper.find('span').at(0);
button.simulate('mouseenter');
expect(onVisibleChange).toBeCalledWith(true);
expect(wrapper.ref('tooltip').prop('visible')).toBe(true);

button.simulate('mouseleave');
expect(onVisibleChange).toBeCalledWith(false);
expect(wrapper.ref('tooltip').prop('visible')).toBe(false);
});

it('should render disabled Button style properly', () => {
const wrapper1 = mount(
<Tooltip title="xxxxx">
<Button disabled>Hello world!</Button>
</Tooltip>
);
const wrapper2 = mount(
<Tooltip title="xxxxx">
<Button disabled style={{ display: 'block' }}>Hello world!</Button>
</Tooltip>
);
expect(wrapper1.getDOMNode().style.display).toBe('inline-block');
expect(wrapper2.getDOMNode().style.display).toBe('block');
});
});
30 changes: 29 additions & 1 deletion components/tooltip/index.tsx
Expand Up @@ -85,6 +85,32 @@ export default class Tooltip extends React.Component<TooltipProps, any> {
});
}

// Fix Tooltip won't hide at disabled button
// mouse events don't trigger at disabled button in Chrome
// https://github.com/react-component/tooltip/issues/18
getDisabledCompatibleChildren(element) {
if ((element.type.__ANT_BUTTON || element.type === 'button') && element.props.disabled) {
// reserve display style for <Button style={{ display: 'block '}}></Button>
// Note:
// If people override ant-btn's style.display by css,
// it will be affected cause we reset it to 'inline-block'
const displayStyle = (element.props.style && element.props.style.display)
? element.props.style.display : 'inline-block';
const child = cloneElement(element, {
style: {
...element.props.style,
pointerEvents: 'none',
},
});
return (
<span style={{ display: displayStyle, cursor: 'not-allowed' }}>
{child}
</span>
);
}
return element;
}

isNoTitle() {
const { title, overlay } = this.props;
return !title && !overlay; // overlay for old version compatibility
Expand Down Expand Up @@ -132,7 +158,9 @@ export default class Tooltip extends React.Component<TooltipProps, any> {
visible = false;
}

const child = React.isValidElement(children) ? children : <span>{children}</span>;
const child = this.getDisabledCompatibleChildren(
React.isValidElement(children) ? children : <span>{children}</span>
);
const childProps = child.props;
const childCls = classNames(childProps.className, {
[openClassName || `${prefixCls}-open`]: true,
Expand Down