diff --git a/tabs/harness.ts b/tabs/harness.ts index 2516dd7246..b85f7d69c2 100644 --- a/tabs/harness.ts +++ b/tabs/harness.ts @@ -15,12 +15,20 @@ import {Tabs} from './lib/tabs.js'; export class TabHarness extends Harness { override async getInteractiveElement() { await this.element.updateComplete; - return this.element.querySelector( - '.button')!; + return this.element.renderRoot + .querySelector('.button')!; } - async isIndicatorShowing() { + private async completeIndicatorAnimation() { await this.element.updateComplete; + const animations = this.element.indicator.getAnimations(); + for (const animation of animations) { + animation.finish(); + } + } + + async isIndicatorShowing() { + await this.completeIndicatorAnimation(); const opacity = getComputedStyle(this.element.indicator)['opacity']; return opacity === '1'; } @@ -30,6 +38,17 @@ export class TabHarness extends Harness { * Test harness for Tabs. */ export class TabsHarness extends Harness { + // Note, Tabs interactive element is the interactive element of the + // selected tab. + override async getInteractiveElement() { + await this.element.updateComplete; + const selectedItemHarness = + (this.element.selectedItem as ElementWithHarness).harness as + TabHarness ?? + new TabHarness(this.element.selectedItem); + return await selectedItemHarness.getInteractiveElement(); + } + get harnessedItems() { // Test access to protected property // tslint:disable-next-line:no-dict-access-on-struct-type diff --git a/tabs/lib/tab.ts b/tabs/lib/tab.ts index 56d45d3949..d80cd5d86e 100644 --- a/tabs/lib/tab.ts +++ b/tabs/lib/tab.ts @@ -81,10 +81,6 @@ export class Tab extends LitElement { @state() private showRipple = false; - // whether or not selection state can be animated; used to avoid initial - // animation and becomes true one task after first update. - private canAnimate = false; - constructor() { super(); if (!isServer) { @@ -125,13 +121,8 @@ export class Tab extends LitElement { `; } - protected override async firstUpdated() { - await new Promise(requestAnimationFrame); - this.canAnimate = true; - } - protected override updated(changed: PropertyValues) { - if (changed.has('selected') && this.shouldAnimate()) { + if (changed.has('selected') && !this.disabled) { this.animateSelected(); } } @@ -144,10 +135,6 @@ export class Tab extends LitElement { dispatchActivationClick(this.button); }; - private shouldAnimate() { - return this.canAnimate && !this.disabled; - } - private readonly getRipple = () => { this.showRipple = true; return this.ripple; diff --git a/tabs/lib/tabs.ts b/tabs/lib/tabs.ts index 7f86ab3126..2e18a72434 100644 --- a/tabs/lib/tabs.ts +++ b/tabs/lib/tabs.ts @@ -232,10 +232,6 @@ export class Tabs extends LitElement { } protected override async updated(changed: PropertyValues) { - // if there's no items, they may not be ready, so wait before syncronizing - if (this.items.length === 0) { - await new Promise(requestAnimationFrame); - } const itemsOrVariantChanged = changed.has('items') || changed.has('variant'); // sync variant with items. @@ -296,13 +292,20 @@ export class Tabs extends LitElement { this.requestUpdate(); } + private async itemsUpdateComplete() { + for (const item of this.items) { + await item.updateComplete; + } + return true; + } + // ensures the given item is visible in view; defaults to the selected item private async scrollItemIntoView(item = this.selectedItem) { if (!item) { return; } // wait for items to render. - await new Promise(requestAnimationFrame); + await this.itemsUpdateComplete(); const isVertical = this.orientation === 'vertical'; const offset = isVertical ? item.offsetTop : item.offsetLeft; const extent = isVertical ? item.offsetHeight : item.offsetWidth; @@ -311,8 +314,11 @@ export class Tabs extends LitElement { const min = offset - this.scrollMargin; const max = offset + extent - hostExtent + this.scrollMargin; const to = Math.min(min, Math.max(max, scroll)); + const behavior = + // type annotation because `instant` is valid but not included in type. + this.focusedItem !== undefined ? 'smooth' : 'instant' as ScrollBehavior; this.scrollTo({ - behavior: 'smooth', + behavior, [isVertical ? 'left' : 'top']: 0, [isVertical ? 'top' : 'left']: to }); diff --git a/tabs/test/window_size.json b/tabs/test/window_size.json new file mode 100644 index 0000000000..191dd70fcb --- /dev/null +++ b/tabs/test/window_size.json @@ -0,0 +1,13 @@ +{ + "capabilities": { + "goog:chromeOptions": { + "args": ["--window-position=0,0", "--window-size=3400,2215"] + }, + "moz:firefoxOptions": { + "args": ["-width=3400","-height=2215"] + } + }, + "extension": { + "xvfbResolution": "3400x2215x24" + } +} diff --git a/tokens/_md-comp-tab.scss b/tokens/_md-comp-tab.scss index f99df4a66b..18b0d334ae 100644 --- a/tokens/_md-comp-tab.scss +++ b/tokens/_md-comp-tab.scss @@ -24,7 +24,6 @@ $_default: ( 'md-sys-shape': md-sys-shape.values(), 'md-sys-state': md-sys-state.values(), 'md-sys-typescale': md-sys-typescale.values(), - 'md-comp-divider': md-comp-divider.values(), ); $supported-tokens: ( @@ -242,7 +241,7 @@ $unsupported-tokens: ( // add tokens for divider / label-text @function _add-missing-tokens($tokens, $deps) { - $divider-tokens: map.get($deps, 'md-comp-divider'); + $divider-tokens: md-comp-divider.values(); @each $key, $value in $divider-tokens { $key: 'divider-#{$key}'; $tokens: map.set($tokens, $key, $value);