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(paper-tabs): converts to a glimmer component. #1313

Open
wants to merge 3 commits into
base: feature/glimmer-paper-switch
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions addon/components/paper-ink-bar.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<md-ink-bar class={{if @movingRight 'md-right' 'md-left'}} style={{this.style}}>
</md-ink-bar>
19 changes: 6 additions & 13 deletions addon/components/paper-ink-bar.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
/* eslint-disable ember/no-classic-components, ember/require-tagless-components, prettier/prettier */
import { computed } from '@ember/object';
import Component from '@ember/component';
import Component from '@glimmer/component';
import { htmlSafe } from '@ember/template';

export default Component.extend({
tagName: 'md-ink-bar',

attributeBindings: ['style'],
classNameBindings: ['movingRight:md-right:md-left'],

style: computed('left', 'right', function() {
return htmlSafe(`left: ${this.left}px; right: ${this.right}px;`);
})
});
export default class PaperInkBar extends Component {
get style() {
return htmlSafe(`left: ${this.args.left}px; right: ${this.args.right}px;`);
}
}
32 changes: 25 additions & 7 deletions addon/components/paper-tab.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
{{! template-lint-disable no-curly-component-invocation }}
{{#if (has-block)}}
{{yield}}
{{else}}
{{@name}}
{{/if}}
<PaperRipple/>
{{#let (element this.tag) as |Tag|}}
<Tag
class='md-tab
{{~if this.focused " md-focused"}}
{{~if this.isSelected " md-active"}}
{{@class}}'
aria-selected={{this.isSelected}}
disabled={{this.disabled}}
href={{this.maybeHref}}
style={{this.style}}
tabindex={{if this.disabled '-1' '0'}}
{{did-insert this.didInsertNode}}
{{did-update this.didUpdateNode @value}}
{{will-destroy this.willDestroyNode}}
{{on 'click' this.handleClick}}
...attributes
>
{{#if (has-block)}}
{{yield}}
{{else}}
{{@name}}
{{/if}}
<PaperRipple />
</Tag>
{{/let}}
212 changes: 167 additions & 45 deletions addon/components/paper-tab.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,194 @@
/* eslint-disable ember/classic-decorator-hooks, ember/classic-decorator-no-classic-methods, ember/no-classic-components, ember/no-computed-properties-in-native-classes, ember/no-mixins */
import {
classNames,
attributeBindings,
classNameBindings,
tagName,
} from '@ember-decorators/component';

import { computed } from '@ember/object';
import Component from '@ember/component';
/**
* @module ember-paper
*/
import Focusable from './-focusable';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { htmlSafe } from '@ember/template';
import { ChildMixin } from 'ember-composability-tools';
import FocusableMixin from 'ember-paper/mixins/focusable-mixin';
import { invokeAction } from 'ember-paper/utils/invoke-action';

@tagName('md-tab-item')
@classNames('md-tab')
@classNameBindings('isSelected:md-active')
@attributeBindings('isSelected:aria-selected', 'style', 'maybeHref:href')
export default class PaperTab extends Component.extend(
ChildMixin,
FocusableMixin
) {
// <a> tags have browser styles or are usually styled by the user
// this makes sure that tab item still looks good with an anchor tag
@computed('href')
import { assert } from '@ember/debug';

/**
* @class PaperTab
* @extends Focusable
*/
export default class PaperTab extends Focusable {
/**
* Reference to the component's DOM element.
*
* @type {HTMLElement}
*/
element;
/**
* The parent this component is bound to.
*
* @type {PaperTabs}
*/
parent;
/**
* Marks whether the component should register itself to the supplied parent.
*
* @type {Boolean}
*/
shouldRegister;
/**
* The top level tag to render. One of {'a', 'md-tab'}.
*
* @type {string}
* @private
* @default 'md-tab-item'
*/
tag;
/**
* provides a proxy value if one is not supplied by the user.
*
* @type {number|*}
* @private
*/
@tracked _value;
/**
* the number of pixels that the upper left corner of the current element is
* offset to the left within the {@link HTMLElement.offsetParent} node.
*
* @type{number}
*/
@tracked left;
/**
* the layout width of the element as an integer.
*
* @type{number}
*/
@tracked width;

/**
* @constructor
* @param owner
* @param args
*/
constructor(owner, args) {
super(owner, args);

this.tag = 'md-tab-item';
if (this.args.href) {
this.tag = 'a';
}

this.shouldRegister = this.args.shouldRegister || true;
if (this.shouldRegister) {
assert(
'A parent component should be supplied to <PaperTab>',
this.args.parentComponent
);
this.parent = this.args.parentComponent;
}
}

/**
* Performs any required DOM setup.
*
* @param {HTMLElement} element - the node that has been added to the DOM.
*/
@action didInsertNode(element) {
this.element = element;
this.left = element.offsetLeft;
this.width = element.offsetWidth;

this.registerListeners(element);

if (this.shouldRegister) {
this.parent.registerChild(this);
}
}

/**
* didUpdateNode is called when tracked component attributes change.
*/
@action didUpdateNode() {
if (this.args.value) {
this.value = this.args.value;
}
}

/**
* Performs any required DOM teardown.
*
* @param {HTMLElement} element - the node to be removed from the DOM.
*/
@action willDestroyNode(element) {
this.unregisterListeners(element);
}

/**
* lifecycle hook to perform non-DOM related teardown.
*/
willDestroy() {
super.willDestroy();

if (this.shouldRegister) {
this.parent.unregisterChild(this);
}
}

/**
* <a> tags have browser styles or are usually styled by the user
* this makes sure that tab item still looks good with an anchor tag.
*
* @returns {string|undefined}
*/
get style() {
if (this.href) {
if (this.args.href) {
return htmlSafe('text-decoration: none; border: none;');
} else {
return undefined;
}
}

@computed('href', 'disabled')
/**
* maybeHref returns the user supplied href link url.
*
* @returns {string|undefined}
*/
get maybeHref() {
if (this.href && !this.disabled) {
return this.href;
if (this.args.href && !this.disabled) {
return this.args.href;
} else {
return undefined;
}
}

@computed('selected', 'value')
/**
* computes whether this is the currently selected tab.
*
* @returns {boolean}
*/
get isSelected() {
return this.selected === this.value;
}

init() {
super.init(...arguments);
if (this.href) {
this.set('tagName', 'a');
}
return this.args.selected === this.value;
}

// this method is called by the parent
updateDimensions() {
// this is the true current width
// it is used to calculate the ink bar position & pagination offset
this.setProperties({
left: this.element.offsetLeft,
width: this.element.offsetWidth,
});
this.left = this.element.offsetLeft;
this.width = this.element.offsetWidth;
}

click() {
get value() {
// enable support for user supplied value
return this.args.value || this._value;
}
set value(value) {
this._value = value;
}

@action handleClick(e) {
if (!this.disabled) {
invokeAction(this, 'onClick', ...arguments);
invokeAction(this, 'onSelect', this);
if (this.args.onClick) {
this.args.onClick(e);
}

if (this.args.onSelect) {
this.args.onSelect(this);
}
}
}
}
Loading
Loading