Skip to content

Commit

Permalink
Merge pull request #996 from carloslancha/issue-995-tooltip
Browse files Browse the repository at this point in the history
 Fix tooltip position and allow tooltip mouseover | Fixes #995
  • Loading branch information
jbalsas authored Jun 12, 2018
2 parents a022a78 + 8543138 commit 84b1c00
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div class="tooltip clay-tooltip-bottom" role="tooltip"><div class="arrow"></div><div class="tooltip-inner">null</div></div>
<div class="tooltip fade clay-tooltip-bottom" data-onmouseenter="_handleMouseEnterTooltip" data-onmouseleave="_handleMouseLeave" role="tooltip"><div class="arrow"></div><div class="tooltip-inner">null</div></div>
183 changes: 141 additions & 42 deletions packages/clay-tooltip/src/ClayTooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,30 @@ class ClayTooltip extends Component {
this._eventHandler = new EventHandler();
}

/**
* @inheritDoc
*/
attached() {
this.addListener('transitionend', this._handleTransitionEnd, true);
}

/**
* @inheritDoc
*/
rendered() {
if (this._target) {
const alignedPosition = Align.align(
this.element,
this._target,
this.position
);

if (this.alignedPosition !== alignedPosition) {
this.alignedPosition = alignedPosition;
}
}
}

/**
* @inheritDoc
*/
Expand All @@ -73,70 +97,133 @@ class ClayTooltip extends Component {
}

/**
* Handles mouseenter events.
* Handles mouseenter event.
* @memberof ClayTooltip
* @param {Object} event The event object.
* @protected
* @param {!Element} element
* @return {!String}
* @private
*/
_handleMouseEnter(event) {
const target = event.delegateTarget;

const titleAttribute = target.getAttribute('title');
_getContent(element) {
const titleAttribute = element.getAttribute('title');

if (titleAttribute) {
target.setAttribute('data-title', titleAttribute);
target.setAttribute('data-restore-title', 'true');
target.removeAttribute('title');
} else if (target.tagName === 'svg') {
let titleTag = target.querySelector('title');
element.setAttribute('data-title', titleAttribute);
element.setAttribute('data-restore-title', 'true');
element.removeAttribute('title');
} else if (element.tagName === 'svg') {
let titleTag = element.querySelector('title');

if (titleTag) {
target.setAttribute('data-title', titleTag.innerHTML);
target.setAttribute('data-restore-title', 'true');
element.setAttribute('data-title', titleTag.innerHTML);
element.setAttribute('data-restore-title', 'true');
titleTag.remove();
}
}

this._content = target.getAttribute('data-title');
return element.getAttribute('data-title');
}

/**
* Handles click event.
* @memberof ClayTooltip
* @param {!Event} event
* @private
*/
_handleMouseClick(event) {
this._restoreTitle(event.delegateTarget);

this._isTransitioning = true;
this.visible = false;
}

/**
* Handles mouseenter event.
* @memberof ClayTooltip
* @param {!Event} event
* @private
*/
_handleMouseEnter(event) {
const content = this._getContent(event.delegateTarget);
this._target = event.delegateTarget;

this._content = content;

if (!this.visible) {
this.element.style.display = 'block';
}
this._isTransitioning = true;
this.visible = true;
}

this.alignedPosition = Align.align(this.element, target, this.position);
this._showTooltip = true;
/**
* Handles tooltip element mouseenter event.
* @memberof ClayTooltip
* @private
*/
_handleMouseEnterTooltip() {
if (this._isTransitioning) {
this.visible = true;
}
}

/**
* Handles mouseleave events.
* @memberof ClayTooltip
* @param {Object} event The event object.
* @protected
* @param {!Event} event
* @private
*/
_handleMouseLeave(event) {
const target = event.delegateTarget;
if (this.visible) {
this._restoreTitle(event.delegateTarget);

const title = target.getAttribute('data-title');
const restoreTitle = target.getAttribute('data-restore-title');
this._isTransitioning = true;
this.visible = false;
}
}

/**
* Handles transionend event.
* @memberof ClayTooltip
* @private
*/
_handleTransitionEnd() {
this._isTransitioning = false;

if (!this.visible) {
this.element.style.display = 'none';
}
}

/**
* Restores the title attribute to an element
* @memberof ClayTooltip
* @param {Element} element
* @private
*/
_restoreTitle(element) {
const title = element.getAttribute('data-title');
const restoreTitle = element.getAttribute('data-restore-title');

if (title && restoreTitle === 'true') {
if (target.tagName === 'svg') {
if (element.tagName === 'svg') {
let titleTag = document.createElement('title');
titleTag.innerHTML = title;

target.appendChild(titleTag);
element.appendChild(titleTag);
} else {
target.setAttribute('title', title);
element.setAttribute('title', title);
}

target.removeAttribute('data-restore-title');
element.removeAttribute('data-restore-title');
}

this._showTooltip = false;
}

/**
* The setter function for the `classMap` staet.
* @memberof ClayTooltip
* @param {Object} val
* @return {!Object}
* @protected
* @private
*/
setterClassMapFn_(val) {
return object.mixin(this.valueClassMapFn_(), val);
Expand All @@ -147,7 +234,7 @@ class ClayTooltip extends Component {
* @memberof ClayTooltip
* @param {Array.<string>} newValue The new value of `this.selectors`.
* @param {Array.<string>} prevValue The previous value of `this.selectors`.
* @protected
* @private
*/
syncSelectors(newValue, prevValue) {
if (newValue) {
Expand All @@ -170,6 +257,12 @@ class ClayTooltip extends Component {
selector,
this._handleMouseLeave.bind(this)
),
dom.delegate(
document,
'click',
selector,
this._handleMouseClick.bind(this)
),
dom.delegate(
document,
'focus',
Expand All @@ -193,10 +286,17 @@ class ClayTooltip extends Component {
}
}

/**
* @inheritDoc
*/
syncVisible() {
// This is needed to make fade transition work
}

/**
* Gets the default value for the `classMap` state.
* @return {!Object}
* @protected
* @private
*/
valueClassMapFn_() {
return {
Expand Down Expand Up @@ -229,17 +329,6 @@ ClayTooltip.STATE = {
.value('')
.internal(),

/**
* A flag indicating if the tooltip should be shown.
* @default false
* @instance
* @memberof ClayTooltip
* @type {boolean}
*/
_showTooltip: Config.bool()
.value(false)
.internal(),

/**
* The current position of the tooltip after being aligned via `Align.align`.
* @default undefined
Expand Down Expand Up @@ -293,6 +382,16 @@ ClayTooltip.STATE = {
* @type {!Array.<string>}
*/
selectors: Config.array().value(['[data-title]', '[title]']),

/**
* Tooltip visible when show is called.
* @default false
* @instance
* @memberof ClayTooltip
* @private
* @type {?bool}
*/
visible: Config.bool().value(false),
};

Soy.register(ClayTooltip, templates);
Expand Down
9 changes: 6 additions & 3 deletions packages/clay-tooltip/src/ClayTooltip.soy
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,31 @@
*/
{template .render}
{@param? _content: html|string}
{@param? _showTooltip: bool}
{@param? alignedPosition: number}
{@param? classMap: ?}
{@param? elementClasses: string}
{@param? position: number}
{@param? visible: bool}

{let $classes: $classMap ? $classMap : ['clay-tooltip-top-left', 'clay-tooltip-top', 'clay-tooltip-top-right', 'clay-tooltip-bottom-left', 'clay-tooltip-bottom', 'clay-tooltip-bottom-right', 'clay-tooltip-right', 'clay-tooltip-left'] /}
{let $currentPosition: $alignedPosition ?: $position /}
{let $positionClass: isNonnull($currentPosition) ? $classes[$currentPosition] : 'clay-tooltip-bottom' /}

{let $tooltipAttributes kind="attributes"}
class="tooltip
class="tooltip fade
{sp}{$positionClass}

{if $elementClasses}
{sp}{$elementClasses}
{/if}

{if $_showTooltip}
{if $visible}
{sp}show
{/if}
"

data-onmouseenter="_handleMouseEnterTooltip"
data-onmouseleave="_handleMouseLeave"
role="tooltip"
{/let}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ClayTooltip should allow setting selectors 1`] = `
<div class="tooltip clay-tooltip-bottom" role="tooltip">
<div class="tooltip fade clay-tooltip-bottom" role="tooltip">
<div class="arrow"></div>
<div class="tooltip-inner"></div>
</div>
`;

exports[`ClayTooltip should create a tooltip 1`] = `
<div class="tooltip clay-tooltip-bottom" role="tooltip">
<div class="tooltip fade clay-tooltip-bottom" role="tooltip">
<div class="arrow"></div>
<div class="tooltip-inner"></div>
</div>
Expand Down

0 comments on commit 84b1c00

Please sign in to comment.