Upgrade gr-dropdown with additional capabilities

The shared dropdown component is made more-configurable, so it can be
reused in more contexts.
* The down-arrow is an flag that can be enabled on the dropdown, instead
  of added (and styled) at the use site.
* Items no longer need to be links to new URLs. They can be buttons with
  declared handlers.
* The dropdown trigger can be a link or a button, as configured by the
  link flag.

Change-Id: Ia9db3b66bf30bc56bf2ab4ce1f2292f51ab4754d
This commit is contained in:
Wyatt Allen
2017-01-24 10:49:28 -08:00
parent 8f5b9aa08a
commit bda4683444
6 changed files with 82 additions and 24 deletions

View File

@@ -34,7 +34,10 @@ limitations under the License.
vertical-align: middle; vertical-align: middle;
} }
</style> </style>
<gr-dropdown items=[[links]] top-content=[[topContent]] <gr-dropdown
link
items=[[links]]
top-content=[[topContent]]
horizontal-align="right"> horizontal-align="right">
<span hidden$="[[_hasAvatars]]" hidden>[[account.name]]</span> <span hidden$="[[_hasAvatars]]" hidden>[[account.name]]</span>
<gr-avatar account="[[account]]" hidden$="[[!_hasAvatars]]" hidden <gr-avatar account="[[account]]" hidden$="[[!_hasAvatars]]" hidden

View File

@@ -52,23 +52,8 @@ limitations under the License.
.linksTitle { .linksTitle {
color: black; color: black;
display: inline-block; display: inline-block;
padding-right: 1em;
position: relative; position: relative;
} }
.downArrow {
border-left: .36em solid transparent;
border-right: .36em solid transparent;
border-top: .36em solid #ccc;
height: 0;
position: absolute;
right: 0;
top: calc(50% - .05em);
transition: border-top-color 200ms;
width: 0;
}
.links li:hover .downArrow {
border-top-color: #666;
}
.rightItems { .rightItems {
align-items: center; align-items: center;
display: flex; display: flex;
@@ -119,10 +104,12 @@ limitations under the License.
<template is="dom-repeat" items="[[_links]]" as="linkGroup"> <template is="dom-repeat" items="[[_links]]" as="linkGroup">
<li> <li>
<gr-dropdown <gr-dropdown
link
down-arrow
items = [[linkGroup.links]] items = [[linkGroup.links]]
horizontal-align="left"> horizontal-align="left">
<span class="linksTitle" id="[[linkGroup.title]]"> <span class="linksTitle" id="[[linkGroup.title]]">
[[linkGroup.title]] <i class="downArrow"></i> [[linkGroup.title]]
</span> </span>
</gr-dropdown> </gr-dropdown>
</li> </li>

View File

@@ -18,6 +18,10 @@
is: 'gr-button', is: 'gr-button',
properties: { properties: {
link: {
type: Boolean,
reflectToAttribute: true,
},
disabled: { disabled: {
type: Boolean, type: Boolean,
observer: '_disabledChanged', observer: '_disabledChanged',

View File

@@ -38,6 +38,9 @@ limitations under the License.
font: inherit; font: inherit;
padding: .3em 0; padding: .3em 0;
} }
:host[down-arrow] .dropdown-trigger {
padding-right: 1.4em;
}
gr-avatar { gr-avatar {
height: 2em; height: 2em;
width: 2em; width: 2em;
@@ -58,16 +61,17 @@ limitations under the License.
font-weight: bold; font-weight: bold;
} }
li .accountInfo, li .accountInfo,
li a { li .itemAction {
cursor: pointer;
display: block; display: block;
padding: .85em 1em; padding: .85em 1em;
} }
li a:link, li .itemAction:link,
li a:visited { li .itemAction:visited {
color: #00e; color: #00e;
text-decoration: none; text-decoration: none;
} }
li a:hover { li .itemAction:hover {
background-color: #6B82D6; background-color: #6B82D6;
color: #fff; color: #fff;
} }
@@ -78,14 +82,30 @@ limitations under the License.
.bold-text { .bold-text {
font-weight: bold; font-weight: bold;
} }
:host:not([down-arrow]) .downArrow { display: none; }
:host[down-arrow] .downArrow {
border-left: .36em solid transparent;
border-right: .36em solid transparent;
border-top: .36em solid #ccc;
height: 0;
position: absolute;
right: .3em;
top: calc(50% - .05em);
transition: border-top-color 200ms;
width: 0;
}
.dropdown-trigger:hover .downArrow {
border-top-color: #666;
}
</style> </style>
<gr-button link class="dropdown-trigger" id="trigger" <gr-button link="[[link]]" class="dropdown-trigger" id="trigger"
on-tap="_showDropdownTapHandler"> on-tap="_showDropdownTapHandler">
<content></content> <content></content>
<i class="downArrow"></i>
</gr-button> </gr-button>
<iron-dropdown id="dropdown" <iron-dropdown id="dropdown"
vertical-align="top" vertical-align="top"
vertical-offset="40" vertical-offset="[[verticalOffset]]"
allow-outside-scroll="true" allow-outside-scroll="true"
horizontal-align="[[horizontalAlign]]" horizontal-align="[[horizontalAlign]]"
on-tap="_handleDropdownTap"> on-tap="_handleDropdownTap">
@@ -109,7 +129,16 @@ limitations under the License.
items="[[items]]" items="[[items]]"
as="link" as="link"
initial-count="75"> initial-count="75">
<li><a href$="[[_computeRelativeURL(link.url)]]">[[link.name]]</a> <li>
<span
class="itemAction"
data-id$="[[link.id]]"
on-tap="_handleItemTap"
hidden$="[[link.url]]">[[link.name]]</span>
<a
class="itemAction"
href$="[[_computeRelativeURL(link.url)]]"
hidden$="[[!link.url]]">[[link.name]]</a>
</li> </li>
</template> </template>
</ul> </ul>

View File

@@ -17,6 +17,12 @@
Polymer({ Polymer({
is: 'gr-dropdown', is: 'gr-dropdown',
/**
* Fired when a non-link dropdown item with the given ID is tapped.
*
* @event tap-item-<id>
*/
properties: { properties: {
items: Array, items: Array,
topContent: Object, topContent: Object,
@@ -24,6 +30,20 @@
type: String, type: String,
value: 'left', value: 'left',
}, },
/**
* Style the dropdown trigger as a link (rather than a button).
*/
link: {
type: Boolean,
value: false,
},
verticalOffset: {
type: Number,
value: 40,
},
_hasAvatars: String, _hasAvatars: String,
}, },
@@ -53,5 +73,10 @@
var host = window.location.host; var host = window.location.host;
return this._computeURLHelper(host, path); return this._computeURLHelper(host, path);
}, },
_handleItemTap: function(e) {
var id = e.target.getAttribute('data-id');
if (id) { this.dispatchEvent(new CustomEvent('tap-item-' + id)); }
},
}); });
})(); })();

View File

@@ -70,5 +70,15 @@ limitations under the License.
assert.isTrue(topItems[0].classList.contains('bold-text')); assert.isTrue(topItems[0].classList.contains('bold-text'));
assert.isFalse(topItems[1].classList.contains('bold-text')); assert.isFalse(topItems[1].classList.contains('bold-text'));
}); });
test('non link items', function() {
element.items = [
{name: 'item one', id: 'foo'}, {name: 'item two', id: 'bar'}];
var stub = sinon.stub();
element.addEventListener('tap-item-foo', stub);
flushAsynchronousOperations();
MockInteractions.tap(element.$$('.itemAction'));
assert.isTrue(stub.called);
});
}); });
</script> </script>