Skip to content

Commit f960691

Browse files
committed
fix(TooltipTrigger): type-guard trigger and tooltip
1 parent 3dc4322 commit f960691

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

src/components/overlays/Tooltip/TooltipTrigger.tsx

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FocusableProvider } from '@react-aria/focus';
22
import {
33
HTMLAttributes,
4+
isValidElement,
45
ReactElement,
56
ReactNode,
67
RefObject,
@@ -23,6 +24,15 @@ import { TooltipContext } from './context';
2324
const DEFAULT_OFFSET = 8; // Offset needed to reach 4px/5px (med/large) distance between tooltip and trigger button
2425
const DEFAULT_CROSS_OFFSET = 0;
2526

27+
// Type guards
28+
function isTriggerFunction(value: unknown): value is TooltipTriggerFunction {
29+
return typeof value === 'function';
30+
}
31+
32+
function isReactElement(value: unknown): value is ReactElement {
33+
return isValidElement(value);
34+
}
35+
2636
export type TooltipTriggerFunction = (
2737
triggerProps: HTMLAttributes<HTMLElement>,
2838
ref: RefObject<HTMLElement>,
@@ -95,12 +105,26 @@ export function TooltipTrigger(props: CubeTooltipTriggerProps) {
95105
const rawChildrenArray = Array.isArray(children)
96106
? (children as unknown[])
97107
: ([children] as unknown[]);
98-
const childrenArray = rawChildrenArray as unknown as [
99-
ReactElement | string | TooltipTriggerFunction,
100-
ReactElement,
101-
];
102-
let [trigger, tooltip] = childrenArray;
103-
const isTriggerFunction = typeof trigger === 'function';
108+
109+
const [trigger, tooltip] = rawChildrenArray;
110+
111+
// Type guard the tooltip
112+
if (!isReactElement(tooltip)) {
113+
throw new Error(
114+
'CubeUIKit: TooltipTrigger expects the second child to be a valid React element (Tooltip component).',
115+
);
116+
}
117+
118+
// Type guard the trigger
119+
if (
120+
!isTriggerFunction(trigger) &&
121+
!isReactElement(trigger) &&
122+
typeof trigger !== 'string'
123+
) {
124+
throw new Error(
125+
'CubeUIKit: TooltipTrigger expects the first child to be a function, React element, or string.',
126+
);
127+
}
104128

105129
// Show deprecation warning for activeWrap
106130
if (activeWrap && process.env.NODE_ENV === 'development') {
@@ -151,12 +175,10 @@ export function TooltipTrigger(props: CubeTooltipTriggerProps) {
151175
};
152176

153177
// Function trigger pattern (new)
154-
if (isTriggerFunction) {
155-
const triggerFn = trigger as TooltipTriggerFunction;
156-
178+
if (isTriggerFunction(trigger)) {
157179
return (
158180
<>
159-
{triggerFn(triggerProps, tooltipTriggerRef)}
181+
{trigger(triggerProps, tooltipTriggerRef)}
160182
<TooltipContext.Provider value={tooltipContextValue}>
161183
<OverlayWrapper
162184
isOpen={state.isOpen}

0 commit comments

Comments
 (0)