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:
@@ -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
|
||||||
|
@@ -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>
|
||||||
|
@@ -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',
|
||||||
|
@@ -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>
|
||||||
|
@@ -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)); }
|
||||||
|
},
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user