Skip to content

Commit

Permalink
feat(stark-ui): implement collapsible feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Dedepon committed Sep 12, 2018
1 parent 7707acf commit 5e536bd
Show file tree
Hide file tree
Showing 28 changed files with 496 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/stark-ui/assets/styles/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ $backgrounds: (
status-bar: map_get($mat-grey, 300),
app-bar: map_get($mat-grey, 100),
background: #f6f9fa,
background-light: rgba(#000, 0.02),
hover: rgba(black, 0.04),
card: #fff,
dialog: #fff,
Expand Down
1 change: 1 addition & 0 deletions packages/stark-ui/src/modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from "./modules/action-bar";
export * from "./modules/app-logo";
export * from "./modules/app-logout";
export * from "./modules/breadcrumb";
export * from "./modules/collapsible";
export * from "./modules/app-sidebar";
export * from "./modules/keyboard-directives";
export * from "./modules/date-picker";
Expand Down
2 changes: 2 additions & 0 deletions packages/stark-ui/src/modules/collapsible.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./collapsible/collapsible.module";
export * from "./collapsible/components";
13 changes: 13 additions & 0 deletions packages/stark-ui/src/modules/collapsible/collapsible.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { NgModule } from "@angular/core";
import { StarkCollapsibleComponent } from "./components";
import { MatExpansionModule } from "@angular/material/expansion";
import { MatIconModule } from "@angular/material/icon";
import { CommonModule } from "@angular/common";
import { TranslateModule } from "@ngx-translate/core";

@NgModule({
declarations: [StarkCollapsibleComponent],
imports: [CommonModule, MatExpansionModule, MatIconModule, TranslateModule],
exports: [StarkCollapsibleComponent]
})
export class StarkCollapsibleModule {}
1 change: 1 addition & 0 deletions packages/stark-ui/src/modules/collapsible/components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./components/collapsible.component";
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* ============================================================================== */
/* S t a r k C o l l a p s i b l e - T h e m e */
/* ============================================================================== */
/* stark-ui: src/modules/collapsible/components/_collapsible-theme.scss */

.stark-collapsible {
.mat-expansion-panel {
box-shadow: $elevation-1;
&.mat-expanded {
box-shadow: $elevation-16;
}

.mat-expansion-panel-header {
border-bottom: 1px solid map-get($mat-light-theme-background, disabled-button);
background-color: map-get($mat-light-theme-background, background-light);
&:not(.mat-expanded) {
&:hover {
background-color: map-get($mat-light-theme-background, background-light);
}
}
&.mat-expanded {
background-color: map-get($mat-light-theme-background, card);
}
}

.mat-expansion-panel-body {
background-color: map-get($mat-light-theme-background, background-light);
}

.mat-expansion-panel-header-description {
color: mat-color(map-get($base-theme, primary-palette), 900);;
}

.mat-expansion-panel-header-title {
color: mat-color(map-get($base-theme, primary-palette), 500);
}

.stark-collapsible-icon {
color: mat-color(map-get($base-theme, primary-palette), 500);
}
}
}

/* END stark-ui: src/modules/collapsible/components/_collapsible-theme.scss */
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* ============================================================================== */
/* S t a r k C o l l a p s i b l e */
/* ============================================================================== */
/* stark-ui: packages/stark-ui/src/modules/collapsible/components/_collapsible.component.scss */

.stark-collapsible {
.mat-expansion-panel {
transition: box-shadow 150ms linear;

&.mat-expanded {
.mat-expansion-panel-header-title {
.stark-collapsible-icon {
&.spin {
transform: rotate(180deg);
}
}
}
}

.mat-expansion-panel-header {
padding-right: 0;
}

.mat-expansion-panel-body {
padding-top: 16px;
}

.mat-expansion-panel-header-title {
align-items: center;
.stark-collapsible-title {
font-size: mat-font-size($typography-config, subheading-1);
font-weight: mat-font-weight($typography-config, subheading-1);
line-height: mat-line-height($typography-config, subheading-1);
}
}

.stark-collapsible-icon {
transition: transform 150ms linear;
margin-right: 6px;
}
}
}

/* END stark-ui: packages/stark-ui/src/modules/collapsible/components/_collapsible.component.scss */
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<mat-expansion-panel class="stark-collapsible"
id="{{ htmlId }}"
[expanded]="isExpanded"
hideToggle>
<mat-expansion-panel-header
(click)="toggleCollapsible()">
<mat-panel-title>
<mat-icon [ngClass]="{ 'spin' : iconSpinningEnabled }" class="stark-collapsible-icon" starkSvgViewBox [svgIcon]="icon"></mat-icon>
<span class="stark-collapsible-title" translate>{{ titleLabel }}</span>
</mat-panel-title>
</mat-expansion-panel-header>

<ng-content></ng-content>
</mat-expansion-panel>
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*tslint:disable:completed-docs*/
import { NO_ERRORS_SCHEMA } from "@angular/core";
import { async, ComponentFixture, TestBed } from "@angular/core/testing";
import {
STARK_LOGGING_SERVICE
} from "@nationalbankbelgium/stark-core";
import { MockStarkLoggingService } from "@nationalbankbelgium/stark-core/testing";
import { StarkCollapsibleComponent } from "../components";

describe("CollapsibleComponent", () => {
let component: StarkCollapsibleComponent;
let fixture: ComponentFixture<StarkCollapsibleComponent>;

/**
* async beforeEach
*/
beforeEach(async(() => {
return (
TestBed.configureTestingModule({
imports: [],
declarations: [StarkCollapsibleComponent],
providers: [
{ provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }
],
schemas: [NO_ERRORS_SCHEMA] // tells the Angular compiler to ignore unrecognized elements and attributes (svgIcon)
})
/**
* Compile template and css
*/
.compileComponents()
);
}));

/**
* Synchronous beforeEach
*/
beforeEach(() => {
fixture = TestBed.createComponent(StarkCollapsibleComponent);
component = fixture.componentInstance;

// inputs
component.htmlId = "toto";
component.titleLabel = "titre";
component.iconSpinningEnabled = true;

fixture.detectChanges(); // trigger initial data binding
});

describe("on initialization", () => {
it("should set internal component properties", () => {
expect(fixture).toBeDefined();
expect(component).toBeDefined();

expect(component.logger).not.toBeNull();
expect(component.logger).toBeDefined();

expect(component.htmlId).not.toBeNull();
expect(component.htmlId).toBeDefined();
expect(component.htmlId).toBe("toto");

expect(component.isExpanded).not.toBeNull();
expect(component.isExpanded).toBeDefined();
expect(component.isExpanded).toBe(false);

expect(component.titleLabel).not.toBeNull();
expect(component.titleLabel).toBeDefined();
expect(component.titleLabel).toBe("titre");

expect(component.iconSpinningEnabled).not.toBeNull();
expect(component.iconSpinningEnabled).toBeDefined();
expect(component.iconSpinningEnabled).toBe(true);
});

});

describe("@Input()", () => {
it("should have modified the view accordingly", () => {
const actionBar: HTMLElement = fixture.nativeElement.querySelector("#" + component.htmlId);
expect(actionBar).toBeDefined();

const matIcon: HTMLElement = fixture.nativeElement.querySelector("mat-icon");
expect(matIcon.className).toContain("spin");
});
});

describe("toggleCollapsible()", () => {
it("should change the isExpanded value and send it as output", () => {
const exp: boolean = component.isExpanded;

// Test output
component.isExpandedChange.subscribe((value: boolean) => {
expect(value).toBe(!exp);
});

component.toggleCollapsible();

expect(component.isExpanded).toBe(!exp);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Component, EventEmitter, HostBinding, Inject, Input, OnInit, Output } from "@angular/core";
import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core";

/**
* Name of the component
*/
const componentName: string = "stark-collapsible";

/**
* Component to display an accordion around included html using angular material's expansion panel.
*/
@Component({
selector: "stark-collapsible",
templateUrl: "./collapsible.component.html"
})
export class StarkCollapsibleComponent implements OnInit {
/**
* Adds class="stark-app-logo" attribute on the host component
*/
@HostBinding("class")
public class: string = componentName;

/**
* ID to set to the collapsible
*/
@Input()
public htmlId: string;

/**
* Icon to use in the header (based on Material Design Icons)
*/
@Input()
public icon: "chevron-right" | string = "chevron-right";

/**
* Boolean value triggering the collapsing of the collapsible
*/
@Input()
public isExpanded: boolean = false;

/**
* Output value giving the collapse state of the collapsible
*/
@Output()
public isExpandedChange: EventEmitter<boolean> = new EventEmitter();

/**
* String or translation key that will be displayed in the title part of the header.
*/
@Input()
public titleLabel: string;

/**
* Design options related to the component
*/
@Input()
public iconSpinningEnabled: boolean = false;

/**
* Class constructor
* @param logger - The logger of the application
*/
public constructor(@Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService) {
// empty constructor
}

/**
* Component lifecycle hook
*/
public ngOnInit(): void {
this.logger.debug(componentName + ": component initialized");
}

/**
* Switch and triggers the dispatch of the collapse state information.
*/
public toggleCollapsible(): void {
this.isExpanded = !this.isExpanded;
this.isExpandedChange.emit(this.isExpanded);
}
}
3 changes: 3 additions & 0 deletions showcase/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
<a mat-list-item uiSref="demo-button" uiSrefActive="active">
<span matLine>Button</span>
</a>
<a mat-list-item uiSref="demo-collapsible" uiSrefActive="active">
<span matLine>Collapsible</span>
</a>
<a mat-list-item uiSref="demo-date-picker" uiSrefActive="active">
<span matLine>Date Picker</span>
</a>
Expand Down
6 changes: 4 additions & 2 deletions showcase/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
ExampleViewerComponent,
HeaderComponent,
KeyboardDirectivesComponent,
LogoutComponent,
DemoPrettyPrintComponent,
SliderComponent,
TableComponent,
LogoutComponent,
SliderComponent,
DemoCollapsibleComponent,
DemoTypographyComponent
} from "./demo";
import { HomeComponent } from "./home";
Expand All @@ -26,6 +27,7 @@ export const APP_STATES: Ng2StateDeclaration[] = [
{ name: "demo-action-bar", url: "/demo/action-bar", component: ActionBarComponent },
{ name: "demo-breadcrumb", url: "/demo/breadcrumb", component: DemoBreadcrumbComponent },
{ name: "demo-button", url: "/demo/button", component: ButtonComponent },
{ name: "demo-collapsible", url: "/demo/collapsible", component: DemoCollapsibleComponent },
{ name: "demo-date-picker", url: "/demo/date-picker", component: DatePickerComponent },
{ name: "demo-date-range-picker", url: "/demo/date-range-picker", component: DateRangePickerComponent },
{ name: "stark-header", url: "/demo/stark-header", component: HeaderComponent },
Expand Down
43 changes: 43 additions & 0 deletions showcase/src/app/demo/collapsible/demo-collapsible.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<example-viewer [extensions]="['HTML', 'CSS', 'TS']" filesPath="collapsible/collapsible-default" exampleTitle="SHOWCASE.DEMO.COLLAPSIBLE.DEFAULT_ICON">
<stark-collapsible
htmlId="firstCollapsible"
titleLabel="SHOWCASE.DEMO.COLLAPSIBLE.TITLE_0"
[(isExpanded)]="collapsed[0]"
>
{{ 'SHOWCASE.DEMO.COLLAPSIBLE.HTML_CONTENT' | translate }}
</stark-collapsible>
<button color="primary" class="collapsible-demo-button" (click)="toggleCollapsible(0)" mat-raised-button>{{ 'SHOWCASE.DEMO.COLLAPSIBLE.TOGGLE_COLLAPSIBLE' | translate }}</button>
</example-viewer>

<example-viewer [extensions]="['HTML', 'CSS', 'TS']" filesPath="collapsible/collapsible-custom" exampleTitle="SHOWCASE.DEMO.COLLAPSIBLE.CUSTOM_ICON">
<stark-collapsible
htmlId="secondCollapsible"
titleLabel="SHOWCASE.DEMO.COLLAPSIBLE.TITLE_1"
[(isExpanded)]="collapsed[1]"
[iconSpinningEnabled]="true"
icon="chevron-down"
>
{{ 'SHOWCASE.DEMO.COLLAPSIBLE.HTML_CONTENT' | translate }}
</stark-collapsible>
<button color="primary" class="collapsible-demo-button" (click)="toggleCollapsible(1)" mat-raised-button>{{ 'SHOWCASE.DEMO.COLLAPSIBLE.TOGGLE_COLLAPSIBLE' | translate }}</button>
<hr class="collapsible-demo-line">
<stark-collapsible
htmlId="thirdCollapsible"
titleLabel="SHOWCASE.DEMO.COLLAPSIBLE.TITLE_1"
[(isExpanded)]="collapsed[2]"
icon="information"
>
{{ 'SHOWCASE.DEMO.COLLAPSIBLE.HTML_CONTENT' | translate }}
</stark-collapsible>
<button color="primary" class="collapsible-demo-button" (click)="toggleCollapsible(2)" mat-raised-button>{{ 'SHOWCASE.DEMO.COLLAPSIBLE.TOGGLE_COLLAPSIBLE' | translate }}</button>
<hr class="collapsible-demo-line">
<stark-collapsible
htmlId="fourthCollapsible"
titleLabel="SHOWCASE.DEMO.COLLAPSIBLE.TITLE_1"
[(isExpanded)]="collapsed[3]"
icon="account-circle"
>
{{ 'SHOWCASE.DEMO.COLLAPSIBLE.HTML_CONTENT' | translate }}
</stark-collapsible>
<button color="primary" class="collapsible-demo-button" (click)="toggleCollapsible(3)" mat-raised-button>{{ 'SHOWCASE.DEMO.COLLAPSIBLE.TOGGLE_COLLAPSIBLE' | translate }}</button>
</example-viewer>
Loading

0 comments on commit 5e536bd

Please sign in to comment.