feat(appui-tabs): add closeable tabs and auto-hide behavior for content tabs, plus API and events to control them
This commit is contained in:
@@ -33,6 +33,12 @@ export class DeesAppuiTabs extends DeesElement {
|
||||
@property({ type: String })
|
||||
accessor tabStyle: 'horizontal' | 'vertical' = 'horizontal';
|
||||
|
||||
@property({ type: Boolean })
|
||||
accessor autoHide: boolean = false;
|
||||
|
||||
@property({ type: Number })
|
||||
accessor autoHideThreshold: number = 0;
|
||||
|
||||
public static styles = [
|
||||
themeDefaultStyles,
|
||||
cssManager.defaultStyles,
|
||||
@@ -198,10 +204,50 @@ export class DeesAppuiTabs extends DeesElement {
|
||||
z-index: 1;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* Close button */
|
||||
.tab-close {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 4px;
|
||||
margin-left: 8px;
|
||||
opacity: 0.4;
|
||||
transition: opacity 0.15s, background 0.15s;
|
||||
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||
}
|
||||
|
||||
.tab:hover .tab-close {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.tab-close:hover {
|
||||
opacity: 1;
|
||||
background: ${cssManager.bdTheme('rgba(0,0,0,0.1)', 'rgba(255,255,255,0.1)')};
|
||||
color: ${cssManager.bdTheme('#ef4444', '#f87171')};
|
||||
}
|
||||
|
||||
.tab.selectedTab .tab-close {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.tab.selectedTab:hover .tab-close {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.tab.selectedTab .tab-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
// Auto-hide when enabled and tab count is at or below threshold
|
||||
if (this.autoHide && this.tabs.length <= this.autoHideThreshold) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
${this.renderTabsWrapper()}
|
||||
`;
|
||||
@@ -225,15 +271,23 @@ export class DeesAppuiTabs extends DeesElement {
|
||||
private renderTab(tab: interfaces.IMenuItem, isHorizontal: boolean): TemplateResult {
|
||||
const isSelected = tab === this.selectedTab;
|
||||
const classes = `tab ${isSelected ? 'selectedTab' : ''}`;
|
||||
|
||||
|
||||
const closeButton = tab.closeable ? html`
|
||||
<span class="tab-close" @click="${(e: Event) => this.closeTab(e, tab)}">
|
||||
<dees-icon .icon=${'lucide:x'} style="font-size: 12px;"></dees-icon>
|
||||
</span>
|
||||
` : '';
|
||||
|
||||
const content = isHorizontal ? html`
|
||||
<span class="tab-content">
|
||||
${this.renderTabIcon(tab)}
|
||||
${tab.key}
|
||||
</span>
|
||||
${closeButton}
|
||||
` : html`
|
||||
${this.renderTabIcon(tab)}
|
||||
${tab.key}
|
||||
${closeButton}
|
||||
`;
|
||||
|
||||
return html`
|
||||
@@ -253,7 +307,7 @@ export class DeesAppuiTabs extends DeesElement {
|
||||
private selectTab(tabArg: interfaces.IMenuItem) {
|
||||
this.selectedTab = tabArg;
|
||||
tabArg.action();
|
||||
|
||||
|
||||
// Emit tab-select event
|
||||
this.dispatchEvent(new CustomEvent('tab-select', {
|
||||
detail: { tab: tabArg },
|
||||
@@ -262,6 +316,22 @@ export class DeesAppuiTabs extends DeesElement {
|
||||
}));
|
||||
}
|
||||
|
||||
private closeTab(e: Event, tab: interfaces.IMenuItem) {
|
||||
e.stopPropagation(); // Don't select tab when closing
|
||||
|
||||
// Call the tab's onClose callback if defined
|
||||
if (tab.onClose) {
|
||||
tab.onClose();
|
||||
}
|
||||
|
||||
// Also emit event for parent components
|
||||
this.dispatchEvent(new CustomEvent('tab-close', {
|
||||
detail: { tab },
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
if (this.tabs && this.tabs.length > 0) {
|
||||
this.selectTab(this.tabs[0]);
|
||||
|
||||
Reference in New Issue
Block a user