Skip to content

Commit

Permalink
feat(tab-nav): adds optional closable functionality to individual `ta…
Browse files Browse the repository at this point in the history
…b-titles` (#6740)

**Related Issue:** #2620

## Summary
`handleTabTitleClose` sequence is as follows:
> if `closed` item is `selected`, fall back on the next
> unless it's the last item, which falls back on previous
> closing non-selected items doesn't affect the `selected` tab
> last remaining item becomes `disabled`, if `closable`

- Added `closed` property
- Added `closable` property
- Added `calciteInternalTabsClose` event
- Added `calciteTabsClose` event
- Added t9n messages for `Close` text.
- Updated styling per new Figma specs
- Added tests

`handleTabTitleClose` keeps track of `visibleTabTitlesIndices` instead
of having Dom queries filter out `hidden`. This helps to sync `tabs`
with `tab-titles` using their corresponding `id`s set on the original
render. `visibleTabIndeces` is an array of `id`s of the non-hidden
`tab-titles`. When `tab-title` is `closed` this `id` is used to navigate
to the next visible item. This makes figuring out what the next item
should be when closing out of order is now more straightforward.

Tests coverage for 

- simple closing behavior 
- closing sequence behavior:
> - when closing `tab-titles` in sequence 1 (first selected) through 4,
`tab-title` and corresponding `tab` become hidden, and selection
fallback is the next tab
> - reverse fallback: when closing `tab-titles` in sequence 4 (last
selected) through 1, `tab-title` and corresponding `tab` become hidden,
and selection fallback is the previous tab
> - closing an unselected `tab-title` does not deselect the current
selection
> - 2 additional cases: works with a randomized closing sequence with
mixed selected and not

---------

Co-authored-by: Matt Driscoll <[email protected]>
Co-authored-by: JC Franco <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Anveshreddy mekala <[email protected]>
Co-authored-by: jona7150 <[email protected]>
Co-authored-by: Kitty Hurley <[email protected]>
  • Loading branch information
7 people authored May 22, 2023
1 parent 167f9f8 commit d30792d
Show file tree
Hide file tree
Showing 51 changed files with 760 additions and 112 deletions.
50 changes: 43 additions & 7 deletions src/components/tab-nav/tab-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from "../../utils/dom";
import { createObserver } from "../../utils/observers";
import { Scale } from "../interfaces";
import { TabChangeEventDetail } from "../tab/interfaces";
import { TabChangeEventDetail, TabCloseEventDetail } from "../tab/interfaces";
import { TabID, TabLayout, TabPosition } from "../tabs/interfaces";

/**
Expand Down Expand Up @@ -110,7 +110,8 @@ export class TabNav {
this.selectedTitle = await this.getTabTitleById(this.selectedTabId);
}

@Watch("selectedTitle") selectedTitleChanged(): void {
@Watch("selectedTitle")
selectedTitleChanged(): void {
this.updateOffsetPosition();
this.updateActiveWidth();
// reset the animation time on tab selection
Expand Down Expand Up @@ -181,6 +182,7 @@ export class TabNav {
// eslint-disable-next-line react/jsx-sort-props
ref={(el: HTMLDivElement) => (this.tabNavEl = el)}
>
<slot />
<div
class="tab-nav-active-indicator-container"
// eslint-disable-next-line react/jsx-sort-props
Expand All @@ -193,7 +195,6 @@ export class TabNav {
ref={(el) => (this.activeIndicatorEl = el as HTMLElement)}
/>
</div>
<slot />
</div>
</Host>
);
Expand Down Expand Up @@ -231,14 +232,19 @@ export class TabNav {
? event.detail.tab
: this.getIndexOfTabTitle(event.target as HTMLCalciteTabTitleElement);
event.stopPropagation();
event.preventDefault();
}

@Listen("calciteTabsActivate") activateTabHandler(event: CustomEvent<void>): void {
@Listen("calciteTabsActivate")
activateTabHandler(event: CustomEvent<void>): void {
this.calciteTabChange.emit();
event.stopPropagation();
}

@Listen("calciteInternalTabsClose")
internalCloseTabHandler(event: CustomEvent<TabCloseEventDetail>): void {
const closedTabTitleEl = event.target as HTMLCalciteTabTitleElement;
this.handleTabTitleClose(closedTabTitleEl);
event.stopPropagation();
event.preventDefault();
}

/**
Expand Down Expand Up @@ -330,7 +336,6 @@ export class TabNav {
focusElementInGroup(this.enabledTabTitles, el, destination);

event.stopPropagation();
event.preventDefault();
};

handleContainerScroll = (): void => {
Expand Down Expand Up @@ -373,6 +378,37 @@ export class TabNav {
return filterDirectChildren<HTMLCalciteTabTitleElement>(
this.el,
"calcite-tab-title:not([disabled])"
).filter((tabTitle) => !tabTitle.closed);
}

private handleTabTitleClose(closedTabTitleEl: HTMLCalciteTabTitleElement): void {
const { tabTitles } = this;

const visibleTabTitlesIndices = tabTitles.reduce(
(tabTitleIndices, tabTitle, index) =>
!tabTitle.closed ? [...tabTitleIndices, index] : tabTitleIndices,
[]
);
const totalVisibleTabTitles = visibleTabTitlesIndices.length;

if (totalVisibleTabTitles === 1 && tabTitles[visibleTabTitlesIndices[0]].closable) {
tabTitles[visibleTabTitlesIndices[0]].closable = false;
this.selectedTabId = visibleTabTitlesIndices[0];
} else if (totalVisibleTabTitles > 1) {
const closedTabTitleIndex = tabTitles.findIndex((el) => el === closedTabTitleEl);
const nextTabTitleIndex = visibleTabTitlesIndices.find(
(value) => value > closedTabTitleIndex
);

if (this.selectedTabId === closedTabTitleIndex) {
this.selectedTabId = nextTabTitleIndex ? nextTabTitleIndex : totalVisibleTabTitles - 1;
}
}

requestAnimationFrame(() => {
this.updateOffsetPosition();
this.updateActiveWidth();
tabTitles[this.selectedTabId].focus();
});
}
}
3 changes: 3 additions & 0 deletions src/components/tab-title/assets/tab-title/t9n/messages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Close"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "إغلاق"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Затваряне"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Zatvori"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Tanca"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Zavřít"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Luk"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Schließen"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Κλείσιμο"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Close"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Cerrar"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Sule"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Sulje"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Fermer"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "סגירה"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Zatvori"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Bezárás"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Tutup"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Chiudi"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "閉じる"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "닫기"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Uždaryti"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Aizvērt"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Sluiten"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Lukk"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Zamknij"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Fechar"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Fechar"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Închidere"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Закрыть"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Zatvoriť"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Zapri"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Zatvori"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Stäng"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "ปิด"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Kapat"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Закрити"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "Đóng"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "关闭"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "關閉"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"close": "關閉"
}
8 changes: 7 additions & 1 deletion src/components/tab-title/resources.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
export const CSS = {
closeButton: "close-button",
container: "container",
containerHasText: "container--has-text",
content: "content",
contentHasText: "content--has-text",
iconEnd: "icon-end",
iconStart: "icon-start",
iconPresent: "icon-present",
titleIcon: "calcite-tab-title--icon"
};

export const ICONS = {
close: "x"
};
Loading

0 comments on commit d30792d

Please sign in to comment.