diff --git a/components/popper/__tests__/__snapshots__/index.test.tsx.snap b/components/popper/__tests__/__snapshots__/index.test.tsx.snap index 9c1c1690..5c674087 100644 --- a/components/popper/__tests__/__snapshots__/index.test.tsx.snap +++ b/components/popper/__tests__/__snapshots__/index.test.tsx.snap @@ -12,7 +12,7 @@ exports[`Popper API test getTriggerElement is useful 1`] = ` tip="tips text" > text @@ -23,7 +23,7 @@ exports[`Popper API test getTriggerElement is useful 1`] = ` test text diff --git a/components/popper/index.tsx b/components/popper/index.tsx index b9ea8ebe..f37860ab 100644 --- a/components/popper/index.tsx +++ b/components/popper/index.tsx @@ -10,6 +10,7 @@ import React, { MutableRefObject, } from 'react' import { createPopper, Instance, Modifier, OptionsGeneric, Placement, VirtualElement } from '@popperjs/core' +import ResizeObserver from 'resize-observer-polyfill' import { tuple } from '../_utils/type' import classnames from 'classnames' import debounce from 'lodash/debounce' @@ -40,7 +41,18 @@ export const Triggers = tuple('hover', 'focus', 'click', 'contextMenu') export type TriggerType = typeof Triggers[number] -export type Reason = TriggerType | 'scroll' | 'clickOutside' | 'clickToClose' | 'parentHidden' | 'unknown' +export type Reason = + | TriggerType + | 'scroll' + | 'clickOutside' + | 'clickToClose' + | 'parentHidden' + | 'unknown' + | 'selectPopperItem' + | 'pressEnter' + | 'escEnter' + | 'delEnter' + | 'otherEnter' export type RenderFunction = () => React.ReactNode @@ -329,13 +341,17 @@ export const Popper = forwardRef((props, ref) => { triggerOpen(nextOpen, triggerType, delay) } - const onClick = () => { - if (!visibleInner) { - onTriggerInner(true, 'click') - } else if (clickToClose) { - onTriggerInner(false, 'clickToClose') - } - } + const onClick = debounce( + () => { + if (!visibleInner) { + onTriggerInner(true, 'click') + } else if (clickToClose) { + onTriggerInner(false, 'clickToClose') + } + }, + 10, + { leading: true }, + ) const onFocus = () => { onTriggerInner(true, 'focus') @@ -407,6 +423,14 @@ export const Popper = forwardRef((props, ref) => { } } + const registerSubPopup = () => { + setTimeout(() => { + if (popperRef?.current) { + parentContext?.registerSubPopup(id, popperRef?.current) + } + }, 10) + } + useEffect(() => { onVisibleChangeRef.current = onVisibleChange }, [onVisibleChange]) @@ -587,17 +611,42 @@ export const Popper = forwardRef((props, ref) => { })) popperInstance.current?.forceUpdate() } - setTimeout(() => { - if (popperRef) { - if (popperRef?.current) { - parentContext?.registerSubPopup(id, popperRef?.current) - } - } - }, 10) + registerSubPopup() } } }, [visibleInner, placementInner, arrow]) + useEffect(() => { + if (!popperRefDom.current) return + + const lastSize = { + width: popperRefDom.current.offsetWidth, + height: popperRefDom.current.offsetHeight, + } + + const dimensionToObserve = + placementInner.startsWith('top') || placementInner.startsWith('bottom') ? 'height' : 'width' + + const resizeObserver = new ResizeObserver((entries) => { + entries.forEach((entry) => { + const { width, height } = entry.contentRect + if (dimensionToObserve === 'height' && height !== lastSize.height) { + lastSize.height = height + popperInstance.current?.update() + } else if (dimensionToObserve === 'width' && width !== lastSize.width) { + lastSize.width = width + popperInstance.current?.update() + } + }) + }) + + resizeObserver.observe(popperRefDom.current) + + return () => { + resizeObserver?.disconnect() + } + }, [exist, placementInner]) + useEnhancedEffect(() => { if (!exist) { return undefined @@ -613,11 +662,7 @@ export const Popper = forwardRef((props, ref) => { popperRefDom.current as HTMLElement, popperOptionsInner, ) - setTimeout(() => { - if (popperRef?.current) { - parentContext?.registerSubPopup(id, popperRef?.current) - } - }, 10) + registerSubPopup() } return () => { @@ -659,7 +704,7 @@ export const Popper = forwardRef((props, ref) => { const referenceProps = { ref: referenceRef, - className: classnames(referenceElement?.props?.className, referencePrefixCls), + className: classnames(referencePrefixCls, referenceElement?.props?.className), } return ( diff --git a/components/tooltip/index.md b/components/tooltip/index.md index 6e031e05..eed3c515 100644 --- a/components/tooltip/index.md +++ b/components/tooltip/index.md @@ -48,11 +48,32 @@ subtitle: 文字提示 | clickToClose | 点击浮层是否可关闭 | boolean | true | 1.0.0 | | trigger | 触发行为,有 `hover` \| `focus` \| `click` \| `contextMenu` 四个行为可选,可使用数组设置多个触发行为 | string \| string\[] | `hover` | 1.0.0 | | visible | 手动控制浮层显隐 | boolean | false | 1.0.0 | -| onVisibleChange | 显示隐藏的回调 | (visible) => void | - | 1.0.0 | +| onVisibleChange | 显示隐藏的回调 | (visible, reason:IReason) => void | - | 1.8.29 | | autoPlacement | 溢出边界时改变 placement,默认镜向翻动 | boolean | true | 1.8.10 | -| autoPlacementList | 溢出边界时,placement 备选展示位置 [参考 popper](https://popper.js.org/docs/v2/modifiers/flip/) | placement\[] | - | 1.8.10 | +| autoPlacementList | 溢出边界时,placement 备选展示位置参考 placement | placement\[] | - | 1.8.10 | | customerModifiers | 自定义修饰符 [参考 popper](https://popper.js.org/docs/v2/modifiers/) | (modifiers: Partial>\[]) => Partial>\[] | - | 1.8.10 | +# Tooltip.onVisibleChange.IReason + +其它组件:(如 `Dropdown` / `Select` / `DatePicker` / `ColorPicker` / `CityPicker` / `Cascader`)使用时也会触发 IReason,下列简称`其它组件` + +| 参数 | 说明 | 版本 | +| ---------------- | -------------------------------------------------------- | ------ | +| click | 点击,仅在 placement 为 click 时出现 | 1.8.29 | +| hover | 悬停,仅在 placement 为 hover 时出现 | 1.8.29 | +| focus | 聚集,仅在 placement 为 focus 时出现 | 1.8.29 | +| contextMenu | 点击右键,仅在 placement 为 contextMenu 时出现 | 1.8.29 | +| clickToClose | 再次次点击触发元素关闭,仅在 clickToClose 为 true 时出现 | 1.8.29 | +| clickOutside | 点击外部关闭 | 1.8.29 | +| parentHidden | 嵌套 tooltip 中,父级关闭 | 1.8.29 | +| scroll | 滚动导致的关闭,仅在 scrollHidden 为 true 时出现 | 1.8.29 | +| selectPopperItem | `其它组件` 选中弹窗选项触发关闭 | 1.8.29 | +| pressEnter | `其它组件` 回车选中后触发关闭 | 1.8.29 | +| escEnter | `其它组件` 点击 ESC 触发关闭 | 1.8.29 | +| delEnter | `其它组件` 点击回退删除触发关闭 | 1.8.29 | +| otherEnter | `其它组件` 点击其它键时触发关闭 | 1.8.29 | +| unknown | 受控或其它情况值的改变 | 1.8.29 | + ## Design Token | 分类 | 组件 token | 全局 token | 默认值 |