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

[Bugfix]: fix the tooltip on disabled children #1658

Merged
merged 14 commits into from
Feb 26, 2021
7 changes: 6 additions & 1 deletion packages/zent/assets/button.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import './theme/default';
@import './theme/font';
@import './mixins/pointer-events';

$btn-height-small: 24px;
$btn-height-normal: 32px;
Expand Down Expand Up @@ -309,12 +310,16 @@ $btn-warning-active: 1;
);
}

&-disabled-wrapper {
cursor: not-allowed;
}

&-disabled,
&-disabled[disabled] {
@include btn-grey(color);
@include theme-color(background-color, stroke, 8);
@include btn-light-grey(border-color);
cursor: not-allowed;
@include prevent-pointer-events;

&:link,
&:visited,
Expand Down
3 changes: 2 additions & 1 deletion packages/zent/assets/checkbox.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import './theme/default';
@import './theme/font';
@import './mixins/pointer-events';
$size: 16px;

.zent-checkbox-group {
Expand Down Expand Up @@ -143,7 +144,7 @@ $size: 16px;
}

& > input[type='checkbox'] {
cursor: not-allowed;
@include prevent-pointer-events;
}
}

Expand Down
7 changes: 6 additions & 1 deletion packages/zent/assets/input.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import './theme/default';
@import './theme/font';
@import './mixins/pointer-events';

$border-radius: 2px;
$border-transition: border 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
Expand Down Expand Up @@ -79,6 +80,10 @@ $large-size: 40px;
.zent-input-close {
@include theme-color(color, stroke, 4);
}

&-disabled {
cursor: not-allowed;
}
}

.zent-textarea-wrapper.zent-input-wrapper {
Expand Down Expand Up @@ -122,7 +127,7 @@ $large-size: 40px;
.zent-input[readonly] {
@include theme-color(background-color, stroke, 8);
@include theme-color(color, stroke, 4);
cursor: not-allowed;
@include prevent-pointer-events;
}

.zent-input-addon-before,
Expand Down
1 change: 1 addition & 0 deletions packages/zent/assets/mixins/_index.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import './popup';
@import './popup-menu-item';
@import './clearfix';
@import './pointer-events';
5 changes: 5 additions & 0 deletions packages/zent/assets/mixins/_pointer-events.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@mixin prevent-pointer-events {
// avoid this disabled element to be the target of pointer events, so that events will trigger on the parent element
// https://github.com/react-component/tooltip/issues/18
pointer-events: none;
}
6 changes: 4 additions & 2 deletions packages/zent/assets/radio.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import './theme/default';
@import './theme/font';
@import './theme/timing-functions';
@import './mixins/pointer-events';

$outer-circle-size: 16px;
$inner-circle-size: 8px;
Expand Down Expand Up @@ -118,7 +119,7 @@ $inner-circle-offset: ($outer-circle-size - $inner-circle-size - 2px) / 2;
}

& > input[type='radio'] {
cursor: not-allowed;
@include prevent-pointer-events;
}
}

Expand Down Expand Up @@ -194,9 +195,10 @@ $inner-circle-offset: ($outer-circle-size - $inner-circle-size - 2px) / 2;
&--disabled {
@include theme-color(color, stroke, 4);
@include theme-color(background-color, stroke, 8);
cursor: not-allowed;

> input[type='radio'] {
cursor: not-allowed;
@include prevent-pointer-events;
}

&.zent-radio-button--checked {
Expand Down
31 changes: 30 additions & 1 deletion packages/zent/src/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { Component } from 'react';
import { Omit } from 'utility-types';
import Group from './Group';
import { IButtonDirectiveProps, ButtonDirective } from './Directive';
import {
IPopoverHoverTriggerContext,
PopoverHoverTriggerContext,
} from '../popover';

export interface IButtonProps
extends Omit<
Expand All @@ -28,6 +32,31 @@ export class Button extends Component<IButtonProps> {

static Group = Group;
static Directive = ButtonDirective;
static contextType = PopoverHoverTriggerContext;
context!: IPopoverHoverTriggerContext;

/**
* Why fixTooltipOnDisabledChildren?
* Mouse events don't trigger on disabled button
* https://github.com/react-component/tooltip/issues/18
*
* Workaround
* 1. Wrap the disabled button/input in another element.
* 2. Add {pointer-events: none} style to the disabled button/input.
*/
renderCompatibleChildren(children: React.ReactNode) {
return this.context.fixTooltipOnDisabledChildren ? (
<span
className="zent-btn-disabled-wrapper"
onMouseEnter={this.props.onMouseEnter}
onMouseLeave={this.props.onMouseLeave}
>
{children}
</span>
) : (
children
);
}

render() {
const {
Expand All @@ -47,7 +76,7 @@ export class Button extends Component<IButtonProps> {
...props
} = this.props;

return (
return this.renderCompatibleChildren(
<ButtonDirective
type={type}
size={size}
Expand Down
26 changes: 24 additions & 2 deletions packages/zent/src/button/Directive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Children, cloneElement, useCallback, useContext, useRef } from 'react';

import Icon, { IconType } from '../icon';
import { DisabledContext } from '../disabled';
import { PopoverHoverTriggerContext } from '../popover';

export interface IButtonDirectiveChildProps {
className?: string;
Expand Down Expand Up @@ -43,9 +44,10 @@ export interface IButtonDirectiveProps<
}

export function ButtonDirective<ChildProps extends IButtonDirectiveChildProps>(
props: IButtonDirectiveProps<ChildProps>
props: IButtonDirectiveProps<ChildProps> & React.HTMLAttributes<HTMLElement>
) {
const disabledContext = useContext(DisabledContext);
const popoverHoverTriggerContext = useContext(PopoverHoverTriggerContext);
const {
outline,
type = 'default',
Expand Down Expand Up @@ -91,7 +93,7 @@ export function ButtonDirective<ChildProps extends IButtonDirectiveChildProps>(
children.props.className
);

return cloneElement<ChildProps>(
const commonChildren = cloneElement<ChildProps>(
children,
{
className,
Expand All @@ -105,4 +107,24 @@ export function ButtonDirective<ChildProps extends IButtonDirectiveChildProps>(
typeof child === 'string' ? <span>{child}</span> : child
) || [])
);

/**
* Mouse events don't trigger on disabled button
* https://github.com/react-component/tooltip/issues/18
*
* Workaround
* 1. Wrap the disabled button/input in another element.
* 2. Add {pointer-events: none} style to the disabled button/input.
*/
return popoverHoverTriggerContext.fixTooltipOnDisabledChildren ? (
<span
className="zent-btn-disabled-wrapper"
onMouseEnter={props.onMouseEnter}
onMouseLeave={props.onMouseLeave}
>
{commonChildren}
</span>
) : (
commonChildren
);
}
7 changes: 6 additions & 1 deletion packages/zent/src/checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import getWidth from '../utils/getWidth';
import GroupContext, { ICheckboxContext } from './GroupContext';
import { DisabledContext, IDisabledContext } from '../disabled';
import CheckboxGroup from './Group';
import omit from '../utils/omit';

export interface ICheckboxEventTarget<Value> extends ICheckboxProps<Value> {
type: 'checkbox';
Expand All @@ -29,6 +30,8 @@ export interface ICheckboxProps<Value> {
labelStyle?: React.CSSProperties;
width?: number;
children?: React.ReactNode;
onMouseEnter?: React.MouseEventHandler<HTMLElement>;
onMouseLeave?: React.MouseEventHandler<HTMLElement>;
}

function getDisabled<Value>(
Expand Down Expand Up @@ -117,11 +120,13 @@ export function Checkbox<Value>(props: ICheckboxProps<Value>) {
style={{
...getWidth(width),
}}
onMouseEnter={props.onMouseEnter}
onMouseLeave={props.onMouseLeave}
>
<span className="zent-checkbox">
<span className="zent-checkbox-inner" />
<input
{...others}
{...omit(others, ['onMouseEnter', 'onMouseLeave'])}
type="checkbox"
checked={checked && !indeterminate}
disabled={disabled}
Expand Down
4 changes: 1 addition & 3 deletions packages/zent/src/grid/SelectionCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ class SelectionCheckbox extends PureComponent<
const { checked } = this.state;
return reason && disabled ? (
<Pop content={reason} trigger="hover" position="top-left" centerArrow>
<span>
<Checkbox onChange={onChange} checked={checked} disabled={disabled} />
</span>
<Checkbox onChange={onChange} checked={checked} disabled={disabled} />
</Pop>
) : (
<Checkbox onChange={onChange} checked={checked} disabled={disabled} />
Expand Down
4 changes: 1 addition & 3 deletions packages/zent/src/grid/SelectionRadio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ class SelectionCheckbox extends PureComponent<
const { checked } = this.state;
return reason && disabled ? (
<Pop content={reason} trigger="hover" position="top-left" centerArrow>
<span>
<Radio onChange={onChange} checked={checked} disabled={disabled} />
</span>
<Radio onChange={onChange} checked={checked} disabled={disabled} />
</Pop>
) : (
<Radio onChange={onChange} checked={checked} disabled={disabled} />
Expand Down
12 changes: 11 additions & 1 deletion packages/zent/src/input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,22 @@ export class Input extends Component<IInputProps, IInputState> {
(props as IInputCoreProps).addonBefore),
'zent-input--has-focus': hasFocus,
'zent-input-wrapper-inline': props.inline,
'zent-input-wrapper-disabled': disabled,
},
className
);

return (
<div className={wrapClass} style={wrapperStyle}>
<div
className={wrapClass}
style={wrapperStyle}
onMouseEnter={
props.onMouseEnter as React.MouseEventHandler<HTMLElement>
}
onMouseLeave={
props.onMouseLeave as React.MouseEventHandler<HTMLElement>
}
>
{renderInner ? renderInner(children) : children}
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions packages/zent/src/pop/Pop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface IPopHoverTriggerProps<
trigger: 'hover';
mouseEnterDelay?: number;
mouseLeaveDelay?: number;
fixTooltipOnDisabledChildren?: boolean;
}

export interface IPopFocusTriggerProps<
Expand Down Expand Up @@ -169,6 +170,7 @@ export class Pop extends Component<IPopProps, IPopState> {
showDelay={props.mouseEnterDelay}
hideDelay={props.mouseLeaveDelay}
anchorOnly={props.anchorOnly}
fixTooltipOnDisabledChildren={props.fixTooltipOnDisabledChildren}
>
{props.children}
</Trigger.Hover>
Expand Down
5 changes: 5 additions & 0 deletions packages/zent/src/pop/README_en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ A floating card opened by clicking, hovering or focusing.
| mouseEnterDelay | Hover open delay(in ms) | number | No | `200` |
| mouseLeaveDelay | Hover close delay(in ms) | number | No | `200` |
| anchorOnly | Only use trigger as hot area | boolean | No | `false` |
| fixTooltipOnDisabledChildren | Fix the tooltip on disabled children | boolean | No | `false` |

**PS**

- `fixTooltipOnDisabledChildren` is only effective on Zent Components.

#### None

Expand Down
5 changes: 5 additions & 0 deletions packages/zent/src/pop/README_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ group: 反馈
| mouseEnterDelay | hover打开的延迟(单位:毫秒) | number | 否 | `200` |
| mouseLeaveDelay | 关闭的的延迟(单位:毫秒) | number | 否 | `200` |
| anchorOnly | 仅考虑 Trigger 作为触发区域 | boolean | 否 | `false` |
| fixTooltipOnDisabledChildren | 被禁用的子节点展示 Tooltip | boolean | 否 | `false` |

**注意**

- `fixTooltipOnDisabledChildren` 仅对 Zent 组件有效。

#### None

Expand Down
Loading