Skip to content

Commit ecc76a0

Browse files
committed
fix(top-nav): match indicator management strategy from Tabs
1 parent 872e9fd commit ecc76a0

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

packages/top-nav/src/TopNav.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ export class TopNav extends SizedMixin(SpectrumElement) {
8787

8888
protected override render(): TemplateResult {
8989
return html`
90-
<div @click=${this.onClick} id="list">
90+
<div
91+
@click=${this.onClick}
92+
id="list"
93+
@sp-top-nav-item-contentchange=${this.updateSelectionIndicator}
94+
>
9195
<slot @slotchange=${this.onSlotChange}></slot>
9296
<div
9397
id="selection-indicator"

packages/top-nav/src/TopNavItem.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ export class TopNavItem extends LikeAnchor(Focusable) {
4545

4646
public value = '';
4747

48+
protected handleContentChange(): void {
49+
/**
50+
* When the content in a tab has changed, JS powered layout related to that content may also need to be changed.
51+
*/
52+
this.dispatchEvent(
53+
new Event('sp-top-nav-item-contentchange', {
54+
bubbles: true,
55+
composed: true,
56+
})
57+
);
58+
}
59+
4860
public override get focusElement(): HTMLAnchorElement {
4961
return this.anchor;
5062
}
@@ -73,10 +85,22 @@ export class TopNavItem extends LikeAnchor(Focusable) {
7385

7486
protected override firstUpdated(changes: PropertyValues): void {
7587
super.firstUpdated(changes);
88+
// @TODO - refactor this as a ResizeObserver up to `sp-tabs` so that it can be more
89+
// resiliant to Tab content changes, as well as other content slotted into the "tablist".
90+
this.shadowRoot.addEventListener(
91+
'slotchange',
92+
this.handleContentChange
93+
);
7694
}
7795

7896
protected override updated(changes: PropertyValues): void {
7997
super.updated(changes);
98+
if (
99+
changes.has('label') &&
100+
typeof changes.get('label') !== 'undefined'
101+
) {
102+
this.handleContentChange();
103+
}
80104
this.value = this.anchor.href;
81105
}
82106
}

packages/top-nav/test/top-nav.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
1010
governing permissions and limitations under the License.
1111
*/
1212

13-
import { elementUpdated, expect, fixture } from '@open-wc/testing';
13+
import { elementUpdated, expect, fixture, nextFrame } from '@open-wc/testing';
1414

1515
import { TopNav, TopNavItem } from '@spectrum-web-components/top-nav';
1616
import { Default, Selected } from '../stories/top-nav.stories.js';
@@ -33,6 +33,28 @@ describe('TopNav', () => {
3333

3434
await expect(el).to.be.accessible();
3535
});
36+
it('updates indicator size when Nav Item conten changes', async () => {
37+
const el = await fixture<TopNav>(Selected());
38+
39+
await elementUpdated(el);
40+
41+
const indicator = el.shadowRoot.querySelector(
42+
'#selection-indicator'
43+
) as HTMLDivElement;
44+
const { width: widthStart } = indicator.getBoundingClientRect();
45+
46+
const selectedItem = el.querySelector(
47+
`[href="${el.selected}"]`
48+
) as TopNavItem;
49+
selectedItem.innerHTML = '0';
50+
51+
// Wait for slotchange time before continuing the test.
52+
await nextFrame();
53+
54+
const { width: widthEnd } = indicator.getBoundingClientRect();
55+
56+
expect(widthStart).to.be.greaterThan(widthEnd);
57+
});
3658
});
3759

3860
describe('TopNavItem', () => {

0 commit comments

Comments
 (0)