Skip to content
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(drawer): Implement persistent drawer #488

Merged
merged 20 commits into from
Apr 12, 2017
Merged

Conversation

lynnmercier
Copy link
Contributor

Resolves #15, Implement persistent drawer by re-using the "slidable" logic from temporary drawer.

@codecov-io
Copy link

codecov-io commented Apr 6, 2017

Codecov Report

Merging #488 into master will decrease coverage by 0.03%.
The diff coverage is 97.9%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #488      +/-   ##
==========================================
- Coverage   99.05%   99.02%   -0.04%     
==========================================
  Files          44       45       +1     
  Lines        2016     2050      +34     
  Branches      249      251       +2     
==========================================
+ Hits         1997     2030      +33     
- Misses         19       20       +1
Impacted Files Coverage Δ
packages/mdc-drawer/temporary/constants.js 100% <ø> (ø) ⬆️
packages/mdc-drawer/temporary/index.js 97.29% <ø> (ø) ⬆️
packages/mdc-drawer/slidable/constants.js 100% <100%> (ø) ⬆️
packages/mdc-drawer/persistent/constants.js 100% <100%> (ø) ⬆️
packages/mdc-drawer/persistent/foundation.js 100% <100%> (ø) ⬆️
packages/mdc-drawer/temporary/foundation.js 100% <100%> (ø) ⬆️
packages/mdc-drawer/persistent/index.js 97.05% <97.05%> (ø)
packages/mdc-drawer/slidable/foundation.js 97.69% <97.69%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update daf17d5...e8b723e. Read the comment docs.

@traviskaufman
Copy link
Contributor

Looks like the coverage diff is failing. Once that's fixed I'll review!

Copy link
Contributor

@traviskaufman traviskaufman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really excellent work here! And thank you especially for taking the time to refactor out the common logic between temp and persistent drawers. Besides the inline comments, a few general comments:

  • I'd add a very simple README inside of the slidable dir denoting its purpose and intent to be used only as a base class for our own drawers, not for public API use. This will make it clear to contributors and users what its purpose is without digging through our code.

  • It doesn't look like the main README has been updated with any usage docs around persistent drawers. This info needs to be added to the README, along with the adapter API table which is required for all components. One note here is that the adapter API should outline all methods needed for the SlidableDrawer adapter as well, as if it were just one object. This denotes how using a slidable drawer base class is purely an implementation detail on our end, and has no effect on how adapters are shaped and passed to the foundation from a client code POV.


import {focusableElements} from '../slidable';

const ROOT = 'mdc-persistent-drawer';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we have this littered throughout our codebase already, but we actually need to ensure moving forward that these are all static strings so that they interop with closure stylesheet's renaming of css classes / strings the correct way.

export const cssClasses = {
  ROOT: 'mdc-persistent-drawer',
  OPEN: 'mdc-persistent-drawer--open',
  ANIMATING: 'mdc-persistent-drawer--animating',
};

export const strings = {
  DRAWER_SELECTOR: '.mdc-persistent-drawer__drawer',
  FOCUSABLE_ELEMENTS: focusableElements,
};

Our bad 😐

}

static get defaultAdapter() {
const defaultAdapter = MDCSlidableDrawerFoundation.defaultAdapter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You could simplify this by using Object.assign

return Object.assign(MDCSlidableDrawerFoundation.defaultAdapter, {
  isRoot: () => false,
});

MDCPersistentDrawerFoundation.cssClasses.OPEN);
}

isRootTransitioningElement_(el) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our authoring components guide, we try very hard not to make references to _element_s or anything that makes assumptions about a host environment in our foundation / adapter code.

I imagine that this method gets called likely in response to an event, to which the event target is passed to this method. In that case, we usually tend to use the term eventTarget in place of element. E.g.

getIndexForEventTarget: (/* target: EventTarget */) => /* number */ 0,

import * as util from '../util';

export {MDCPersistentDrawerFoundation};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may want to consider exporting util here. Users have asked for this in the past with other utility modules we've made for components.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and exported util for temporary/index.js too

}

&--animating {
transition: mdc-animation-enter(width, $mdc-slidable-drawer-transition-time);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, you definitely don't want to be animating width here if at all possible, as it has severe performance implications, especially considering that this will tend to have implications on how the entire page is laid out. I'd be okay with a jump-cut here. Otherwise, I'd look into using something like the FLIP model to see if we can achieve the same affect using transforms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going with jump-cut for now...but I left the extra div element (aka .mdc-persistent-drawer and .mdc-persistent-drawer__drawer) since I figured clients will want to animate something like width?

@include mdc-rtl-reflexive-position(left, 0);

@include mdc-theme-dark {
background: #212121;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we want to hard-code BG colors here, as this gives the user a lot less thematic control and assumes that this is the color of the background we want to use for dark themes. I'd take an approach similar to dialog here (source).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and refactored permanent drawers to "not hard-code BG colors" too

@@ -15,5 +15,7 @@
*/

import * as util from './util';
export {MDCSlidableDrawerFoundation} from './slidable';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we want to export this particular foundation here since it's meant to be subclassed by our drawer implementations, and we want to reduce the API surface such that we're not encouraging users to make their own versions of Material Design drawers.

* limitations under the License.
*/

export const focusableElements =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This should be named FOCUSABLE_ELEMENTS to adhere to constants conventions.

* limitations under the License.
*/

@import "@material/rtl/mixins";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: looks like there are a few magic numbers (107%, 20px) here. Perhaps they should be refactored into scss vars?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly...I have no idea, they were existing magic numbers in temporary drawers.

I've isolated them to slideable's _mixins.scss in this Pull Request. I think a follow up pull request might want to investigate these magic numbers more

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't realize they came from temporary drawer. SGTM for addressing in a different PR.

getDrawerWidth: () => /* number */ 0,
isDrawer: (/* el: Element */) => /* boolean */ false,
};
const defaultAdapter = MDCSlidableDrawerFoundation.defaultAdapter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as in persistent drawer regarding Object.assign.

@lynnmercier
Copy link
Contributor Author

Updated based on comments, PTAL

Copy link
Contributor

@traviskaufman traviskaufman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just nits / small changes this time around!

@@ -70,6 +70,131 @@ CSS classes:
| `mdc-permanent-drawer__content` | Mandatory. Needs to be set on the container node for the drawer content. |
| `mdc-permanent-drawer__toolbar-spacer` | Optional. Add to node to provide the matching amount of space for toolbar. |

## Persistent drawer usage

A persistent drawers can toggle open or closed. The drawer sits on the same surface elevation as the content. It is closed by default. When the drawer is outside of the page grid and opens, the drawer forces other content to change size and adapt to the smaller viewport. Persistent drawers stay open until closed by the user.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change this first sentence to "Persistent drawers can be toggled open or closed"?


export const strings = {
DRAWER_SELECTOR: '.mdc-persistent-drawer__drawer',
FOCUSABLE_ELEMENTS: FOCUSABLE_ELEMENTS,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can just the object shorthand property here

export const strings = {
  DRAWER_SELECTOR: '.mdc-persistent-drawer__drawer',
  FOCUSABLE_ELEMENTS,
};

@include mdc-rtl-reflexive-position(left, 0);

@include mdc-theme-dark {
background-color: $mdc-persistent-drawer-dark-theme-bg-color;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

supernit: seems like the indentation is off here. V surprised stylelint didn't catch that.

* limitations under the License.
*/

@import "@material/rtl/mixins";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't realize they came from temporary drawer. SGTM for addressing in a different PR.

this.openCssClass_ = openCssClass;

this.transitionEndHandler_ = (ev) => {
if (this.isRootTransitioningElement_(ev.target)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be isRootTransitioningEventTarget_ ?

@@ -0,0 +1,284 @@
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be named mdc-persistent-drawer.test.js. It actually might not be getting run otherwise...

Also FYI chai has assert.{isTrue,isFalse} which is a strict boolean test rather than just a test for truthiness / falsiness.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, totally was not running...well done lynn...

`;
document.body.appendChild(root);
const component = new MDCPersistentDrawer(root);
assert.isOk(component.getDefaultFoundation().adapter_.isRtl());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you'll want to make sure to remove the root element from document.body before the test ends, here and below.

});

test('defaultAdapter returns a complete adapter implementation', () => {
const {defaultAdapter} = MDCPersistentDrawerFoundation;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a verifyDefaultAdapter helper method in test/helpers/foundation which you can use for this

suite('MDCSlidableDrawerFoundation');

test('defaultAdapter returns a complete adapter implementation', () => {
const {defaultAdapter} = MDCSlidableDrawerFoundation;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above re verifyDefaultAdapter

</nav>
</aside>
<div class="demo-content">
<header class="mdc-toolbar mdc-elevation--z4">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this DOM needs to be updated to reflect recent toolbar changes:

<header class="mdc-toolbar mdc-elevation--z4">
  <div class="mdc-toolbar__row">
    <section class="mdc-toolbar__section mdc-toolbar__section--align-start">
      <button class="demo-menu material-icons">menu</button>
    </section>
  </div>
</header>

…e 'drawer' element as the root transitioning element, now that I removed the transition property from the component's root element
@lynnmercier
Copy link
Contributor Author

Updated based on comments, PTAL

Copy link
Contributor

@traviskaufman traviskaufman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💎 💯 🔥 🚀 :shipit: One nit but besides that LGTM! Awesome stuff here, especially around the refactoring.

| `restoreElementTabState(el: Element) => void` | Restores the saved tab index (if any) for an element. |
| `makeElementUntabbable(el: Element) => void` | Makes an element untabbable. |
| `isRtl() => boolean` | Returns boolean indicating whether the current environment is RTL. |
| `isRoot(el: Element) => boolean` | Returns boolean indicating whether the provided element is the root container element. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like this method is used anywhere anymore. Left over from a previous iteration?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm nope. fixed

@lynnmercier lynnmercier merged commit 79a2352 into master Apr 12, 2017
@lynnmercier lynnmercier deleted the feat/permanent-drawer branch April 12, 2017 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants