Skip to content

Commit

Permalink
feat(tooltip): add support for hoverable definition tooltip body (#5323)
Browse files Browse the repository at this point in the history
  • Loading branch information
emyarod authored Feb 25, 2020
1 parent 7599426 commit 550bc70
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
class="{{@root.prefix}}--tooltip__trigger {{@root.prefix}}--tooltip--a11y {{@root.prefix}}--tooltip__trigger--definition {{@root.prefix}}--tooltip--bottom {{@root.prefix}}--tooltip--align-start">
Definition Tooltip (start aligned)
</button>
<div class="bx--assistive-text" id="example-start" role="tooltip">Brief description of the dotted, underlined word
<div class="{{@root.prefix}}--assistive-text" id="example-start" role="tooltip">Brief description of the dotted,
underlined word
above.</div>
</div>
<br>
Expand All @@ -19,7 +20,8 @@
class="{{@root.prefix}}--tooltip__trigger {{@root.prefix}}--tooltip--a11y {{@root.prefix}}--tooltip__trigger--definition {{@root.prefix}}--tooltip--bottom {{@root.prefix}}--tooltip--align-center">
Definition Tooltip (center aligned)
</button>
<div class="bx--assistive-text" id="example-center" role="tooltip">Brief description of the dotted, underlined word
<div class="{{@root.prefix}}--assistive-text" id="example-center" role="tooltip">Brief description of the dotted,
underlined word
above.</div>
</div>
<br>
Expand All @@ -28,6 +30,7 @@
class="{{@root.prefix}}--tooltip__trigger {{@root.prefix}}--tooltip--a11y {{@root.prefix}}--tooltip__trigger--definition {{@root.prefix}}--tooltip--bottom {{@root.prefix}}--tooltip--align-end">
Definition Tooltip (end aligned)
</button>
<div class="bx--assistive-text" id="example-end" role="tooltip">Brief description of the dotted, underlined word
<div class="{{@root.prefix}}--assistive-text" id="example-end" role="tooltip">Brief description of the dotted,
underlined word
above.</div>
</div>
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
3 changes: 1 addition & 2 deletions packages/components/src/globals/scss/_tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
font-weight: 400;
text-align: left;
transform: translateX(-50%);
pointer-events: none;
background-color: $inverse-02;
@include type-style('body-short-01');

Expand Down Expand Up @@ -97,7 +96,6 @@
display: flex;
align-items: center;
opacity: 0;
pointer-events: none;

// IE media query
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
Expand Down Expand Up @@ -150,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
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ exports[`TooltipDefinition should allow the user to specify the direction 1`] =
<div
className="bx--tooltip--definition bx--tooltip--a11y custom-class"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
<button
aria-describedby="definition-tooltip-3"
Expand Down Expand Up @@ -39,6 +40,7 @@ exports[`TooltipDefinition should render 1`] = `
<div
className="bx--tooltip--definition bx--tooltip--a11y custom-class"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
<button
aria-describedby="definition-tooltip-1"
Expand Down Expand Up @@ -69,6 +71,7 @@ exports[`TooltipDefinition should support a custom trigger element class 1`] = `
<div
className="bx--tooltip--definition bx--tooltip--a11y custom-class"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
<button
aria-describedby="definition-tooltip-2"
Expand Down

0 comments on commit 550bc70

Please sign in to comment.