diff --git a/addon/components/paper-tab.hbs b/addon/components/paper-tab.hbs
index f5007a8b9..1a49402b7 100644
--- a/addon/components/paper-tab.hbs
+++ b/addon/components/paper-tab.hbs
@@ -1,7 +1,25 @@
-{{! template-lint-disable no-curly-component-invocation }}
-{{#if (has-block)}}
- {{yield}}
-{{else}}
- {{@name}}
-{{/if}}
-
\ No newline at end of file
+{{#let (element this.tag) as |Tag|}}
+
+ {{#if (has-block)}}
+ {{yield}}
+ {{else}}
+ {{@name}}
+ {{/if}}
+
+
+{{/let}}
\ No newline at end of file
diff --git a/addon/components/paper-tab.js b/addon/components/paper-tab.js
index a31c0cb49..25ed0aa81 100644
--- a/addon/components/paper-tab.js
+++ b/addon/components/paper-tab.js
@@ -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
-) {
- // 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 ',
+ 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);
+ }
+ }
+
+ /**
+ * 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);
+ }
}
}
}