diff --git a/components/tooltip/__docs__/Tooltip.stories.jsx b/components/tooltip/__docs__/Tooltip.stories.jsx
index 343839e44..9a80ef7a5 100644
--- a/components/tooltip/__docs__/Tooltip.stories.jsx
+++ b/components/tooltip/__docs__/Tooltip.stories.jsx
@@ -59,6 +59,11 @@ export default {
options: ['info', 'error'],
description: 'Theme of tooltip: info (blue) or error (red)',
},
+ iconVariant: {
+ control: 'select',
+ options: ['bare', 'error', 'inverse', 'warning'],
+ description: 'Styles the default info icon trigger (no children)',
+ },
variant: {
control: 'select',
options: ['base', 'learnMore', 'list-item'],
@@ -172,7 +177,8 @@ export const LearnMore = {
parameters: {
docs: {
description: {
- story: 'The Learn More variant displays an info icon as the trigger. When no children are provided and `onClickTrigger` is set, it renders as a clickable link.',
+ story:
+ 'The Learn More variant displays an info icon as the trigger. When no children are provided and `onClickTrigger` is set, it renders as a clickable link.',
},
},
},
@@ -197,7 +203,14 @@ export const AllAlignments = {
];
return (
-
+
{alignments.map((alignment) => (
(
-
+
Hover over this text
@@ -274,7 +291,8 @@ export const WithDelay = {
parameters: {
docs: {
description: {
- story: 'You can configure open and close delays. This example has a 500ms open delay and 300ms close delay.',
+ story:
+ 'You can configure open and close delays. This example has a 500ms open delay and 300ms close delay.',
},
},
},
@@ -297,7 +315,8 @@ export const AnchoredNubbin = {
parameters: {
docs: {
description: {
- story: 'The anchored nubbin variant attaches the arrow directly to the trigger element. Use `hasStaticAlignment: true` with this feature.',
+ story:
+ 'The anchored nubbin variant attaches the arrow directly to the trigger element. Use `hasStaticAlignment: true` with this feature.',
},
},
},
@@ -339,7 +358,8 @@ export const InButtonGroup = {
parameters: {
docs: {
description: {
- story: 'Tooltips work well with icon buttons in a button group to provide context about each action.',
+ story:
+ 'Tooltips work well with icon buttons in a button group to provide context about each action.',
},
},
},
@@ -358,11 +378,7 @@ export const Controlled = {
onClick={() => setIsOpen(!isOpen)}
/>
-
+
@@ -371,7 +387,8 @@ export const Controlled = {
parameters: {
docs: {
description: {
- story: 'Use the `isOpen` prop to control tooltip visibility programmatically. When set, hover/focus behavior is disabled.',
+ story:
+ 'Use the `isOpen` prop to control tooltip visibility programmatically. When set, hover/focus behavior is disabled.',
},
},
},
@@ -387,7 +404,44 @@ export const DefaultTrigger = {
parameters: {
docs: {
description: {
- story: 'When no children are provided, Tooltip renders a default info icon button as the trigger.',
+ story:
+ 'When no children are provided, Tooltip renders a default info icon button as the trigger.',
+ },
+ },
+ },
+};
+
+// Icon variants on the default trigger (matches lightning-helptext icon-variant)
+export const IconVariants = {
+ render: () => (
+
+ {['bare', 'warning', 'error'].map((iconVariant) => (
+
+ {' '}
+ {iconVariant}
+
+ ))}
+
+ {' '}
+ inverse
+
+
+ ),
+ parameters: {
+ docs: {
+ description: {
+ story:
+ 'The `iconVariant` prop styles the default info icon trigger, like `icon-variant` on `lightning-helptext`. Use `inverse` on dark backgrounds, and `warning` or `error` to draw attention to the help text.',
},
},
},
diff --git a/components/tooltip/__tests__/tooltip.test.jsx b/components/tooltip/__tests__/tooltip.test.jsx
index aae9dae22..30263ac9c 100644
--- a/components/tooltip/__tests__/tooltip.test.jsx
+++ b/components/tooltip/__tests__/tooltip.test.jsx
@@ -18,7 +18,10 @@ describe('SLDSTooltip', () => {
id: 'myTooltip123',
};
- const renderTooltip = (props = {}, children =
) => {
+ const renderTooltip = (
+ props = {},
+ children =
+ ) => {
return render(
@@ -40,24 +43,32 @@ describe('SLDSTooltip', () => {
describe('component basic props render', () => {
it('is not open initially', () => {
renderTooltip({ align: 'top' });
- expect(document.querySelector('.slds-popover_tooltip')).not.toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).not.toBeInTheDocument();
});
describe('expanded', () => {
it('shows tooltip on mouse enter', async () => {
renderTooltip({ align: 'top' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
});
});
it('adds nubbin class', async () => {
renderTooltip({ align: 'top' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
@@ -69,24 +80,35 @@ describe('SLDSTooltip', () => {
it('closes on mouse leave', async () => {
renderTooltip({ align: 'top' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
});
await userEvent.unhover(trigger);
- await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).not.toBeInTheDocument();
- }, { timeout: 200 });
+ await waitFor(
+ () => {
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).not.toBeInTheDocument();
+ },
+ { timeout: 200 }
+ );
});
it('positions tooltip relative to trigger', async () => {
renderTooltip({ align: 'top' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
@@ -110,14 +132,18 @@ describe('SLDSTooltip', () => {
describe('Custom props work as expected', () => {
it('does not open when isOpen is false', async () => {
renderTooltip({ isOpen: false });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
// Wait a moment to ensure it doesn't open
- await new Promise(resolve => setTimeout(resolve, 100));
+ await new Promise((resolve) => setTimeout(resolve, 100));
- expect(document.querySelector('.slds-popover_tooltip')).not.toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).not.toBeInTheDocument();
});
it('opens immediately when isOpen is true', async () => {
@@ -132,7 +158,9 @@ describe('SLDSTooltip', () => {
it('uses custom id when provided', () => {
renderTooltip({ id: 'custom-tooltip-id' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
// The id will be used for aria-describedby when open
expect(trigger).not.toHaveAttribute('aria-describedby');
@@ -140,38 +168,58 @@ describe('SLDSTooltip', () => {
it('respects hoverOpenDelay', async () => {
const { container } = renderTooltip({ hoverOpenDelay: 100 });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
fireEvent.mouseEnter(trigger);
// Should not be open immediately
- expect(document.querySelector('.slds-popover_tooltip')).not.toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).not.toBeInTheDocument();
// Should open after delay
- await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
- }, { timeout: 200 });
+ await waitFor(
+ () => {
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
+ },
+ { timeout: 200 }
+ );
});
it('respects hoverCloseDelay', async () => {
renderTooltip({ hoverCloseDelay: 100 });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
});
fireEvent.mouseLeave(trigger, { relatedTarget: document.body });
// Should still be open immediately after mouse leave
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
// Should close after delay
- await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).not.toBeInTheDocument();
- }, { timeout: 200 });
+ await waitFor(
+ () => {
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).not.toBeInTheDocument();
+ },
+ { timeout: 200 }
+ );
});
});
@@ -181,7 +229,9 @@ describe('SLDSTooltip', () => {
alignments.forEach((alignment) => {
it(`renders with ${alignment} alignment`, async () => {
renderTooltip({ align: alignment });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
@@ -207,7 +257,9 @@ describe('SLDSTooltip', () => {
describe('Theme prop', () => {
it('applies error theme', async () => {
renderTooltip({ theme: 'error' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
@@ -219,7 +271,9 @@ describe('SLDSTooltip', () => {
it('applies info theme by default', async () => {
renderTooltip();
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
@@ -231,53 +285,152 @@ describe('SLDSTooltip', () => {
});
});
+ describe('IconVariant prop', () => {
+ const renderDefaultTrigger = (props = {}) =>
+ render(
+
+
+
+ );
+
+ it('renders the default trigger with bare styling by default', () => {
+ renderDefaultTrigger();
+ const button = screen.getByRole('button', { name: 'Help' });
+ const svg = button.querySelector('svg');
+
+ expect(button).toHaveClass('slds-button', 'slds-button_icon');
+ expect(button).not.toHaveClass('slds-button_icon-inverse');
+ expect(svg).not.toHaveClass('slds-icon-text-warning');
+ expect(svg).not.toHaveClass('slds-icon-text-error');
+ });
+
+ it('applies inverse button classes to the default trigger', () => {
+ renderDefaultTrigger({ iconVariant: 'inverse' });
+ const button = screen.getByRole('button', { name: 'Help' });
+
+ expect(button).toHaveClass(
+ 'slds-button',
+ 'slds-button_icon',
+ 'slds-button_icon-bare',
+ 'slds-button_icon-inverse'
+ );
+ });
+
+ it.each(['warning', 'error'])(
+ 'applies %s icon color to the default trigger',
+ (iconVariant) => {
+ renderDefaultTrigger({ iconVariant });
+ const button = screen.getByRole('button', { name: 'Help' });
+
+ expect(button).toHaveClass('slds-button', 'slds-button_icon');
+ expect(button.querySelector('svg')).toHaveClass(
+ 'slds-button__icon',
+ `slds-icon-text-${iconVariant}`
+ );
+ }
+ );
+
+ it('applies inverse to the onClickTrigger link icon', () => {
+ renderDefaultTrigger({
+ iconVariant: 'inverse',
+ onClickTrigger: () => {},
+ });
+ const svg = screen.getByRole('link').querySelector('svg');
+
+ expect(svg).toHaveClass('slds-icon');
+ expect(svg).not.toHaveClass('slds-icon-text-default');
+ });
+
+ it('applies warning color to the onClickTrigger link icon', () => {
+ renderDefaultTrigger({
+ iconVariant: 'warning',
+ onClickTrigger: () => {},
+ });
+ const svg = screen.getByRole('link').querySelector('svg');
+
+ expect(svg).toHaveClass('slds-icon-text-warning');
+ expect(svg).not.toHaveClass('slds-icon-text-default');
+ });
+
+ it('does not change custom children', () => {
+ renderTooltip({ iconVariant: 'inverse' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
+
+ expect(trigger).not.toHaveClass('slds-button_icon-inverse');
+ });
+ });
+
describe('Keyboard navigation', () => {
it('shows tooltip on focus', async () => {
renderTooltip();
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
trigger.focus();
fireEvent.focus(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
});
});
it('hides tooltip on blur', async () => {
renderTooltip();
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
trigger.focus();
fireEvent.focus(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
});
trigger.blur();
fireEvent.blur(trigger, { relatedTarget: document.body });
- await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).not.toBeInTheDocument();
- }, { timeout: 200 });
+ await waitFor(
+ () => {
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).not.toBeInTheDocument();
+ },
+ { timeout: 200 }
+ );
});
it('closes tooltip on Escape key', async () => {
renderTooltip();
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
});
fireEvent.keyDown(trigger, { key: 'Escape' });
- await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).not.toBeInTheDocument();
- }, { timeout: 200 });
+ await waitFor(
+ () => {
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).not.toBeInTheDocument();
+ },
+ { timeout: 200 }
+ );
});
});
@@ -291,20 +444,29 @@ describe('SLDSTooltip', () => {
await userEvent.hover(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
});
});
});
describe('HasAnchoredNubbin', () => {
it('renders with anchored nubbin when enabled', async () => {
- const { container } = renderTooltip({ hasAnchoredNubbin: true, align: 'top' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const { container } = renderTooltip({
+ hasAnchoredNubbin: true,
+ align: 'top',
+ });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
await waitFor(() => {
- expect(document.querySelector('.slds-popover_tooltip')).toBeInTheDocument();
+ expect(
+ document.querySelector('.slds-popover_tooltip')
+ ).toBeInTheDocument();
// NOTE: Anchored nubbin is rendered via inline styles, check for style element
const styleElement = container.querySelector('style');
@@ -317,7 +479,9 @@ describe('SLDSTooltip', () => {
describe('DialogClassName prop', () => {
it('applies custom class to dialog', async () => {
renderTooltip({ dialogClassName: 'custom-tooltip-class' });
- const trigger = screen.getByRole('button', { name: 'Hover me for tooltip' });
+ const trigger = screen.getByRole('button', {
+ name: 'Hover me for tooltip',
+ });
await userEvent.hover(trigger);
@@ -330,7 +494,9 @@ describe('SLDSTooltip', () => {
describe('TriggerClassName prop', () => {
it('applies custom class to trigger wrapper', () => {
- const { container } = renderTooltip({ triggerClassName: 'custom-trigger-class' });
+ const { container } = renderTooltip({
+ triggerClassName: 'custom-trigger-class',
+ });
const triggerWrapper = container.querySelector('.slds-tooltip-trigger');
expect(triggerWrapper).toHaveClass('custom-trigger-class');
@@ -340,7 +506,7 @@ describe('SLDSTooltip', () => {
describe('TriggerStyle prop', () => {
it('applies custom styles to trigger wrapper', () => {
const { container } = renderTooltip({
- triggerStyle: { backgroundColor: 'rgb(255, 0, 0)' }
+ triggerStyle: { backgroundColor: 'rgb(255, 0, 0)' },
});
const triggerWrapper = container.querySelector('.slds-tooltip-trigger');
diff --git a/components/tooltip/index.tsx b/components/tooltip/index.tsx
index a539a792b..09dfd99e8 100644
--- a/components/tooltip/index.tsx
+++ b/components/tooltip/index.tsx
@@ -47,10 +47,13 @@ export type TooltipAlign =
| 'left top'
| 'left bottom';
-export type TooltipPosition = 'absolute' | 'overflowBoundaryElement' | 'relative';
+export type TooltipPosition =
+ 'absolute' | 'overflowBoundaryElement' | 'relative';
export type TooltipTheme = 'info' | 'error';
+export type TooltipIconVariant = 'bare' | 'error' | 'inverse' | 'warning';
+
export type TooltipVariant = 'base' | 'learnMore' | 'list-item';
export interface TooltipAssistiveText {
@@ -98,6 +101,14 @@ export interface TooltipProps {
* `hasStaticAlignment` disables this behavior.
*/
hasStaticAlignment?: boolean;
+ /**
+ * Styles the default info icon trigger that renders when no children are passed. Matches `icon-variant` on `lightning-helptext`.
+ * * `bare` - (default) Default icon color.
+ * * `error` - Red icon, to call out an error.
+ * * `inverse` - White icon, for dark backgrounds.
+ * * `warning` - Yellow icon, to advise caution.
+ */
+ iconVariant?: TooltipIconVariant;
/**
* Delay on Tooltip closing in milliseconds. Defaults to 50
*/
@@ -180,6 +191,7 @@ const Tooltip = ({
hasStaticAlignment = false,
hoverCloseDelay = 50,
hoverOpenDelay = 0,
+ iconVariant = 'bare',
id: idProp,
labels: labelsProp,
isOpen: isOpenProp,
@@ -211,27 +223,32 @@ const Tooltip = ({
// Check props in development
useEffect(() => {
- checkProps(POPOVER_TOOLTIP, {
- align,
- assistiveText,
- children,
- content,
- dialogClassName,
- hasAnchoredNubbin,
- hasStaticAlignment,
- hoverCloseDelay,
- hoverOpenDelay,
- id: idProp,
- labels,
- isOpen: isOpenProp,
- onRequestTargetElement,
- onClickTrigger,
- triggerClassName,
- position,
- triggerStyle,
- theme,
- variant,
- }, componentDoc);
+ checkProps(
+ POPOVER_TOOLTIP,
+ {
+ align,
+ assistiveText,
+ children,
+ content,
+ dialogClassName,
+ hasAnchoredNubbin,
+ hasStaticAlignment,
+ hoverCloseDelay,
+ hoverOpenDelay,
+ iconVariant,
+ id: idProp,
+ labels,
+ isOpen: isOpenProp,
+ onRequestTargetElement,
+ onClickTrigger,
+ triggerClassName,
+ position,
+ triggerStyle,
+ theme,
+ variant,
+ },
+ componentDoc
+ );
}, []);
// Cleanup on unmount
@@ -287,45 +304,56 @@ const Tooltip = ({
}, hoverOpenDelay);
}, [hoverOpenDelay]);
- const handleMouseLeave = useCallback((e: MouseEvent | FocusEvent) => {
- e.stopPropagation();
- if (tooltipTimeoutRef.current) {
- clearTimeout(tooltipTimeoutRef.current);
- }
-
- tooltipTimeoutRef.current = setTimeout(() => {
- const relatedTarget = (e as MouseEvent).relatedTarget as HTMLElement | null;
- const isHoveringTooltip =
- relatedTarget?.classList?.contains('slds-popover_tooltip') ||
- relatedTarget?.classList?.contains('slds-popover__body');
-
- if (!isUnmountingRef.current && !isHoveringTooltip) {
- setIsOpenState(false);
+ const handleMouseLeave = useCallback(
+ (e: MouseEvent | FocusEvent) => {
+ e.stopPropagation();
+ if (tooltipTimeoutRef.current) {
+ clearTimeout(tooltipTimeoutRef.current);
}
- }, hoverCloseDelay);
- }, [hoverCloseDelay]);
- const handleKeyDown = useCallback((e: KeyboardEvent) => {
- e.stopPropagation();
+ tooltipTimeoutRef.current = setTimeout(() => {
+ const relatedTarget = (e as MouseEvent)
+ .relatedTarget as HTMLElement | null;
+ const isHoveringTooltip =
+ relatedTarget?.classList?.contains('slds-popover_tooltip') ||
+ relatedTarget?.classList?.contains('slds-popover__body');
+
+ if (!isUnmountingRef.current && !isHoveringTooltip) {
+ setIsOpenState(false);
+ }
+ }, hoverCloseDelay);
+ },
+ [hoverCloseDelay]
+ );
- tooltipTimeoutRef.current = setTimeout(() => {
- if (!isUnmountingRef.current && e.key === 'Escape') {
- setIsOpenState(false);
- }
- }, hoverCloseDelay);
- }, [hoverCloseDelay]);
+ const handleKeyDown = useCallback(
+ (e: KeyboardEvent) => {
+ e.stopPropagation();
+
+ tooltipTimeoutRef.current = setTimeout(() => {
+ if (!isUnmountingRef.current && e.key === 'Escape') {
+ setIsOpenState(false);
+ }
+ }, hoverCloseDelay);
+ },
+ [hoverCloseDelay]
+ );
// Save trigger ref and trigger re-render once mounted
- const saveTriggerRef = useCallback((component: HTMLDivElement | null) => {
- if (component && triggerRef.current !== component) {
- (triggerRef as React.MutableRefObject).current = component;
- // Dialog/Popper.js cannot place the popover until
- // the trigger/target DOM node is mounted.
- if (!triggerRendered) {
- setTriggerRendered(true);
+ const saveTriggerRef = useCallback(
+ (component: HTMLDivElement | null) => {
+ if (component && triggerRef.current !== component) {
+ (triggerRef as React.MutableRefObject).current =
+ component;
+ // Dialog/Popper.js cannot place the popover until
+ // the trigger/target DOM node is mounted.
+ if (!triggerRendered) {
+ setTriggerRendered(true);
+ }
}
- }
- }, [triggerRendered]);
+ },
+ [triggerRendered]
+ );
// Render helpers
const getAnchoredNubbinStyles = () => {
@@ -333,7 +361,8 @@ const Tooltip = ({
return null;
}
- const alignment = align.split(' ')[0] as 'top' | 'bottom' | 'left' | 'right';
+ const alignment = align.split(' ')[0] as
+ 'top' | 'bottom' | 'left' | 'right';
const nubbinContainerStyles: CSSProperties = {
height: '0',
position: 'relative',
@@ -348,8 +377,12 @@ const Tooltip = ({
width: '1rem',
};
const triggerDimensions = {
- height: triggerRef.current ? triggerRef.current.getBoundingClientRect().height : 0,
- width: triggerRef.current ? triggerRef.current.getBoundingClientRect().width : 0,
+ height: triggerRef.current
+ ? triggerRef.current.getBoundingClientRect().height
+ : 0,
+ width: triggerRef.current
+ ? triggerRef.current.getBoundingClientRect().width
+ : 0,
};
switch (alignment) {
@@ -400,15 +433,26 @@ const Tooltip = ({
const getContent = () => {
let childrenToRender: ReactNode;
const noChildrenProvided = React.Children.count(children) === 0;
+ const isInverseIcon = iconVariant === 'inverse';
+ const iconColorVariant =
+ iconVariant === 'error' || iconVariant === 'warning'
+ ? iconVariant
+ : undefined;
if (noChildrenProvided && onClickTrigger) {
childrenToRender = (
}
+ onClick={
+ EventUtil.trappedHandler(
+ onClickTrigger
+ ) as React.MouseEventHandler
+ }
>
);
@@ -438,23 +488,26 @@ const Tooltip = ({
return child;
}
- return React.cloneElement(child as React.ReactElement<{
- key?: React.Key;
- 'aria-describedby'?: string;
- onBlur?: (e: FocusEvent) => void;
- onFocus?: () => void;
- onMouseEnter?: () => void;
- onMouseLeave?: (e: MouseEvent) => void;
- onKeyDown?: (e: KeyboardEvent) => void;
- }>, {
- key: i,
- 'aria-describedby': getIsOpen() ? getId() : undefined,
- onBlur: handleMouseLeave,
- onFocus: handleMouseEnter,
- onMouseEnter: handleMouseEnter,
- onMouseLeave: handleMouseLeave,
- onKeyDown: handleKeyDown,
- });
+ return React.cloneElement(
+ child as React.ReactElement<{
+ key?: React.Key;
+ 'aria-describedby'?: string;
+ onBlur?: (e: FocusEvent) => void;
+ onFocus?: () => void;
+ onMouseEnter?: () => void;
+ onMouseLeave?: (e: MouseEvent) => void;
+ onKeyDown?: (e: KeyboardEvent) => void;
+ }>,
+ {
+ key: i,
+ 'aria-describedby': getIsOpen() ? getId() : undefined,
+ onBlur: handleMouseLeave,
+ onFocus: handleMouseEnter,
+ onMouseEnter: handleMouseEnter,
+ onMouseLeave: handleMouseLeave,
+ onKeyDown: handleKeyDown,
+ }
+ );
});
};
@@ -462,9 +515,9 @@ const Tooltip = ({
// REMOVE AT NEXT BREAKING CHANGE (v1.0 or v0.9)
// Support deprecated 'error' variant value (now use theme='error')
const isErrorTheme = theme === 'error' || (variant as string) === 'error';
-
+
return (
-