From 114c968bff7b060357a9d374f15b3e090041eb09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Mon, 28 Sep 2026 10:39:00 +0800 Subject: [PATCH] refactor: use the shared non-nullable overlay guard --- package.json | 2 +- src/Tooltip.tsx | 7 +++++-- tests/renderability.test.tsx | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/renderability.test.tsx diff --git a/package.json b/package.json index a040308..377c2f2 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ }, "dependencies": { "@rc-component/trigger": "^3.10.0", - "@rc-component/util": "^1.11.1", + "@rc-component/util": "^1.13.0", "clsx": "^2.1.1" }, "devDependencies": { diff --git a/src/Tooltip.tsx b/src/Tooltip.tsx index fc67dcb..2ff59f7 100644 --- a/src/Tooltip.tsx +++ b/src/Tooltip.tsx @@ -6,7 +6,7 @@ import type { TriggerRef, } from '@rc-component/trigger'; import Trigger from '@rc-component/trigger'; -import { useId } from '@rc-component/util'; +import { isNonNullable, useId } from '@rc-component/util'; import { clsx } from 'clsx'; import * as React from 'react'; import { useImperativeHandle, useRef } from 'react'; @@ -121,7 +121,10 @@ const Tooltip = React.forwardRef((props, ref) => { const getChildren: TriggerProps['children'] = ({ open }) => { const child = React.Children.only(children); const childAriaDescribedBy = (child.props as React.AriaAttributes)['aria-describedby']; - const ariaDescribedBy = [childAriaDescribedBy, overlay != null && open ? mergedId : undefined] + const ariaDescribedBy = [ + childAriaDescribedBy, + isNonNullable(overlay) && open ? mergedId : undefined, + ] .filter(Boolean) .join(' '); const ariaProps: React.AriaAttributes = { diff --git a/tests/renderability.test.tsx b/tests/renderability.test.tsx new file mode 100644 index 0000000..c0611db --- /dev/null +++ b/tests/renderability.test.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Tooltip from '../src'; + +it.each([0, false, '', null, undefined])( + 'preserves aria-describedby presence for overlay %s', + (overlay) => { + const { getByRole } = render( + + + , + ); + const button = getByRole('button'); + if (overlay === null || overlay === undefined) { + expect(button).not.toHaveAttribute('aria-describedby'); + } else { + expect(button).toHaveAttribute('aria-describedby', 'tip'); + } + }, +);