Update tooltip behavior to support bottom tooltips

Account statuses will have tooltips that are really close to the top of
the page. In order to ensure their content doesn't get cut off, we will
use a bottom tooltip instead.

This change modifies the tooltip element to support an optional
positionBottom property. If the property does not exist, the tooltip is
positioned to the top, as it was before.

Change-Id: Iaa66b9edeebf4eb40cd20e897e59388bc9c0f70c
This commit is contained in:
Becky Siegel
2017-10-25 15:01:46 -07:00
parent d8f57da28e
commit 84912bf1ef
8 changed files with 77 additions and 7 deletions

View File

@@ -26,6 +26,11 @@
type: Boolean,
observer: '_setupTooltipListeners',
},
positionBelow: {
type: Boolean,
value: false,
reflectToAttribute: true,
},
_isTouchDevice: {
type: Boolean,
@@ -73,6 +78,7 @@
const tooltip = document.createElement('gr-tooltip');
tooltip.text = this._titleText;
tooltip.maxWidth = this.getAttribute('max-width');
tooltip.positionBelow = this.getAttribute('position-below');
// Set visibility to hidden before appending to the DOM so that
// calculations can be made based on the elements size.
@@ -125,9 +131,14 @@
});
}
tooltip.style.left = Math.max(0, left) + 'px';
tooltip.style.top = Math.max(0, top) + 'px';
tooltip.style.transform = 'translateY(calc(-100% - ' + BOTTOM_OFFSET +
'px))';
if (!this.positionBelow) {
tooltip.style.top = Math.max(0, top) + 'px';
tooltip.style.transform = 'translateY(calc(-100% - ' + BOTTOM_OFFSET +
'px))';
} else {
tooltip.style.top = top + rect.height + BOTTOM_OFFSET + 'px';
}
},
};
})(window);

View File

@@ -111,6 +111,24 @@ limitations under the License.
assert.equal(tooltip.style.top, '100px');
});
test('position to bottom', () => {
sandbox.stub(element, 'getBoundingClientRect', () => {
return {top: 100, left: 950, width: 50, height: 50};
});
const tooltip = makeTooltip(
{height: 30, width: 120},
{top: 0, left: 0, width: 1000});
element.positionBelow = true;
element._positionTooltip(tooltip);
assert.isTrue(tooltip.updateStyles.called);
const offset = tooltip.updateStyles
.lastCall.args[0]['--gr-tooltip-arrow-center-offset'];
assert.isAbove(parseFloat(offset.replace(/px$/, '')), 0);
assert.equal(tooltip.style.left, '915px');
assert.equal(tooltip.style.top, '157.2px');
});
test('hides tooltip when detached', () => {
sandbox.stub(element, '_handleHideTooltip');
element.remove();

View File

@@ -53,7 +53,7 @@ limitations under the License.
</style>
<gr-tooltip-content
has-tooltip
position-bottom
position-below
title="[[tooltipText]]"
max-width="40em">
<div class="chip" aria-label$="Label: [[status]]">

View File

@@ -26,6 +26,11 @@
type: String,
reflectToAttribute: true,
},
positionBelow: {
type: Boolean,
valye: false,
reflectToAttribute: true,
},
showIcon: {
type: Boolean,
value: false,

View File

@@ -43,6 +43,12 @@ limitations under the License.
.querySelector('.arrow').hidden, true);
});
test('position-below attribute is reflected', () => {
assert.isFalse(element.hasAttribute('position-below'));
element.positionBelow = true;
assert.isTrue(element.hasAttribute('position-below'));
});
test('icon is visible with showIcon property', () => {
element.showIcon = true;
assert.equal(Polymer.dom(element.root)

View File

@@ -35,21 +35,35 @@ limitations under the License.
:host .tooltip {
padding: .5em .85em;
}
:host .arrowPositionBelow,
:host([position-below]) .arrowPositionAbove {
display: none;
}
:host([position-below]) .arrowPositionBelow {
display: initial;
}
.arrow {
border-left: var(--gr-tooltip-arrow-size) solid transparent;
border-right: var(--gr-tooltip-arrow-size) solid transparent;
border-top: var(--gr-tooltip-arrow-size) solid #333;
bottom: -var(--gr-tooltip-arrow-size);
height: 0;
position: absolute;
left: calc(50% - var(--gr-tooltip-arrow-size));
margin-left: var(--gr-tooltip-arrow-center-offset);
width: 0;
}
.arrowPositionAbove {
border-top: var(--gr-tooltip-arrow-size) solid #333;
bottom: -var(--gr-tooltip-arrow-size);
}
.arrowPositionBelow {
border-bottom: var(--gr-tooltip-arrow-size) solid #333;
top: -var(--gr-tooltip-arrow-size);
}
</style>
<div class="tooltip">
<i class="arrowPositionBelow arrow"></i>
[[text]]
<i class="arrow"></i>
<i class="arrowPositionAbove arrow"></i>
</div>
</template>
<script src="gr-tooltip.js"></script>

View File

@@ -23,6 +23,10 @@
type: String,
observer: '_updateWidth',
},
positionBelow: {
type: Boolean,
reflectToAttribute: true,
},
},
_updateWidth(maxWidth) {

View File

@@ -44,5 +44,17 @@ limitations under the License.
element.maxWidth = '50px';
assert.equal(getComputedStyle(element).width, '50px');
});
test('the correct arrow is displayed', () => {
assert.equal(getComputedStyle(element.$$('.arrowPositionBelow')).display,
'none');
assert.notEqual(getComputedStyle(element.$$('.arrowPositionAbove'))
.display, 'none');
element.positionBelow = true;
assert.notEqual(getComputedStyle(element.$$('.arrowPositionBelow'))
.display, 'none');
assert.equal(getComputedStyle(element.$$('.arrowPositionAbove'))
.display, 'none');
});
});
</script>