Skip to content

Commit

Permalink
feat(tooltip): add tooltip visible class
Browse files Browse the repository at this point in the history
  • Loading branch information
emyarod committed Feb 18, 2020
1 parent e27c121 commit 32bab8c
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 10 deletions.
38 changes: 30 additions & 8 deletions packages/components/src/components/tooltip/tooltip--simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import debounce from 'lodash.debounce';
import settings from '../../globals/js/settings';
import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
Expand Down Expand Up @@ -32,30 +33,50 @@ export default class TooltipSimple extends mixin(
// ESC
if (event.which === 27) {
this.allowTooltipVisibility({ visible: false });
const tooltipTriggerButton = this.getTooltipTriggerButton();
if (tooltipTriggerButton) {
tooltipTriggerButton.classList.remove(
this.options.classTooltipVisible
);
}
}
})
);
this.manage(
on(this.element, 'mouseenter', () =>
this.allowTooltipVisibility({ visible: true })
)
on(this.element, 'mouseenter', () => {
this.tooltipFadeOut.cancel();
this.allowTooltipVisibility({ visible: true });
const tooltipTriggerButton = this.getTooltipTriggerButton();
if (tooltipTriggerButton) {
tooltipTriggerButton.classList.add(this.options.classTooltipVisible);
}
})
);
this.manage(on(this.element, 'mouseleave', this.tooltipFadeOut));
this.manage(
on(this.element, 'focus', event => {
on(this.element, 'focusin', event => {
if (eventMatches(event, this.options.selectorTriggerButton)) {
this.allowTooltipVisibility({ visible: true });
}
})
);
}

allowTooltipVisibility = ({ visible }) => {
const tooltipTriggerButton = this.element.matches(
this.options.selectorTriggerButton
)
tooltipFadeOut = debounce(() => {
const tooltipTriggerButton = this.getTooltipTriggerButton();
if (tooltipTriggerButton) {
tooltipTriggerButton.classList.remove(this.options.classTooltipVisible);
}
}, 100);

getTooltipTriggerButton = () =>
this.element.matches(this.options.selectorTriggerButton)
? this.element
: this.element.querySelector(this.options.selectorTriggerButton);

allowTooltipVisibility = ({ visible }) => {
const tooltipTriggerButton = this.getTooltipTriggerButton();

if (!tooltipTriggerButton) {
return;
}
Expand Down Expand Up @@ -83,6 +104,7 @@ export default class TooltipSimple extends mixin(
selectorInit: '[data-tooltip-definition],[data-tooltip-icon]',
selectorTriggerButton: `.${prefix}--tooltip__trigger.${prefix}--tooltip--a11y`,
classTooltipHidden: `${prefix}--tooltip--hidden`,
classTooltipVisible: `${prefix}--tooltip--visible`,
};
}

Expand Down
1 change: 1 addition & 0 deletions packages/components/src/globals/scss/_tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
content: none;
}

&.#{$prefix}--tooltip--visible,
&:hover,
&:focus {
&::before,
Expand Down
18 changes: 18 additions & 0 deletions packages/components/tests/spec/tooltip--simple_spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Promise, { delay } from 'bluebird';
import Tooltip from '../../src/components/tooltip/tooltip--simple';
import TooltipDefinitionHTML from '../../html/tooltip/tooltip--definition.html';
import TooltipIconHTML from '../../html/tooltip/tooltip--icon.html';
Expand Down Expand Up @@ -88,6 +89,23 @@ describe('Test simple tooltip', function() {
expect(element.classList.contains('bx--tooltip--hidden')).toBe(false);
});

it('Should have visible class after mouseenter', function() {
element.dispatchEvent(new CustomEvent('mouseenter', { bubbles: true }));
expect(element.classList.contains('bx--tooltip--visible')).toBe(true);
});

it('Should not have visible class after mouseleave', async function() {
await new Promise(resolve => {
resolve(
element.dispatchEvent(
new CustomEvent('mouseleave', { bubbles: true })
)
);
});
await delay(100);
expect(element.classList.contains('bx--tooltip--visible')).toBe(false);
});

it('Should not have hidden class after focus', function() {
element.dispatchEvent(new CustomEvent('focus', { bubbles: true }));
expect(element.classList.contains('bx--tooltip--hidden')).toBe(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import cx from 'classnames';
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { settings } from 'carbon-components';
import debounce from 'lodash.debounce';
import setupGetInstanceId from '../../tools/setupGetInstanceId';
import { composeEventHandlers } from '../../tools/events';
import { keys, matches } from '../../internal/keyboard';
Expand All @@ -24,10 +25,12 @@ const TooltipDefinition = ({
align,
onFocus,
onMouseEnter,
onMouseLeave,
tooltipText,
...rest
}) => {
const [allowTooltipVisibility, setAllowTooltipVisibility] = useState(true);
const [tooltipVisible, setTooltipVisible] = useState(false);
const tooltipId = id || `definition-tooltip-${getInstanceId()}`;
const tooltipClassName = cx(
`${prefix}--tooltip--definition`,
Expand All @@ -43,10 +46,17 @@ const TooltipDefinition = ({
[`${prefix}--tooltip--${direction}`]: direction,
[`${prefix}--tooltip--align-${align}`]: align,
[`${prefix}--tooltip--hidden`]: !allowTooltipVisibility,
[`${prefix}--tooltip--visible`]: tooltipVisible,
}
);
const debounceTooltipVisible = debounce(() => setTooltipVisible(false), 100);
const handleFocus = () => setAllowTooltipVisibility(true);
const handleMouseEnter = () => setAllowTooltipVisibility(true);
const handleMouseEnter = () => {
debounceTooltipVisible.cancel();
setAllowTooltipVisibility(true);
setTooltipVisible(true);
};
const handleMouseLeave = debounceTooltipVisible;
useEffect(() => {
const handleEscKeyDown = event => {
if (matches(event, [keys.Escape])) {
Expand All @@ -61,7 +71,8 @@ const TooltipDefinition = ({
<div
{...rest}
className={tooltipClassName}
onMouseEnter={composeEventHandlers([onMouseEnter, handleMouseEnter])}>
onMouseEnter={composeEventHandlers([onMouseEnter, handleMouseEnter])}
onMouseLeave={composeEventHandlers([onMouseLeave, handleMouseLeave])}>
<button
className={tooltipTriggerClasses}
aria-describedby={tooltipId}
Expand Down

0 comments on commit 32bab8c

Please sign in to comment.