-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(top-app-bar): Add top app bar component #2225
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2225 +/- ##
=========================================
Coverage ? 98.73%
=========================================
Files ? 96
Lines ? 3943
Branches ? 508
=========================================
Hits ? 3893
Misses ? 50
Partials ? 0
Continue to review full report at Codecov.
|
254d145
to
8829dc3
Compare
demos/index.html
Outdated
@@ -215,6 +215,14 @@ | |||
</span> | |||
</a> | |||
|
|||
<a href="top-app-bar.html" role="listitem" class="mdc-list-item"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p comes after o, so this should be after Toolbar if we're being consistent with alpha order.
OTOH I talked with Will about potential for confusion by adding this alongside toolbar before there are features implemented that differentiate it (and before we eventually relegate the toolbar package for different functionality...) and maybe we just shouldn't add this to the demo page until the distinguishing features are added? (So maybe we shouldn't add front-matter to the readme for the site yet either.)
@@ -0,0 +1,18 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have package-lock.json within any of our other packages folders, so I don't think this needs to be committed? (Or we should commit them across the board at some point later, but i.e. I don't think they get generated when doing npm install from the top-level which is usually all we need to do for development.)
demos/top-app-bar.scss
Outdated
} | ||
} | ||
|
||
.demo-controls-container { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see this used anywhere?
package-lock.json
Outdated
@@ -2,6 +2,16 @@ | |||
"requires": true, | |||
"lockfileVersion": 1, | |||
"dependencies": { | |||
"JSONStream": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these changes seem to just reorder things, so I'm not sure this is needed in this PR?
@@ -151,6 +151,7 @@ | |||
"text-field", | |||
"theme", | |||
"toolbar", | |||
"top-app-bar", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about closure whitelist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toolbar doesn't currently exist in closure whitelist, so I didn't add this one either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think any component we are writing from scratch should aim to be in the whitelist at the get-go at this point, because it's easier to deal with incrementally than having to come back through and clean up later.
packages/mdc-top-app-bar/README.md
Outdated
`mdc-top-app-bar-ink-color($color)` | Sets the ink color of the top app bar | ||
`mdc-top-app-bar-fill-color($color)` | Sets the fill color of the top app bar | ||
`mdc-top-app-bar-fill-color-accessible($color)` | Sets the fill color of the top app bar and automatically sets a high-contrast ink color | ||
`mdc-top-app-bar-icon-ink-color($color)` | Sets the ink color of a top app bar icon |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"of top app bar icons"?
@mixin mdc-top-app-bar-icon-ink-color($color) { | ||
.mdc-top-app-bar__icon, | ||
.mdc-top-app-bar__menu-icon { | ||
@include mdc-theme-prop(color, $color); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would leave mdc-states
out of the private mixin, and include it here and pass $color
. (Edit: this was done)
packages/mdc-top-app-bar/adapter.js
Outdated
/* eslint no-unused-vars: [2, {"args": "none"}] */ | ||
|
||
/** | ||
* Adapter for MDC Top App Bar . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove space before period
packages/mdc-top-app-bar/adapter.js
Outdated
removeClass(className) {} | ||
|
||
/** | ||
* Returns true if the root element contains the given class name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capitalize Element to be consistent with above, or lowercase it everywhere?
*/ | ||
static get defaultAdapter() { | ||
return /** @type {!MDCTopAppBarAdapter} */ { | ||
hasClass: (/* className: string */) => /* boolean */ false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure this should be {}
on the RHS, as in, it's an empty function (not a return value).
I realize we seem to be 50/50 on this throughout the repo currently but I'm inclined to think it's a mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was copied from the toolbar.
To explain what's going on here in case anyone's wondering, we're planning on reorganizing toolbar into common logic + specializations. Since mdc-toolbar was originally created primarily with scenarios for top app bars in mind, it's likely that some functionality currently present in mdc-toolbar will eventually manifest here and be removed from the mdc-toolbar package. |
be4a5db
to
5b47a3f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI I found a bug: It seems like everything in the top app bar is vertically misaligned too low in Firefox, Edge, and IE.
demos/top-app-bar.html
Outdated
</div> | ||
</main> | ||
|
||
<script src="/assets/material-components-web.js" async></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Load /assets/common.js above this line, to automatically get preventDefault on a
elements (to avoid the browser navigating to #)
packages/mdc-top-app-bar/README.md
Outdated
section: components | ||
excerpt: "A container for multiple rows of items such as application title, navigation menu, or tabs." | ||
iconId: toolbar | ||
path: /catalog/topappbar/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're adding this front-matter now, I would hyphenate top-app-bar here just like the package name.
packages/mdc-top-app-bar/README.md
Outdated
@@ -0,0 +1,112 @@ | |||
<!--docs: | |||
title: "Toolbars" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update title if we're adding this front-matter now
packages/mdc-top-app-bar/README.md
Outdated
|
||
# Top App Bar | ||
|
||
MDC Top App Bar acts as a container for items such as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: the line wrapping here seems weird
```html | ||
<header class="mdc-top-app-bar"> | ||
<div class="mdc-top-app-bar__row"> | ||
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity... does design have more semantic names we should be using for the align-start and align-end sections? Or are they general-purpose enough that there's no name that would fit all cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think designers know we split the toolbar into two sides so we can show some things on the left and some things on the right. I'll get with the designer to see if they have any input bit it seems like this was named by a developer smashing together align-items
and flex-start
. Which makes sense for developers to use.
} | ||
|
||
&__icon, | ||
&__menu-icon { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for grouping these two together to reduce CSS output <3
packages/mdc-top-app-bar/adapter.js
Outdated
removeClass(className) {} | ||
|
||
/** | ||
* Returns true if the root Element contains the given class name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We say just "class" in the other two descriptions but "class name" here (and "className" in the readme)... should we just reduce this description to class as well?
packages/mdc-top-app-bar/index.js
Outdated
const icons = [].slice.call(this.root_.querySelectorAll(strings.ACTION_ICON_SELECTOR)); | ||
icons.push(this.navIcon_); | ||
|
||
this.iconRipples_ = icons.map(function(icon) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use fat arrow here and in the forEach below
packages/mdc-top-app-bar/index.js
Outdated
this.navIconClick_ = this.navigationEvent_.bind(this); | ||
|
||
if (this.navIcon_) { | ||
this.navIcon_.addEventListener('click', this.navIconClick_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This much logic should not be in the component. This should be hooked up through the foundation with [de]registerInteractionHandler APIs.
Look at textfield/icon for example (not saying this has to be a subcomponent, but that shows an example of hooking up icon interaction + event emit through the foundation and that's almost the only thing that one does).
], | ||
"dependencies": { | ||
"@material/base": "^0.29.0", | ||
"@material/elevation": "^0.28.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we're planning to use this later? It's not currently used, seemingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is a remnant of my prototype.
demos/top-app-bar.scss
Outdated
padding: 20px 28px; | ||
} | ||
|
||
@media (max-width: 599px) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference $mdc-top-app-bar-mobile-breakpoint
?
// limitations under the License. | ||
// | ||
|
||
@import "@material/elevation/mixins"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I flagged this in package.json earlier, and since we removed it there, we should remove it here to avoid breaking things.
demos/top-app-bar.scss
Outdated
@import "../packages/mdc-button/mdc-button"; | ||
@import "../packages/mdc-list/mdc-list"; | ||
@import "../packages/mdc-menu/mdc-menu"; | ||
@import "../packages/mdc-theme/color-palette"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import?
// limitations under the License. | ||
// | ||
|
||
@import "@material/theme/variables"; // for mdc-theme-accessible-ink-color |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically missing theme/mixins for mdc-theme-prop?
|
||
@import "@material/elevation/mixins"; | ||
@import "@material/rtl/mixins"; | ||
@import "@material/theme/mixins"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think theme/mixins is needed in this file? (I commented about it being missing in the mixins file though.)
test('#init calls component event registrations', () => { | ||
const {foundation} = setupTest(); | ||
|
||
foundation.init(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't testing anything? Should this be mocking adapter#registerNavigationInteractionHandler
?
There's also no reciprocal test for #destroy
and deregister
.
foundation.init(); | ||
}); | ||
|
||
test('foundation returns strings', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not combine this with the "exports strings" test? e.g.
assert.deepEqual(MDCCheckboxFoundation.strings, strings); |
|
||
let click; | ||
|
||
td.when(mockAdapter.registerNavigationIconInteractionHandler('click', td.matchers.isA(Function))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might be able to use captureHandlers
in test/unit/helpers/foundation.js
to help with this.
See e.g. how ripple uses it:
const handlers = captureHandlers(adapter, 'registerInteractionHandler'); |
test('adapter#hasClass returns true if the root element has specified class', () => { | ||
const {root, component} = setupTest(); | ||
root.classList.add('foo'); | ||
assert.isOk(component.getDefaultFoundation().adapter_.hasClass('foo')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I know we do this a bunch of places, but I'd advocate using isTrue
and isFalse
specifically given that the API is supposed to return a boolean.
@@ -0,0 +1,104 @@ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove leading newline?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Goldens and css-bundle-factory
LGTM!
b7dcacf
to
ca70eb4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm noticing that in seemingly every browser except chrome, the ripples are not positioned/sized correctly. This might be a case of missing position: relative
on the surface, which we've run into before (and I should really look at the techdebt issue of centralizing...).
demos/top-app-bar.html
Outdated
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link rel="icon" type="image/png" href="/images/logo_components_color_2x_web_48dp.png"> | ||
<link rel="stylesheet" href="/assets/top-app-bar.css"> | ||
<link rel="stylesheet" href="/assets/drawer/drawer.css"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how I feel about this vs. importing mdc-drawer in the top-app-bar demo scss. Including this instead also picks up a bunch of demo styles specific to the drawer page that aren't being used here.
demos/top-app-bar.html
Outdated
</div> | ||
</header> | ||
|
||
<aside class="mdc-drawer mdc-drawer--temporary demo-drawer"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the demo-drawer
and demo-drawer-list-item
classes are being styled at all in this demo page.
demos/top-app-bar.html
Outdated
<script src="/assets/material-components-web.js" async></script> | ||
<script type="text/javascript"> | ||
demoReady(function() { | ||
var appBarElement = document.getElementById('demo-top-app-bar'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Shorten to appBarEl
to match drawerEl
?
packages/mdc-top-app-bar/README.md
Outdated
`removeClass(className: string) => void` | Removes a class from the root element of the component. | ||
`registerNavigationIconInteractionHandler(evtType: string, handler: EventListener) => void` | Registers an event listener on the native navigation icon element for a given event. | ||
`deregisterNavigationIconInteractionHandler(evtType: string, handler: EventListener) => void` | Deregisters an event listener on the native navigation icon element for a given event. | ||
`notifyNavigationIconClicked() => void` | Emits a custom event "MDCTopAppBar:nav" when the navigation icon is clicked. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: switch from quotes to backticks around the custom event name
7875c6e
to
34735fe
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI we currently have no tests for the top-app-bar component's destroy logic (to iterate and destroy ripples), but that might require adding a factory argument along the lines of what textfield/index.js does. I commented on a couple of other things we can probably test more easily to increase coverage.
packages/mdc-top-app-bar/README.md
Outdated
|
||
Event Name | Event Data Structure | Description | ||
--- | --- | --- | ||
`MDCTopAppBar:nav` | None | Emits when the menu icon is clicked. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: we say "navigation icon" a few lines up, but "menu icon" here... is there one right word for it?
/** @enum {string} */ | ||
const strings = { | ||
NAVIGATION_EVENT: 'MDCTopAppBar:nav', | ||
TITLE_SELECTOR: '.mdc-top-app-bar__title', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used (or will it be)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be used in the next PR. It won't hurt to leave it in for now.
assert.isFalse(root.classList.contains('foo')); | ||
}); | ||
|
||
test('#adapter.registerNavigationIconInteractionHandler adds a handler to the nav icon ' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How hard would it be to add tests to verify that no handler gets registered if there is no navigation icon? Currently the implicit "else" branch isn't covered in the register/deregister logic.
return {root, adjust, component, icon}; | ||
} | ||
|
||
class FakeRipple { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this above setupTest? It's jarring to see things defined after they're used.
} | ||
|
||
suite('MDCTopAppBar'); | ||
|
||
test('attachTo initializes and returns an MDCTopAppBar instance', () => { | ||
test('initialize and returns an MDCTopAppBar instance', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this test name rephrased? It still does the same thing (and now it's grammatically incorrect).
assert.isTrue(MDCTopAppBar.attachTo(getFixture()) instanceof MDCTopAppBar); | ||
}); | ||
|
||
test('constructor instantiates icon ripples', () => { | ||
const {root, component} = setupTest(); | ||
const icons = root.querySelectorAll('.mdc-top-app-bar__icon').length + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this reuse the two *_ICON_SELECTOR
constants together in one selector and forego the +1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM provided that CI passes
refs: #2222