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
@@ -0,0 +1,125 @@
import { Component } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { tb_base } from '../../../../test';
import { ItGapDirective, ItGapXDirective, ItGapYDirective } from './gap.directive';

@Component({
selector: 'it-test-gap0',
standalone: true,
imports: [ItGapDirective],
template: `<div [itGap]="0">content</div>`,
})
class Gap0Host {}

@Component({
selector: 'it-test-gap1',
standalone: true,
imports: [ItGapDirective],
template: `<div [itGap]="1">content</div>`,
})
class Gap1Host {}

@Component({
selector: 'it-test-gap3',
standalone: true,
imports: [ItGapDirective],
template: `<div [itGap]="3">content</div>`,
})
class Gap3Host {}

@Component({
selector: 'it-test-gap5',
standalone: true,
imports: [ItGapDirective],
template: `<div [itGap]="5">content</div>`,
})
class Gap5Host {}

@Component({
selector: 'it-test-gx2',
standalone: true,
imports: [ItGapXDirective],
template: `<div [itGapX]="2">content</div>`,
})
class GapX2Host {}

@Component({
selector: 'it-test-gy4',
standalone: true,
imports: [ItGapYDirective],
template: `<div [itGapY]="4">content</div>`,
})
class GapY4Host {}

@Component({
selector: 'it-test-combined',
standalone: true,
imports: [ItGapXDirective, ItGapYDirective],
template: `<div [itGapX]="2" [itGapY]="4">content</div>`,
})
class CombinedHost {}

describe('ItGapDirective', () => {
it('should apply gap: 0 for scale 0', () => {
TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap0Host] });
const fix = TestBed.createComponent(Gap0Host);
fix.detectChanges();
const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
expect(div.style.gap).toBe('0px');
});

it('should apply gap: 0.25rem for scale 1', () => {
TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap1Host] });
const fix = TestBed.createComponent(Gap1Host);
fix.detectChanges();
const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
expect(div.style.gap).toBe('0.25rem');
});

it('should apply gap: 1rem for scale 3', () => {
TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap3Host] });
const fix = TestBed.createComponent(Gap3Host);
fix.detectChanges();
const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
expect(div.style.gap).toBe('1rem');
});

it('should apply gap: 3rem for scale 5', () => {
TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap5Host] });
const fix = TestBed.createComponent(Gap5Host);
fix.detectChanges();
const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
expect(div.style.gap).toBe('3rem');
});
});

describe('ItGapXDirective', () => {
it('should apply column-gap: 0.5rem for scale 2', () => {
TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), GapX2Host] });
const fix = TestBed.createComponent(GapX2Host);
fix.detectChanges();
const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
expect(div.style.columnGap).toBe('0.5rem');
});
});

describe('ItGapYDirective', () => {
it('should apply row-gap: 1.5rem for scale 4', () => {
TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), GapY4Host] });
const fix = TestBed.createComponent(GapY4Host);
fix.detectChanges();
const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
expect(div.style.rowGap).toBe('1.5rem');
});
});

describe('ItGapX + ItGapY combined', () => {
it('should apply column-gap and row-gap independently', () => {
TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), CombinedHost] });
const fix = TestBed.createComponent(CombinedHost);
fix.detectChanges();
const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
expect(div.style.columnGap).toBe('0.5rem');
expect(div.style.rowGap).toBe('1.5rem');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Directive, HostBinding, Input } from '@angular/core';

/** Bootstrap Italia spacer scale (0-5). */
export type GapScale = 0 | 1 | 2 | 3 | 4 | 5;

/**
* Maps Bootstrap Italia spacer scale values (0-5) to their actual
* CSS sizes following the $spacer variable ($spacer = 1rem = 16px).
*/
const SPACER_MAP: Record<GapScale, string> = {
0: '0',
1: '0.25rem',
2: '0.5rem',
3: '1rem',
4: '1.5rem',
5: '3rem',
};

/**
* Directive that applies the CSS `gap` property to the host element.
*
* Bootstrap Italia's `.g-*` classes only set CSS variables consumed by `.row`.
* This directive applies real CSS `gap`, making it usable on any flex or grid container.
*
* @example
* ```html
* <div class="d-flex" [itGap]="3">...</div>
* ```
*/
@Directive({
selector: '[itGap]',
standalone: true,
})
export class ItGapDirective {
@Input('itGap') value: GapScale = 0;

@HostBinding('style.gap')
get gap(): string {
return SPACER_MAP[this.value] ?? '0';
}
}

/**
* Directive that applies the CSS `column-gap` property to the host element.
*
* @example
* ```html
* <div class="d-flex" [itGapX]="2">...</div>
* ```
*/
@Directive({
selector: '[itGapX]',
standalone: true,
})
export class ItGapXDirective {
@Input('itGapX') value: GapScale = 0;

@HostBinding('style.column-gap')
get columnGap(): string {
return SPACER_MAP[this.value] ?? '0';
}
}

/**
* Directive that applies the CSS `row-gap` property to the host element.
*
* @example
* ```html
* <div class="d-flex flex-wrap" [itGapY]="4">...</div>
* ```
*/
@Directive({
selector: '[itGapY]',
standalone: true,
})
export class ItGapYDirective {
@Input('itGapY') value: GapScale = 0;

@HostBinding('style.row-gap')
get rowGap(): string {
return SPACER_MAP[this.value] ?? '0';
}
}
1 change: 1 addition & 0 deletions projects/design-angular-kit/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export * from './lib/components/navigation/skiplink/skiplink/skiplink.component'
export * from './lib/components/utils/error-page/error-page.component';
export * from './lib/components/utils/icon/icon.component';
export * from './lib/components/utils/language-switcher/language-switcher.component';
export * from './lib/components/utils/gap/gap.directive';

// Services
export * from './lib/services/notification/notification.service';
Expand Down
Loading