Skip to content

Commit

Permalink
refactor: transfer、tooltip (#4306)
Browse files Browse the repository at this point in the history
* refactor(transfer): use composition api (#4135)

* refactor(transfer): use composition api

* fix: remove console

* refactor(tooltip): use composition api (#4059)

* refactor(tooltip): use composition api

* chore: useConfigInject

* fix: remove useless

* style: format code

* refactor: transfer

* refactor: tooltip

Co-authored-by: ajuner <106791576@qq.com>
  • Loading branch information
tangjinzhou and ajuner authored Jul 6, 2021
1 parent 16ee0dd commit 8198cab
Show file tree
Hide file tree
Showing 33 changed files with 2,017 additions and 1,490 deletions.
13 changes: 9 additions & 4 deletions components/dropdown/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,15 @@ const Dropdown = defineComponent({
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
const child = getSlot(this)[0];
const dropdownTrigger = cloneElement(child, {
class: classNames(child?.props?.class, `${prefixCls}-trigger`),
disabled,
});
const dropdownTrigger = cloneElement(
child,
Object.assign(
{
class: classNames(child?.props?.class, `${prefixCls}-trigger`),
},
disabled ? { disabled } : {},
),
);
const triggerActions = disabled ? [] : typeof trigger === 'string' ? [trigger] : trigger;
let alignPoint;
if (triggerActions && triggerActions.indexOf('contextmenu') !== -1) {
Expand Down
612 changes: 408 additions & 204 deletions components/locale-provider/__tests__/__snapshots__/index.test.js.snap

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions components/slider/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ describe('Slider', () => {
await asyncExpect(() => {
expect(document.body.innerHTML).toMatchSnapshot();
wrapper.findAll('.ant-slider-handle')[0].trigger('mouseleave');
}, 0);
}, 100);
await asyncExpect(() => {
expect(document.body.innerHTML).toMatchSnapshot();
}, 0);
}, 100);
});
});
3 changes: 3 additions & 0 deletions components/style/themes/default.less
Original file line number Diff line number Diff line change
Expand Up @@ -775,9 +775,12 @@
// Transfer
// ---
@transfer-header-height: 40px;
@transfer-item-height: @height-base;
@transfer-disabled-bg: @disabled-bg;
@transfer-list-height: 200px;
@transfer-item-hover-bg: @item-hover-bg;
@transfer-item-padding-vertical: 6px;
@transfer-list-search-icon-top: 12px;

// Message
// ---
Expand Down
257 changes: 136 additions & 121 deletions components/tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import type { ExtractPropTypes, CSSProperties } from 'vue';
import { defineComponent, inject } from 'vue';
import { computed, watch } from 'vue';
import { defineComponent, onMounted, ref } from 'vue';
import VcTooltip from '../vc-tooltip';
import classNames from '../_util/classNames';
import getPlacements from './placements';
import PropTypes from '../_util/vue-types';
import { PresetColorTypes } from '../_util/colors';
import {
hasProp,
getComponent,
getStyle,
filterEmpty,
getSlot,
isValidElement,
} from '../_util/props-util';
import warning from '../_util/warning';
import { getPropsSlot, getStyle, filterEmpty, isValidElement } from '../_util/props-util';
import { cloneElement } from '../_util/vnode';
import { defaultConfigProvider } from '../config-provider';
import type { triggerTypes, placementTypes } from './abstractTooltipProps';
import abstractTooltipProps from './abstractTooltipProps';
import useConfigInject from '../_util/hooks/useConfigInject';
import getPlacements, { AdjustOverflow, PlacementsConfig } from './placements';

export { AdjustOverflow, PlacementsConfig };

export type TooltipPlacement = typeof placementTypes;

// https://github.com/react-component/tooltip
// https://github.com/yiminghe/dom-align
export interface TooltipAlignConfig {
points?: [string, string];
offset?: [number | string, number | string];
targetOffset?: [number | string, number | string];
overflow?: { adjustX: boolean; adjustY: boolean };
useCssRight?: boolean;
useCssBottom?: boolean;
useCssTransform?: boolean;
}

const splitObject = (obj: any, keys: string[]) => {
const picked = {};
Expand All @@ -37,59 +49,70 @@ const tooltipProps = {
title: PropTypes.VNodeChild,
};

export type TriggerTypes = typeof triggerTypes[number];

export type PlacementTypes = typeof placementTypes[number];

export type TooltipProps = Partial<ExtractPropTypes<typeof tooltipProps>>;

export default defineComponent({
name: 'ATooltip',
inheritAttrs: false,
props: tooltipProps,
emits: ['update:visible', 'visibleChange'],
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
};
},
data() {
return {
sVisible: !!this.$props.visible || !!this.$props.defaultVisible,
setup(props, { slots, emit, attrs, expose }) {
const { prefixCls, getTargetContainer } = useConfigInject('tooltip', props);

const visible = ref(false);

const tooltip = ref();

onMounted(() => {
warning(
!('default-visible' in attrs) || !('defaultVisible' in attrs),
'Tooltip',
`'defaultVisible' is deprecated, please use 'v-model:visible'`,
);
});
watch(
() => props.visible,
val => {
visible.value = !!val;
},
{ immediate: true },
);

const isNoTitle = () => {
const title = getPropsSlot(slots, props, 'title');
return !title && title !== 0;
};
},
watch: {
visible(val) {
this.sVisible = val;
},
},
methods: {
handleVisibleChange(visible: boolean) {
if (!hasProp(this, 'visible')) {
this.sVisible = this.isNoTitle() ? false : visible;
}
if (!this.isNoTitle()) {
this.$emit('update:visible', visible);
this.$emit('visibleChange', visible);

const handleVisibleChange = (val: boolean) => {
visible.value = isNoTitle() ? false : val;
if (!isNoTitle()) {
emit('update:visible', val);
emit('visibleChange', val);
}
},
};

getPopupDomNode() {
return (this.$refs.tooltip as any).getPopupDomNode();
},
const getPopupDomNode = () => {
return tooltip.value.getPopupDomNode();
};

getPlacements() {
const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = this.$props;
expose({ getPopupDomNode, visible });

const tooltipPlacements = computed(() => {
const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = props;
return (
builtinPlacements ||
getPlacements({
arrowPointAtCenter,
verticalArrowShift: 8,
autoAdjustOverflow,
})
);
},
});

// 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(ele: any) {
const getDisabledCompatibleChildren = (ele: any) => {
if (
((typeof ele.type === 'object' &&
(ele.type.__ANT_BUTTON === true ||
Expand Down Expand Up @@ -128,27 +151,22 @@ export default defineComponent({
},
true,
);
return <span style={spanStyle}>{child}</span>;
return (
<span style={spanStyle} class={`${prefixCls}-disabled-compatible-wrapper`}>
{child}
</span>
);
}
return ele;
},

isNoTitle() {
const title = getComponent(this, 'title');
return !title && title !== 0;
},
};

getOverlay() {
const title = getComponent(this, 'title');
if (title === 0) {
return title;
}
return title || '';
},
const getOverlay = () => {
const title = getPropsSlot(slots, props, 'title');
return title ?? '';
};

// 动态设置动画点
onPopupAlign(domNode: HTMLElement, align: any) {
const placements = this.getPlacements();
const onPopupAlign = (domNode: HTMLElement, align: any) => {
const placements = tooltipPlacements.value;
// 当前返回的位置
const placement = Object.keys(placements).filter(
key =>
Expand All @@ -175,67 +193,64 @@ export default defineComponent({
transformOrigin.left = `${-align.offset[0]}px`;
}
domNode.style.transformOrigin = `${transformOrigin.left} ${transformOrigin.top}`;
},
},
};

render() {
const { $props, $data, $attrs } = this;
const {
prefixCls: customizePrefixCls,
openClassName,
getPopupContainer,
color,
overlayClassName,
} = $props;
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('tooltip', customizePrefixCls);
let children = this.children || filterEmpty(getSlot(this));
children = children.length === 1 ? children[0] : children;
let sVisible = $data.sVisible;
// Hide tooltip when there is no title
if (!hasProp(this, 'visible') && this.isNoTitle()) {
sVisible = false;
}
if (!children) {
return null;
}
const child = this.getDisabledCompatibleChildren(
isValidElement(children) ? children : <span>{children}</span>,
);
const childCls = classNames({
[openClassName || `${prefixCls}-open`]: sVisible,
[child.props && child.props.class]: child.props && child.props.class,
});
const customOverlayClassName = classNames(overlayClassName, {
[`${prefixCls}-${color}`]: color && PresetColorRegex.test(color),
});
let formattedOverlayInnerStyle: CSSProperties;
let arrowContentStyle: CSSProperties;
if (color && !PresetColorRegex.test(color)) {
formattedOverlayInnerStyle = { backgroundColor: color };
arrowContentStyle = { backgroundColor: color };
}
return () => {
const { openClassName, getPopupContainer, color, overlayClassName } = props;
let children = filterEmpty(slots.default?.()) ?? null;
children = children.length === 1 ? children[0] : children;

const vcTooltipProps = {
...$attrs,
...$props,
prefixCls,
getTooltipContainer: getPopupContainer || getContextPopupContainer,
builtinPlacements: this.getPlacements(),
overlay: this.getOverlay(),
visible: sVisible,
ref: 'tooltip',
overlayClassName: customOverlayClassName,
overlayInnerStyle: formattedOverlayInnerStyle,
arrowContent: <span class={`${prefixCls}-arrow-content`} style={arrowContentStyle}></span>,
onVisibleChange: this.handleVisibleChange,
onPopupAlign: this.onPopupAlign,
let tempVisible = visible.value;
// Hide tooltip when there is no title
if (props.visible === undefined && isNoTitle()) {
tempVisible = false;
}
if (!children) {
return null;
}
const child = getDisabledCompatibleChildren(
isValidElement(children) ? children : <span>{children}</span>,
);
const childCls = classNames({
[openClassName || `${prefixCls.value}-open`]: true,
[child.props && child.props.class]: child.props && child.props.class,
});
const customOverlayClassName = classNames(overlayClassName, {
[`${prefixCls.value}-${color}`]: color && PresetColorRegex.test(color),
});
let formattedOverlayInnerStyle: CSSProperties;
let arrowContentStyle: CSSProperties;
if (color && !PresetColorRegex.test(color)) {
formattedOverlayInnerStyle = { backgroundColor: color };
arrowContentStyle = { backgroundColor: color };
}

const vcTooltipProps = {
...attrs,
...props,
prefixCls: prefixCls.value,
getTooltipContainer: getPopupContainer || getTargetContainer.value,
builtinPlacements: tooltipPlacements.value,
overlay: getOverlay(),
visible: tempVisible,
ref: tooltip,
overlayClassName: customOverlayClassName,
overlayInnerStyle: formattedOverlayInnerStyle,
onVisibleChange: handleVisibleChange,
onPopupAlign,
};
return (
<VcTooltip
{...vcTooltipProps}
v-slots={{
arrowContent: () => (
<span class={`${prefixCls.value}-arrow-content`} style={arrowContentStyle}></span>
),
}}
>
{visible.value ? cloneElement(child, { class: childCls }) : child}
</VcTooltip>
);
};
return (
<VcTooltip {...vcTooltipProps}>
{sVisible ? cloneElement(child, { class: childCls }) : child}
</VcTooltip>
);
},
});
Loading

0 comments on commit 8198cab

Please sign in to comment.