Skip to content

Added MDC Tab bar scroller#21

Merged
Kerrick merged 6 commits intomasterfrom
tab-bar-scroller
Aug 28, 2017
Merged

Added MDC Tab bar scroller#21
Kerrick merged 6 commits intomasterfrom
tab-bar-scroller

Conversation

@danielraggs
Copy link
Copy Markdown

@danielraggs danielraggs commented Aug 1, 2017

Material Design Tab Bar Scroller component is now available for use in Ember Material Components Web. This component acts as a parent container for mdc-tab-bar by invoking an instance of it inside its Handlebars.

Example implementation:

{{#mdc-tab-bar-scroller as |scroller|}}
    {{#scroller.tab-bar links=false as |bar|}}
      {{#bar.tab}}
        Red
      {{/bar.tab}}
      {{#bar.tab}}
        Yellow
      {{/bar.tab}}
      {{#bar.tab}}
        Green
      {{/bar.tab}}
      {{#bar.tab}}
        White
      {{/bar.tab}}
      {{#bar.tab}}
        Blue
      {{/bar.tab}}
    {{/scroller.tab-bar}}
{{/mdc-tab-bar-scroller}}

Comment thread addon/components/mdc-tab-bar.js Outdated

export default Ember.Component.extend(MDCComponent, {
//region Attributes
/**
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What does the @private signify, given that it's within Attributes which are usually public?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The attribute scrolling only ever gets used inside mdc-tab-bar-scroller.hbs, where it gets passed into {{mdc-tab-bar}} as true. In that sense yes it's an attribute, but I marked it as private because this isn't something the user should ever be passing on their own into the {{mdc-tab-bar}}, it's handled internally by the code.

Comment thread addon/components/mdc-tab-bar.js Outdated
},
didInsertElement() {
this._super(...arguments);
if (get(this, 'scrolling')) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems like you might want to gate this based on the presence of the action instead of scrolling.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah that's a good idea. If I do this then I no longer need the scrolling attribute also.

Comment thread addon/components/mdc-tab-bar.js Outdated
},
willDestroyElement() {
this._super(...arguments);
if (get(this, 'scrolling')) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems like you might want to gate this based on the presence of the action instead of scrolling.

},
didInsertElement() {
this._super(...arguments);
set(this, 'scrollFrameElement', getElementProperty(this, 'querySelector')(strings.FRAME_SELECTOR));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please be sure to have a fallback for getElementProperty when it's supposed to return a function. Example:

getElementProperty(this, 'querySelector', () => null)(strings.FRAME_SELECTOR)

CLASS_NAMES: cssClasses,

/**
* @type {Object}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe these should be @property not @type, and should be HTMLElement instead of Object.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I can make this change but just to double-check, was this also supposed to apply to mdc-menu.js as well? We have a property there that uses @type {HTMLElement} instead of @property.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Whoops! Those should eventually be fixed, but they shouldn't block this PR.

removeClassFromForwardIndicator: (className) => run(() => get(this, 'forwardIndicatorClasses').removeObject(className)),
addClassToBackIndicator: (className) => run(() => get(this, 'backIndicatorClasses').addObject(className)),
removeClassFromBackIndicator: (className) => run(() => get(this, 'backIndicatorClasses').removeObject(className)),
isRTL: () => getElementProperty(this, 'direction') === 'rtl',
Copy link
Copy Markdown
Contributor

@Kerrick Kerrick Aug 24, 2017

Choose a reason for hiding this comment

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

I believe you want to get dir, not direction. Alternatively, you can do getComputedStyle for the CSS direction.

addClassToBackIndicator: (className) => run(() => get(this, 'backIndicatorClasses').addObject(className)),
removeClassFromBackIndicator: (className) => run(() => get(this, 'backIndicatorClasses').removeObject(className)),
isRTL: () => getElementProperty(this, 'direction') === 'rtl',
registerBackIndicatorClickHandler: (handler) => get(this, 'backIndicatorElement').addEventListener('click', handler),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure if this will happen or not, but I have a concern:

If the back indicator element is un-rendered and re-rendered as a different DOM element by Ember after the click handler was registered, then it will no longer have a click event listener attached. This is bad, and should be avoided.

If this is a problem, I see two ways to avoid it:

  1. Store the back indicator element click handlers in the component JS, and re-attach them every time on didRender
  2. Store the back indicator element click handlers in the component JS, and use the click Ember hook for the whole component, firing off each back indicator element click handler if the event's target was the back indicator element.

I think I'd prefer the latter of those two, and I'm not sure that list is exhaustive.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This applies to the other register/deregisterHandler methods that apply listeners directly to the elements, too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'm not sure I understand-- why would the back indicator element ever be un-rendered without the entire component itself being un-rendered?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You're completely right, it wouldn't be. This was only a risk if there was a boolean around the indicators or something, which there's clearly not.

@secondstreet secondstreet deleted a comment from danielraggs Aug 24, 2017
removeClassFromForwardIndicator: (className) => run(() => get(this, 'forwardIndicatorClasses').removeObject(className)),
addClassToBackIndicator: (className) => run(() => get(this, 'backIndicatorClasses').addObject(className)),
removeClassFromBackIndicator: (className) => run(() => get(this, 'backIndicatorClasses').removeObject(className)),
isRTL: () => getComputedStyle(get(this, 'element')).getPropertyValue('direction') === 'rtl',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems like this might run the risk of this.element being missing because the component has been destroyed -- probably safest to change it to something like:

!!this && !get(this, 'isDestroyed') && !!get(this, 'element') && getComputedStyle(get(this, 'element')).getPropertyValue('direction') === 'rtl'

Comment thread addon/components/mdc-tab-bar.js Outdated
},
willDestroyElement() {
this._super(...arguments);
if (get(this, 'deregister-tab-bar')) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You won't have to wrap this or the other in an if if you add a default for deregister-tab-bar in the Attributes region.

@Kerrick
Copy link
Copy Markdown
Contributor

Kerrick commented Aug 28, 2017

Thank you so much for the PR! This will ship out soon with v0.0.35 👍

@Kerrick Kerrick merged commit daf9f3e into master Aug 28, 2017
Kerrick added a commit that referenced this pull request Aug 30, 2017
- 🐛 Fix unsafe HTML element access
- ✨ Dark theme can be used for tab bars and tab bar scrollers (#26)
- ⚡ Don't unnecessarily (de|re)-attach handlers (#25)
- ✨ Implement tab-bar-scroller from @material/tabs (#21)
- ✨ Implement @material/switch (#24)
Kerrick added a commit that referenced this pull request Aug 30, 2017
- 🐛 Fix unsafe HTML element access
- ✨ Dark theme can be used for tab bars and tab bar scrollers (#26)
- ⚡ Don't unnecessarily (de|re)-attach handlers (#25)
- ✨ Implement tab-bar-scroller from @material/tabs (#21)
- ✨ Implement @material/switch (#24)
@Kerrick Kerrick deleted the tab-bar-scroller branch October 12, 2017 20:56
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.

2 participants