diff --git a/packages/calcite-components/src/components/tab-nav/tab-nav.tsx b/packages/calcite-components/src/components/tab-nav/tab-nav.tsx index ee20703666d..da6d6e80e41 100644 --- a/packages/calcite-components/src/components/tab-nav/tab-nav.tsx +++ b/packages/calcite-components/src/components/tab-nav/tab-nav.tsx @@ -12,7 +12,6 @@ import { focusElementInGroup, FocusElementInGroupDestination, getElementDir, - slotChangeGetAssignedElements, } from "../../utils/dom"; import { createObserver } from "../../utils/observers"; import { Scale } from "../interfaces"; @@ -72,6 +71,8 @@ export class TabNav extends LitElement { return filterDirectChildren(this.el, "calcite-tab-title"); } + private makeFirstVisibleTabClosable = false; + // #endregion // #region State Properties @@ -367,14 +368,21 @@ export class TabNav extends LitElement { (event.currentTarget as HTMLDivElement).scrollBy(scrollByX, 0); } - private onSlotChange(event: Event): void { + private onSlotChange(): void { this.intersectionObserver?.disconnect(); - const slottedElements = slotChangeGetAssignedElements(event, "calcite-tab-title"); - slottedElements.forEach((child) => { + const tabTitles = this.tabTitles; + tabTitles.forEach((child) => { this.intersectionObserver?.observe(child); }); - this.calciteInternalTabNavSlotChange.emit(slottedElements); + const visibleTabTitlesIndices = this.getVisibleTabTitlesIndices(tabTitles); + const totalVisibleTabTitles = visibleTabTitlesIndices.length; + if (totalVisibleTabTitles > 1 && this.makeFirstVisibleTabClosable) { + tabTitles[visibleTabTitlesIndices[0]].closable = true; + this.makeFirstVisibleTabClosable = false; + } + + this.calciteInternalTabNavSlotChange.emit(tabTitles); } private storeTabTitleWrapperRef(el: HTMLDivElement) { @@ -517,18 +525,23 @@ export class TabNav extends LitElement { }); } - private handleTabTitleClose(closedTabTitleEl: TabTitle["el"]): void { - const { tabTitles } = this; - const selectionModified = closedTabTitleEl.selected; - - const visibleTabTitlesIndices = tabTitles.reduce( + private getVisibleTabTitlesIndices(tabTitles: TabTitle["el"][]): number[] { + return tabTitles.reduce( (tabTitleIndices: number[], tabTitle, index) => !tabTitle.closed ? [...tabTitleIndices, index] : tabTitleIndices, [], ); + } + + private handleTabTitleClose(closedTabTitleEl: TabTitle["el"]): void { + const { tabTitles } = this; + const selectionModified = closedTabTitleEl.selected; + + const visibleTabTitlesIndices = this.getVisibleTabTitlesIndices(tabTitles); const totalVisibleTabTitles = visibleTabTitlesIndices.length; if (totalVisibleTabTitles === 1 && tabTitles[visibleTabTitlesIndices[0]].closable) { + this.makeFirstVisibleTabClosable = true; tabTitles[visibleTabTitlesIndices[0]].closable = false; this.selectedTabId = visibleTabTitlesIndices[0]; diff --git a/packages/calcite-components/src/components/tabs/tabs.e2e.ts b/packages/calcite-components/src/components/tabs/tabs.e2e.ts index 1ad96997de1..7155a2a5ef7 100644 --- a/packages/calcite-components/src/components/tabs/tabs.e2e.ts +++ b/packages/calcite-components/src/components/tabs/tabs.e2e.ts @@ -405,5 +405,45 @@ describe("calcite-tabs", () => { expect(selectedTitleOnEmit).toBe("Tab 2 Title"); }); + + describe("hiding/displaying X", () => { + it("should hide x when tabs 2 to 4 closed and display x closable tab added", async () => { + for (let i = 2; i <= 4; ++i) { + await page.click(`#tab-title-${i} >>> .${TabTitleCSS.closeButton}`); + } + let tab1 = await page.find(`#tab-title-1`); + expect(await tab1.getProperty("closable")).toBe(false); + expect(await page.find(`#tab-title-1 >>> .${TabTitleCSS.closeButton}`)).toBeNull(); + + await page.evaluate(() => { + document + .getElementById("tab-title-4") + .insertAdjacentHTML("afterend", `Test`); + }); + await page.waitForChanges(); + tab1 = await page.find(`#tab-title-1`); + expect(await tab1.getProperty("closable")).toBe(true); + expect(await page.find(`#tab-title-1 >>> .${TabTitleCSS.closeButton}`)).toBeDefined(); + }); + + it("should hide x when tabs 1 to 3 closed and display x when closable tab added", async () => { + for (let i = 1; i <= 3; ++i) { + await page.click(`#tab-title-${i} >>> .${TabTitleCSS.closeButton}`); + } + let tab4 = await page.find(`#tab-title-4`); + expect(await tab4.getProperty("closable")).toBe(false); + expect(await page.find(`#tab-title-4 >>> .${TabTitleCSS.closeButton}`)).toBeNull(); + + await page.evaluate(() => { + document + .getElementById("tab-title-4") + .insertAdjacentHTML("afterend", `Test`); + }); + await page.waitForChanges(); + tab4 = await page.find(`#tab-title-4`); + expect(await tab4.getProperty("closable")).toBe(true); + expect(await page.find(`#tab-title-4 >>> .${TabTitleCSS.closeButton}`)).toBeDefined(); + }); + }); }); });