mirror of
https://github.com/material-components/material-web.git
synced 2024-09-11 13:46:10 +03:00
fix(tabs): remove previously selected tab property
PiperOrigin-RevId: 563797711
This commit is contained in:
parent
2468241157
commit
70ce0d2779
@ -8,25 +8,25 @@ import '../../elevation/elevation.js';
|
|||||||
import '../../focus/md-focus-ring.js';
|
import '../../focus/md-focus-ring.js';
|
||||||
import '../../ripple/ripple.js';
|
import '../../ripple/ripple.js';
|
||||||
|
|
||||||
import {html, isServer, LitElement, nothing, PropertyValues} from 'lit';
|
import {html, isServer, LitElement, nothing} from 'lit';
|
||||||
import {property, query, queryAssignedElements, queryAssignedNodes, state} from 'lit/decorators.js';
|
import {property, query, queryAssignedElements, queryAssignedNodes, state} from 'lit/decorators.js';
|
||||||
import {classMap} from 'lit/directives/class-map.js';
|
import {classMap} from 'lit/directives/class-map.js';
|
||||||
|
|
||||||
import {polyfillElementInternalsAria, setupHostAria} from '../../internal/aria/aria.js';
|
import {polyfillElementInternalsAria, setupHostAria} from '../../internal/aria/aria.js';
|
||||||
import {EASING} from '../../internal/motion/animation.js';
|
import {EASING} from '../../internal/motion/animation.js';
|
||||||
|
|
||||||
interface Tabs extends HTMLElement {
|
|
||||||
selected?: number;
|
|
||||||
selectedItem?: Tab;
|
|
||||||
previousSelectedItem?: Tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbol for tabs to use to animate their indicators based off another tab's
|
* Symbol for tabs to use to animate their indicators based off another tab's
|
||||||
* indicator.
|
* indicator.
|
||||||
*/
|
*/
|
||||||
const INDICATOR = Symbol('indicator');
|
const INDICATOR = Symbol('indicator');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symbol used by the tab bar to request a tab to animate its indicator from a
|
||||||
|
* previously selected tab.
|
||||||
|
*/
|
||||||
|
export const ANIMATE_INDICATOR = Symbol('animateIndicator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tab component.
|
* Tab component.
|
||||||
*/
|
*/
|
||||||
@ -104,11 +104,8 @@ export class Tab extends LitElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override updated(changed: PropertyValues) {
|
protected override updated() {
|
||||||
if (changed.has('active')) {
|
this.internals.ariaSelected = String(this.active);
|
||||||
this.internals.ariaSelected = String(this.active);
|
|
||||||
this.animateSelected();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleKeydown(event: KeyboardEvent) {
|
private async handleKeydown(event: KeyboardEvent) {
|
||||||
@ -125,7 +122,7 @@ export class Tab extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private animateSelected() {
|
[ANIMATE_INDICATOR](previousTab: Tab) {
|
||||||
if (!this[INDICATOR]) {
|
if (!this[INDICATOR]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -133,25 +130,22 @@ export class Tab extends LitElement {
|
|||||||
this[INDICATOR].getAnimations().forEach(a => {
|
this[INDICATOR].getAnimations().forEach(a => {
|
||||||
a.cancel();
|
a.cancel();
|
||||||
});
|
});
|
||||||
const frames = this.getKeyframes();
|
const frames = this.getKeyframes(previousTab);
|
||||||
if (frames !== null) {
|
if (frames !== null) {
|
||||||
this[INDICATOR].animate(
|
this[INDICATOR].animate(
|
||||||
frames, {duration: 250, easing: EASING.EMPHASIZED});
|
frames, {duration: 250, easing: EASING.EMPHASIZED});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getKeyframes() {
|
private getKeyframes(previousTab: Tab) {
|
||||||
const reduceMotion = shouldReduceMotion();
|
const reduceMotion = shouldReduceMotion();
|
||||||
if (!this.active) {
|
if (!this.active) {
|
||||||
return reduceMotion ? [{'opacity': 1}, {'transform': 'none'}] : null;
|
return reduceMotion ? [{'opacity': 1}, {'transform': 'none'}] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/298105040): avoid hardcoding selector
|
|
||||||
const tabs = this.closest<Tabs>('md-tabs');
|
|
||||||
const from: Keyframe = {};
|
const from: Keyframe = {};
|
||||||
const fromRect =
|
const fromRect =
|
||||||
(tabs?.previousSelectedItem?.[INDICATOR]?.getBoundingClientRect() ??
|
previousTab[INDICATOR]?.getBoundingClientRect() ?? ({} as DOMRect);
|
||||||
({} as DOMRect));
|
|
||||||
const fromPos = fromRect.left;
|
const fromPos = fromRect.left;
|
||||||
const fromExtent = fromRect.width;
|
const fromExtent = fromRect.width;
|
||||||
const toRect = this[INDICATOR]!.getBoundingClientRect();
|
const toRect = this[INDICATOR]!.getBoundingClientRect();
|
||||||
|
@ -11,7 +11,7 @@ import {property, queryAssignedElements, state} from 'lit/decorators.js';
|
|||||||
|
|
||||||
import {polyfillElementInternalsAria, setupHostAria} from '../../internal/aria/aria.js';
|
import {polyfillElementInternalsAria, setupHostAria} from '../../internal/aria/aria.js';
|
||||||
|
|
||||||
import {Tab} from './tab.js';
|
import {ANIMATE_INDICATOR, Tab} from './tab.js';
|
||||||
|
|
||||||
const NAVIGATION_KEYS = new Map([
|
const NAVIGATION_KEYS = new Map([
|
||||||
['default', new Set(['Home', 'End'])],
|
['default', new Set(['Home', 'End'])],
|
||||||
@ -85,7 +85,7 @@ export class Tabs extends LitElement {
|
|||||||
/**
|
/**
|
||||||
* The item previously selected.
|
* The item previously selected.
|
||||||
*/
|
*/
|
||||||
get previousSelectedItem() {
|
private get previousSelectedItem() {
|
||||||
return this.tabs[this.previousSelected];
|
return this.tabs[this.previousSelected];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +142,7 @@ export class Tabs extends LitElement {
|
|||||||
this.previousSelectedItem !== this.selectedItem) {
|
this.previousSelectedItem !== this.selectedItem) {
|
||||||
this.previousSelectedItem.active = false;
|
this.previousSelectedItem.active = false;
|
||||||
this.selectedItem.active = true;
|
this.selectedItem.active = true;
|
||||||
|
this.selectedItem[ANIMATE_INDICATOR](this.previousSelectedItem);
|
||||||
}
|
}
|
||||||
if (this.selectedItem !== this.focusedItem) {
|
if (this.selectedItem !== this.focusedItem) {
|
||||||
this.updateFocusableItem(this.selectedItem);
|
this.updateFocusableItem(this.selectedItem);
|
||||||
|
@ -70,17 +70,14 @@ describe('<md-tabs>', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updates selectedItem/previousSelectedItem', async () => {
|
it('updates selectedItem', async () => {
|
||||||
const {harness} = await setupTest({selected: 1});
|
const {harness} = await setupTest({selected: 1});
|
||||||
expect(harness.element.selectedItem)
|
expect(harness.element.selectedItem)
|
||||||
.toBe(harness.harnessedItems[1].element);
|
.toBe(harness.harnessedItems[1].element);
|
||||||
expect(harness.element.previousSelectedItem).toBeUndefined();
|
|
||||||
harness.element.selected = 0;
|
harness.element.selected = 0;
|
||||||
await harness.element.updateComplete;
|
await harness.element.updateComplete;
|
||||||
expect(harness.element.selectedItem)
|
expect(harness.element.selectedItem)
|
||||||
.toBe(harness.harnessedItems[0].element);
|
.toBe(harness.harnessedItems[0].element);
|
||||||
expect(harness.element.previousSelectedItem)
|
|
||||||
.toBe(harness.harnessedItems[1].element);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maintains selection when tabs are mutated', async () => {
|
it('maintains selection when tabs are mutated', async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user