Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
[class.row]="vertical"
[class.flex-row-reverse]="inverted && vertical"
[class.d-flex]="inverted && !vertical"
[class.flex-column-reverse]="inverted && !vertical">
[class.flex-column-reverse]="inverted && !vertical"
[class.h-100]="fullHeight && vertical"
[class.flex-grow-1]="fullHeight && !vertical">
<div
[class.col-5]="inverted && vertical"
[class.col-md-4]="inverted && vertical"
Expand All @@ -18,6 +20,7 @@
[class.auto]="auto"
[class.nav-tabs-icon-text]="iconText"
[class.nav-dark]="dark"
[class.h-100]="fullHeight && vertical"
role="tablist">
@for (tab of tabs; track tab.id; let i = $index) {
<li class="nav-item">
Expand Down Expand Up @@ -58,15 +61,19 @@
[class.col-md-8]="inverted && vertical"
[class.col-lg-9]="inverted && vertical"
[class.col-8]="!inverted && vertical"
[class.col-md-9]="!inverted && vertical">
[class.col-md-9]="!inverted && vertical"
[class.d-flex]="fullHeight"
[class.flex-column]="fullHeight"
[class.flex-grow-1]="fullHeight">
@if (tabs) {
<div class="tab-content">
<div class="tab-content" [class.flex-grow-1]="fullHeight" [class.d-flex]="fullHeight" [class.flex-column]="fullHeight">
@for (tab of tabs; track tab.id) {
<div
[id]="tab.id + '-tab'"
class="tab-pane p-4 fade {{ tab.class ?? '' }}"
[class.active]="tab.active"
[class.show]="tab.active"
[class.flex-grow-1]="fullHeight && tab.active"
role="tabpanel"
[attr.aria-labelledby]="tab.id + '-tab-link'">
<ng-container *ngTemplateOutlet="tab.htmlContent"></ng-container>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Component, ChangeDetectionStrategy } from '@angular/core';

import { ItTabContainerComponent } from './tab-container.component';
import { ItTabItemComponent } from '../tab-item/tab-item.component';
import { tb_base } from '../../../../../test';

@Component({
selector: 'it-test-fullheight-host',
standalone: true,
imports: [ItTabContainerComponent, ItTabItemComponent],
template: `
<div style="height:500px">
<it-tab-container [vertical]="true" [fullHeight]="true">
<it-tab-item label="Tab 1" [active]="true"><p>Content 1</p></it-tab-item>
<it-tab-item label="Tab 2"><p>Content 2</p></it-tab-item>
</it-tab-container>
</div>
`,
})
class FullHeightHostComponent {}

@Component({
selector: 'it-test-fullheight-horizontal-host',
standalone: true,
imports: [ItTabContainerComponent, ItTabItemComponent],
template: `
<div style="height:400px">
<it-tab-container [fullHeight]="true">
<it-tab-item label="Tab A" [active]="true"><p>Content A</p></it-tab-item>
<it-tab-item label="Tab B"><p>Content B</p></it-tab-item>
</it-tab-container>
</div>
`,
})
class FullHeightHorizontalHostComponent {}

describe('ItTabContainerComponent', () => {
let component: ItTabContainerComponent;
let fixture: ComponentFixture<ItTabContainerComponent>;
Expand All @@ -19,3 +51,102 @@ describe('ItTabContainerComponent', () => {
expect(component).toBeTruthy();
});
});

describe('ItTabContainerComponent fullHeight (vertical)', () => {
let fixture: ComponentFixture<FullHeightHostComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
...tb_base,
imports: [...tb_base.imports, FullHeightHostComponent],
})
.overrideComponent(ItTabContainerComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default },
})
.compileComponents();

fixture = TestBed.createComponent(FullHeightHostComponent);
fixture.detectChanges();
});

it('should apply height:100% on the host element', () => {
const host: HTMLElement = fixture.nativeElement.querySelector('it-tab-container');
expect(host.style.height).toBe('100%');
});

it('should apply d-flex class on the host element', () => {
const host: HTMLElement = fixture.nativeElement.querySelector('it-tab-container');
expect(host.classList.contains('d-flex')).toBeTrue();
});

it('should NOT apply flex-column on vertical layout host', () => {
const host: HTMLElement = fixture.nativeElement.querySelector('it-tab-container');
expect(host.classList.contains('flex-column')).toBeFalse();
});

it('should apply h-100 on the .row wrapper', () => {
const row: HTMLElement = fixture.nativeElement.querySelector('.row');
expect(row).toBeTruthy();
expect(row.classList.contains('h-100')).toBeTrue();
});

it('should apply h-100 on the nav-tabs-vertical ul', () => {
const ul: HTMLElement = fixture.nativeElement.querySelector('ul.nav-tabs-vertical');
expect(ul).toBeTruthy();
expect(ul.classList.contains('h-100')).toBeTrue();
});

it('should apply flex-grow-1 on the tab-content wrapper', () => {
const tabContent: HTMLElement = fixture.nativeElement.querySelector('.tab-content');
expect(tabContent).toBeTruthy();
expect(tabContent.classList.contains('flex-grow-1')).toBeTrue();
});

it('should apply flex-grow-1 on the active tab pane', () => {
const activePane: HTMLElement = fixture.nativeElement.querySelector('.tab-pane.active');
expect(activePane).toBeTruthy();
expect(activePane.classList.contains('flex-grow-1')).toBeTrue();
});
});

describe('ItTabContainerComponent fullHeight (horizontal)', () => {
let fixture: ComponentFixture<FullHeightHorizontalHostComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
...tb_base,
imports: [...tb_base.imports, FullHeightHorizontalHostComponent],
})
.overrideComponent(ItTabContainerComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default },
})
.compileComponents();

fixture = TestBed.createComponent(FullHeightHorizontalHostComponent);
fixture.detectChanges();
});

it('should apply height:100% on horizontal fullHeight host', () => {
const host: HTMLElement = fixture.nativeElement.querySelector('it-tab-container');
expect(host.style.height).toBe('100%');
});

it('should apply flex-column on horizontal fullHeight host', () => {
const host: HTMLElement = fixture.nativeElement.querySelector('it-tab-container');
expect(host.classList.contains('flex-column')).toBeTrue();
});

it('should apply flex-grow-1 on the outer wrapper div', () => {
const wrapper: HTMLElement = fixture.nativeElement.querySelector('it-tab-container > div');
expect(wrapper).toBeTruthy();
expect(wrapper.classList.contains('flex-grow-1')).toBeTrue();
});

it('should apply flex-grow-1 + d-flex + flex-column on tab-content', () => {
const tabContent: HTMLElement = fixture.nativeElement.querySelector('.tab-content');
expect(tabContent).toBeTruthy();
expect(tabContent.classList.contains('flex-grow-1')).toBeTrue();
expect(tabContent.classList.contains('d-flex')).toBeTrue();
expect(tabContent.classList.contains('flex-column')).toBeTrue();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ import { inputToBoolean } from '../../../../utils/coercion';
templateUrl: './tab-container.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ItIconComponent, NgTemplateOutlet],
host: {
'[class.d-flex]': 'fullHeight',
'[class.flex-column]': 'fullHeight && !vertical',
'[style.height]': 'fullHeight ? "100%" : null',
},
})
export class ItTabContainerComponent extends ItAbstractComponent implements OnDestroy, AfterViewInit {
/**
Expand Down Expand Up @@ -52,6 +57,13 @@ export class ItTabContainerComponent extends ItAbstractComponent implements OnDe
*/
@Input({ transform: inputToBoolean }) vertical?: boolean;

/**
* When used with vertical layout, makes the tab container
* occupy the full available vertical height.
* @default false
*/
@Input({ transform: inputToBoolean }) fullHeight?: boolean;

/**
* The tab position
*/
Expand Down
13 changes: 13 additions & 0 deletions src/app/tabs/tabs-examples/tabs-examples.component.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,16 @@

<it-source-display html="{$ sanitize(htmlDynamic) $}" typescript="{$ sanitize(typescriptDynamic) $}" >
</it-source-display>

{% set htmlFullHeight %}
{% include "../tabs-full-height-example/tabs-full-height-example.component.html" %}
{% endset %}

{% set typescriptFullHeight %}
{% include "../tabs-full-height-example/tabs-full-height-example.component.ts" %}
{% endset %}

<it-tabs-full-height-example></it-tabs-full-height-example>

<it-source-display html="{$ sanitize(htmlFullHeight) $}" typescript="{$ sanitize(typescriptFullHeight) $}" >
</it-source-display>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<h3>Full Height Tab</h3>
<p class="mb-4">
Con <code>[fullHeight]="true"</code> il tab container si espande per occupare il 100% dell'altezza del genitore. Utile quando le tab
devono riempire l'intero spazio disponibile.
</p>

<div style="height: 300px; border: 1px dashed #b1b1b3; padding: 8px">
<it-tab-container [fullHeight]="true">
<it-tab label="Pannello A" active>
<p>Questo contenuto si espande verticalmente per riempire il contenitore padre.</p>
</it-tab>
<it-tab label="Pannello B">
<p>Anche questo pannello occupa tutta l'altezza disponibile.</p>
</it-tab>
</it-tab-container>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Component } from '@angular/core';

@Component({
selector: 'it-tabs-full-height-example',
templateUrl: './tabs-full-height-example.component.html',
})
export class TabsFullHeightExampleComponent {}
9 changes: 8 additions & 1 deletion src/app/tabs/tabs.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@ import { TabsExampleComponent } from './tabs-example/tabs-example.component';
import { TabsExamplesComponent } from './tabs-examples/tabs-examples.component';
import { TabsIndexComponent } from './tabs-index/tabs-index.component';
import { TabsDynamicExampleComponent } from './tabs-dynamic-example/tabs-dynamic-example.component';
import { TabsFullHeightExampleComponent } from './tabs-full-height-example/tabs-full-height-example.component';

@NgModule({
imports: [CommonModule, FormsModule, ReactiveFormsModule, SharedModule, TabsRoutingModule],
declarations: [TabsExampleComponent, TabsExamplesComponent, TabsIndexComponent, TabsDynamicExampleComponent],
declarations: [
TabsExampleComponent,
TabsExamplesComponent,
TabsIndexComponent,
TabsDynamicExampleComponent,
TabsFullHeightExampleComponent,
],
})
export class TabsModule {}
Loading