diff --git a/packages/stark-build/config/tslint.json b/packages/stark-build/config/tslint.json
index f552ee820b..dde0b96445 100644
--- a/packages/stark-build/config/tslint.json
+++ b/packages/stark-build/config/tslint.json
@@ -34,7 +34,7 @@
"use-view-encapsulation": false,
"trackBy-function": true,
"no-unused-css": true,
- "template-cyclomatic-complexity": [true, 5],
+ "template-cyclomatic-complexity": [true, 10],
"template-conditional-complexity": [true, 4],
// TSlint rules
diff --git a/packages/stark-core/src/common/translations/translations/en.ts b/packages/stark-core/src/common/translations/translations/en.ts
index b5126abc35..8b9465e74e 100644
--- a/packages/stark-core/src/common/translations/translations/en.ts
+++ b/packages/stark-core/src/common/translations/translations/en.ts
@@ -12,6 +12,21 @@ export const translationsEn: object = {
SORTING: {
ASC: "Ascending",
DESC: "Descending"
+ },
+ ICONS: {
+ ADD_ITEM: "Add",
+ EDIT_ITEM: "Edit",
+ DELETE_ITEM: "Delete",
+ APPROVE_ITEM: "Approve",
+ REJECT_ITEM: "Reject",
+ RELOAD_PAGE: "Reload page",
+ OPEN_SELECTION: "Open selection",
+ SAVE_ITEM: "Save",
+ CLOSE_ITEM: "Close",
+ RESET: "Reset",
+ SEARCH: "Search",
+ NEW_ITEM: "New",
+ SAVE_AND_NEXT: "Save And Next"
}
}
};
diff --git a/packages/stark-core/src/common/translations/translations/fr.ts b/packages/stark-core/src/common/translations/translations/fr.ts
index af7cd26f36..22aa4fa42f 100644
--- a/packages/stark-core/src/common/translations/translations/fr.ts
+++ b/packages/stark-core/src/common/translations/translations/fr.ts
@@ -12,6 +12,21 @@ export const translationsFr: object = {
SORTING: {
ASC: "Ascendant",
DESC: "Descendant"
+ },
+ ICONS: {
+ ADD_ITEM: "Ajouter",
+ EDIT_ITEM: "Modifier",
+ DELETE_ITEM: "Supprimer",
+ APPROVE_ITEM: "Approuver",
+ REJECT_ITEM: "Rejeter",
+ RELOAD_PAGE: "Recharger la page",
+ OPEN_SELECTION: "Ouvrir la sélection",
+ SAVE_ITEM: "Sauver",
+ CLOSE_ITEM: "Fermer",
+ RESET: "Réinitialiser",
+ SEARCH: "Chercher",
+ NEW_ITEM: "Nouveau",
+ SAVE_AND_NEXT: "Sauver et Suivant"
}
}
};
diff --git a/packages/stark-core/src/common/translations/translations/nl.ts b/packages/stark-core/src/common/translations/translations/nl.ts
index afdff31cdf..515cf6cc71 100644
--- a/packages/stark-core/src/common/translations/translations/nl.ts
+++ b/packages/stark-core/src/common/translations/translations/nl.ts
@@ -12,6 +12,21 @@ export const translationsNl: object = {
SORTING: {
ASC: "Oplopend",
DESC: "Aflopend"
+ },
+ ICONS: {
+ ADD_ITEM: "Toevoegen",
+ EDIT_ITEM: "Wijzig",
+ DELETE_ITEM: "Verwijder",
+ APPROVE_ITEM: "Goedkeuren",
+ REJECT_ITEM: "Afkeuren",
+ RELOAD_PAGE: "Pagina vernieuwen",
+ OPEN_SELECTION: "Open selectie",
+ SAVE_ITEM: "Bewaren",
+ CLOSE_ITEM: "Sluiten",
+ RESET: "Reset",
+ SEARCH: "Zoeken",
+ NEW_ITEM: "Nieuw",
+ SAVE_AND_NEXT: "Bewaar en volgende"
}
}
};
diff --git a/packages/stark-ui/assets/styles/_base.scss b/packages/stark-ui/assets/styles/_base.scss
index acb8adff8b..a0ac789468 100644
--- a/packages/stark-ui/assets/styles/_base.scss
+++ b/packages/stark-ui/assets/styles/_base.scss
@@ -27,11 +27,6 @@
}
@media screen {
- html,
- body {
- overflow: hidden;
- }
-
.stark-app {
display: flex;
flex-direction: column;
@@ -68,6 +63,7 @@ body {
/* system sans-serif font stack */
font-family: mat-font-family($typography-config);
font-size: mat-font-size($typography-config, body-1);
+ line-height: mat-line-height($typography-config, body-1);
}
h1,
diff --git a/packages/stark-ui/assets/styles/_colors.scss b/packages/stark-ui/assets/styles/_colors.scss
index 55985ccbb3..4e4c9a65dd 100644
--- a/packages/stark-ui/assets/styles/_colors.scss
+++ b/packages/stark-ui/assets/styles/_colors.scss
@@ -1,10 +1,16 @@
$mat-light-theme-background: $backgrounds;
+$mat-light-theme-foreground: $foregrounds;
@if variable-exists(stark-base-theme) {
$base-theme: map-merge($base-theme, $stark-base-theme);
+
@if map-has-key($stark-base-theme, backgrounds) {
$mat-light-theme-background: map-merge($backgrounds, map-get($stark-base-theme, backgrounds));
}
+
+ @if map-has-key($stark-base-theme, foregrounds) {
+ $mat-light-theme-foreground: map-merge($foregrounds, map-get($stark-base-theme, foregrounds));
+ }
}
$stark-color-theme: mat-light-theme(
diff --git a/packages/stark-ui/assets/styles/_media-queries.scss b/packages/stark-ui/assets/styles/_media-queries.scss
new file mode 100644
index 0000000000..d873cb087b
--- /dev/null
+++ b/packages/stark-ui/assets/styles/_media-queries.scss
@@ -0,0 +1,8 @@
+$tablet-query: "(min-width: 600px)";
+$tablet-screen-query: "screen and (min-width: 600px)";
+$desktop-query: "(min-width: 960px)";
+$desktop-screen-query: "screen and (min-width: 960px)";
+$mobile-only-query: "(max-width: 599px)";
+$mobile-only-screen-query: "screen and (max-width: 599px)";
+$tablet-only-query: "(min-width: 600px) and (max-width: 959px)";
+$tablet-only-screen-query: "screen and (min-width: 600px) and (max-width: 959px)";
diff --git a/packages/stark-ui/assets/styles/_old-variables.scss b/packages/stark-ui/assets/styles/_old-variables.scss
index 6f255401ed..8aa7c5c32d 100644
--- a/packages/stark-ui/assets/styles/_old-variables.scss
+++ b/packages/stark-ui/assets/styles/_old-variables.scss
@@ -1,13 +1,3 @@
-// Old Stark vars
-$tablet-query: "(min-width: 600px)";
-$tablet-screen-query: "screen and (min-width: 600px)";
-$desktop-query: "(min-width: 960px)";
-$desktop-screen-query: "screen and (min-width: 960px)";
-$mobile-only-query: "(max-width: 599px)";
-$mobile-only-screen-query: "screen and (max-width: 599px)";
-$tablet-only-query: "(min-width: 600px) and (max-width: 959px)";
-$tablet-only-screen-query: "screen and (min-width: 600px) and (max-width: 959px)";
-
$elevation-1: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12);
$elevation-2: 0 1px 5px 0 rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12);
$elevation-3: 0 1px 8px 0 rgba(0, 0, 0, 0.2), 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.12);
diff --git a/packages/stark-ui/assets/styles/_typography.scss b/packages/stark-ui/assets/styles/_typography.scss
index 7d3ca25b3e..c41a41273d 100644
--- a/packages/stark-ui/assets/styles/_typography.scss
+++ b/packages/stark-ui/assets/styles/_typography.scss
@@ -15,7 +15,7 @@ $typography-config: mat-typography-config(
$display-1: mat-typography-level-create(map-get($typography-theme, display-1)),
$headline: mat-typography-level-create(map-get($typography-theme, headline)),
$title: mat-typography-level-create(map-get($typography-theme, title)),
- $subheading-2: mat-typography-level-create(map-get($typography-theme, subheading-2)),
+ $subheading-2: mat-typography-level-create(map-get($typography-theme, subheading-2)), /*Menu, List, Option*/
$subheading-1: mat-typography-level-create(map-get($typography-theme, subheading-1)),
$body-2: mat-typography-level-create(map-get($typography-theme, body-2)),
$body-1: mat-typography-level-create(map-get($typography-theme, body-1)),
diff --git a/packages/stark-ui/assets/styles/_variables.scss b/packages/stark-ui/assets/styles/_variables.scss
index bade1756f1..350d518358 100644
--- a/packages/stark-ui/assets/styles/_variables.scss
+++ b/packages/stark-ui/assets/styles/_variables.scss
@@ -200,9 +200,9 @@ $typography-theme: (
500
),
subheading-2: (
+ 13px,
16px,
- 28px,
- 400
+ 500
),
subheading-1: (
15px,
diff --git a/packages/stark-ui/assets/themes/_button-theme.scss b/packages/stark-ui/assets/themes/_button-theme.scss
index 395cdb19de..5b69bbb690 100644
--- a/packages/stark-ui/assets/themes/_button-theme.scss
+++ b/packages/stark-ui/assets/themes/_button-theme.scss
@@ -1,3 +1,13 @@
+@mixin stark-button-color($color) {
+ color: $color;
+ .mat-button-focus-overlay {
+ background-color: rgba($color: $color, $alpha: 0.12);
+ }
+ .mat-ripple-element {
+ background-color: rgba($color: $color, $alpha: 0.1);
+ }
+}
+
@if variable-exists(stark-button-theme) {
$button-theme: map-merge($button-theme, $stark-button-theme);
}
diff --git a/packages/stark-ui/assets/themes/_menu-theme.scss b/packages/stark-ui/assets/themes/_menu-theme.scss
new file mode 100644
index 0000000000..92a70a47f2
--- /dev/null
+++ b/packages/stark-ui/assets/themes/_menu-theme.scss
@@ -0,0 +1,13 @@
+.mat-menu-content .mat-menu-item {
+ color: mat-color(map-get($base-theme, primary-palette));
+ .mat-icon {
+ color: inherit;
+ svg {
+ height: 20px;
+ width: 20px;
+ }
+ }
+ &[disabled] {
+ color: map-get($mat-light-theme-foreground, disabled-button);
+ }
+}
diff --git a/packages/stark-ui/assets/themes/_theming.scss b/packages/stark-ui/assets/themes/_theming.scss
index 8367343cbc..cb901bf3a0 100644
--- a/packages/stark-ui/assets/themes/_theming.scss
+++ b/packages/stark-ui/assets/themes/_theming.scss
@@ -4,5 +4,6 @@
@import "../styles/variables";
@import "../styles/colors";
@import "../styles/typography";
+@import "../styles/media-queries";
@import "../styles/old-variables";
@import "../styles/base";
diff --git a/packages/stark-ui/src/modules.ts b/packages/stark-ui/src/modules.ts
index 597277f3c7..d191c9ebfa 100644
--- a/packages/stark-ui/src/modules.ts
+++ b/packages/stark-ui/src/modules.ts
@@ -1,3 +1,4 @@
+export * from "./modules/action-bar";
export * from "./modules/app-logo";
export * from "./modules/slider";
export * from "./modules/svg-view-box";
diff --git a/packages/stark-ui/src/modules/action-bar.ts b/packages/stark-ui/src/modules/action-bar.ts
new file mode 100644
index 0000000000..01c7f68707
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar.ts
@@ -0,0 +1,2 @@
+export * from "./action-bar/action-bar.module";
+export * from "./action-bar/components";
diff --git a/packages/stark-ui/src/modules/action-bar/action-bar.module.ts b/packages/stark-ui/src/modules/action-bar/action-bar.module.ts
new file mode 100644
index 0000000000..2df8152ed7
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/action-bar.module.ts
@@ -0,0 +1,13 @@
+import { NgModule } from "@angular/core";
+import { BrowserModule } from "@angular/platform-browser";
+import { MatButtonModule, MatIconModule, MatMenuModule, MatTooltipModule } from "@angular/material";
+import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module";
+import { StarkActionBarComponent } from "./components";
+import { TranslateModule } from "@ngx-translate/core";
+
+@NgModule({
+ declarations: [StarkActionBarComponent],
+ imports: [BrowserModule, StarkSvgViewBoxModule, MatButtonModule, MatIconModule, MatMenuModule, MatTooltipModule, TranslateModule],
+ exports: [StarkActionBarComponent]
+})
+export class StarkActionBarModule {}
diff --git a/packages/stark-ui/src/modules/action-bar/components.ts b/packages/stark-ui/src/modules/action-bar/components.ts
new file mode 100644
index 0000000000..0e897e2847
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components.ts
@@ -0,0 +1,3 @@
+export * from "./components/action-bar.component";
+export * from "./components/action.intf";
+export * from "./components/action-bar-config.intf";
diff --git a/packages/stark-ui/src/modules/action-bar/components/_action-bar-theme.scss b/packages/stark-ui/src/modules/action-bar/components/_action-bar-theme.scss
new file mode 100644
index 0000000000..632674297f
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components/_action-bar-theme.scss
@@ -0,0 +1,38 @@
+.stark-action-bar {
+ .mat-icon-button {
+ @include stark-button-color(mat-color(map-get($base-theme, primary-palette)));
+ }
+ &.stark-action-bar-full {
+ background-color: rgba(0, 0, 0, 0.85);
+ color: rgba(255, 255, 255, 0.8);
+ .mat-icon-button {
+ @include stark-button-color(rgba($color: #fff, $alpha: 0.8));
+ }
+ .action-label {
+ &.disabled {
+ color: rgba($color: #fff, $alpha: 0.25);
+ }
+ }
+ }
+}
+
+@media #{$tablet-query} {
+ .stark-action-bar {
+ color: $md-primary;
+ &.stark-action-bar-full {
+ background: none;
+ color: mat-color(map-get($base-theme, primary-palette));
+ .mat-icon-button:not([disabled]) {
+ @include stark-button-color(mat-color(map-get($base-theme, primary-palette)));
+ }
+ [disabled].mat-icon-button {
+ @include stark-button-color(map-get($mat-light-theme-foreground, disabled-button));
+ }
+ .action-label {
+ &.disabled {
+ color: map-get($mat-light-theme-foreground, disabled-button);
+ }
+ }
+ }
+ }
+}
diff --git a/packages/stark-ui/src/modules/action-bar/components/_action-bar.component.scss b/packages/stark-ui/src/modules/action-bar/components/_action-bar.component.scss
new file mode 100644
index 0000000000..ba878ad4e2
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components/_action-bar.component.scss
@@ -0,0 +1,62 @@
+.stark-action-bar {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ max-height: 40px;
+ overflow: hidden;
+ transform-origin: bottom;
+ .action-bar-wrapper {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ }
+ .mat-icon-button {
+ .mat-icon svg {
+ height: 20px;
+ width: 20px;
+ }
+ }
+ &.stark-action-bar-full {
+ bottom: 0;
+ left: 0;
+ margin-bottom: 0;
+ padding: 4px 0;
+ position: fixed;
+ right: 0;
+ z-index: 4;
+ &.extended {
+ transition: 0.3s ease;
+ height: auto;
+ max-height: 280px;
+ overflow-y: scroll;
+ .action-bar-wrapper {
+ display: flex;
+ align-items: flex-start;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ }
+ }
+ .action-label {
+ font-size: 13px;
+ padding-left: 15px;
+ }
+ }
+}
+
+@media #{$tablet-query} {
+ .stark-action-bar {
+ position: relative;
+ height: auto;
+ transition: 0.7s ease;
+ &.stark-action-bar-full {
+ position: relative;
+ &.extended {
+ max-height: 900px;
+ }
+ }
+ }
+ .stark-action-bar-compact {
+ flex-wrap: nowrap;
+ padding: 0;
+ }
+}
diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar-config.intf.ts b/packages/stark-ui/src/modules/action-bar/components/action-bar-config.intf.ts
new file mode 100644
index 0000000000..42bcbc4de0
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components/action-bar-config.intf.ts
@@ -0,0 +1,16 @@
+import { StarkAction } from "./action.intf";
+
+/**
+ * Stark Action interface
+ */
+export interface StarkActionBarConfig {
+ /**
+ * Array of actions (StarkAction config objects) to be included in the action bar
+ */
+ actions: StarkAction[];
+
+ /**
+ * If false, then action bar will not be present on the page (optional)
+ */
+ isPresent?: boolean;
+}
diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar.component.html b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.html
new file mode 100644
index 0000000000..302a86080e
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ action.label }}
+
+
+
+
+
+
diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar.component.spec.ts b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.spec.ts
new file mode 100644
index 0000000000..1e4834e0cc
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.spec.ts
@@ -0,0 +1,131 @@
+import { NO_ERRORS_SCHEMA } from "@angular/core";
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
+import { MatButtonModule, MatMenuModule, MatTooltipModule } from "@angular/material";
+import { STARK_LOGGING_SERVICE, STARK_ROUTING_SERVICE } from "@nationalbankbelgium/stark-core";
+import { MockStarkLoggingService, MockStarkRoutingService } from "@nationalbankbelgium/stark-core/testing";
+import { StarkSvgViewBoxModule } from "../../svg-view-box/svg-view-box.module";
+import { StarkActionBarComponent } from "./action-bar.component";
+import { StarkActionBarConfig } from "./action-bar-config.intf";
+import { StarkAction } from "./action.intf";
+import { TranslateModule, TranslateService } from "@ngx-translate/core";
+import createSpy = jasmine.createSpy;
+
+describe("ActionBarComponent", () => {
+ let fixture: ComponentFixture;
+ let component: StarkActionBarComponent;
+ const buttonToggleSelector: string = ".extend-action-bar";
+
+ beforeEach(async(() => {
+ return TestBed.configureTestingModule({
+ declarations: [StarkActionBarComponent],
+ imports: [StarkSvgViewBoxModule, MatButtonModule, MatMenuModule, MatTooltipModule, TranslateModule.forRoot()],
+ providers: [
+ { provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() },
+ { provide: STARK_ROUTING_SERVICE, useClass: MockStarkRoutingService },
+ TranslateService
+ ],
+ schemas: [NO_ERRORS_SCHEMA] // tells the Angular compiler to ignore unrecognized elements and attributes (svgIcon)
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StarkActionBarComponent);
+ component = fixture.componentInstance;
+ const demoActions: StarkAction[] = [
+ {
+ id: "userDetailValidate",
+ label: "Validate",
+ icon: "check",
+ actionCall: createSpy("actionCallSpy"),
+ isEnabled: false,
+ isVisible: true
+ },
+ {
+ id: "userDetailSave",
+ label: "Save",
+ icon: "content-save",
+ actionCall: createSpy("actionCallSpy"),
+ isEnabled: true,
+ isVisible: true
+ }
+ ];
+
+ const demoActionBarConfig: StarkActionBarConfig = {
+ actions: demoActions,
+ isPresent: true
+ };
+
+ component.actionBarConfig = demoActionBarConfig;
+ fixture.detectChanges();
+ });
+
+ describe("@Input() mode", () => {
+ it("should have the toggle action bar button visible in full mode", () => {
+ component.mode = "full";
+ fixture.detectChanges();
+ const buttonToggleExtend: HTMLElement = fixture.nativeElement.querySelector(buttonToggleSelector);
+ expect(buttonToggleExtend).toBeDefined();
+ });
+
+ it("should not have the toggle action bar button visible in compact mode", () => {
+ component.mode = "compact";
+ fixture.detectChanges();
+ const buttonToggleExtend: HTMLElement = fixture.nativeElement.querySelector(buttonToggleSelector);
+ expect(buttonToggleExtend).toBeNull();
+ });
+ });
+
+ describe("@Input() actionBarId", () => {
+ it("should have set the id of the action bar", () => {
+ component.actionBarId = "action-bar-id";
+ fixture.detectChanges();
+ const actionBar: HTMLElement = fixture.nativeElement.querySelector("#" + component.actionBarId);
+ expect(actionBar).toBeDefined();
+ });
+ });
+
+ describe("@Input() actionBarConfig", () => {
+ it("should not call the defined action when disabled", () => {
+ const menuItem: HTMLElement = fixture.nativeElement.querySelector(
+ "#" + component.actionBarId + "-" + component.actionBarConfig.actions[0].id
+ );
+ menuItem.click();
+ expect(component.actionBarConfig.actions[0].actionCall).not.toHaveBeenCalled();
+ });
+
+ it("should call the defined action when enabled", () => {
+ const menuItem: HTMLElement = fixture.nativeElement.querySelector(
+ "#" + component.actionBarId + "-" + component.actionBarConfig.actions[1].id
+ );
+ menuItem.click();
+ expect(component.actionBarConfig.actions[1].actionCall).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe("@Input() alternativeActions", () => {
+ beforeEach(() => {
+ component.alternativeActions = component.actionBarConfig.actions;
+ fixture.detectChanges();
+ });
+
+ it("should display", () => {
+ const actionBar: HTMLElement = fixture.nativeElement.querySelector(".open-alt-actions");
+ expect(actionBar).toBeDefined();
+ });
+ });
+
+ describe("toggle extended action bar", () => {
+ it("should toggle the action bar extension", () => {
+ const buttonToggleExtend: HTMLElement = fixture.nativeElement.querySelector(buttonToggleSelector);
+ spyOn(component, "toggleExtendedActionBar").and.callThrough();
+ buttonToggleExtend.click();
+ fixture.detectChanges();
+ expect(component.toggleExtendedActionBar).toHaveBeenCalledTimes(1);
+ expect(component.isExtended).toBe(true);
+ buttonToggleExtend.click();
+ fixture.detectChanges();
+ expect(component.toggleExtendedActionBar).toHaveBeenCalledTimes(2);
+ expect(component.isExtended).toBe(false);
+ });
+ });
+});
diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar.component.ts b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.ts
new file mode 100644
index 0000000000..cfb7d1dcd3
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.ts
@@ -0,0 +1,74 @@
+import { Component, ViewEncapsulation, Input } from "@angular/core";
+import { StarkActionBarConfig } from "./action-bar-config.intf";
+import { StarkAction } from "./action.intf";
+
+export type StarkActionBarComponentMode = "full" | "compact";
+
+/**
+ * Component to display the application's action bars
+ */
+@Component({
+ selector: "stark-action-bar",
+ templateUrl: "./action-bar.component.html",
+ encapsulation: ViewEncapsulation.None
+})
+export class StarkActionBarComponent {
+ /**
+ * HTML id of action bar component.
+ */
+ @Input() public actionBarId: string = "";
+
+ /**
+ * StarkActionBarConfig object.
+ */
+ @Input() public actionBarConfig: StarkActionBarConfig;
+
+ /**
+ * HTML id of action bar component.
+ */
+ @Input() public actionBarScope: any;
+
+ /**
+ * Alternative actions
+ */
+ @Input() public alternativeActions: StarkAction[];
+
+ /**
+ * Desired layout or flavour:
+ * - full: full featured action bar with labels, expanded view, etc...
+ * - compact: minimalistic layout with icons only.
+ */
+ @Input() public mode: StarkActionBarComponentMode = "full";
+
+ /**
+ * status of the extended action in full mode
+ */
+ public isExtended: boolean = false;
+
+ /**
+ * toggle the extended action in full mode
+ */
+ public toggleExtendedActionBar(): void {
+ this.isExtended = !this.isExtended;
+ }
+
+ /**
+ * Action onClick handler
+ */
+ public onClick(action: StarkAction, $event: Event): void {
+ if (action.isEnabled) {
+ let scope: any = {};
+ if (this.actionBarScope) {
+ scope = this.actionBarScope;
+ }
+ action.actionCall($event, scope);
+ }
+ }
+
+ /**
+ * @ignore
+ */
+ public trackAction(_index: number, action: StarkAction): string {
+ return action.id;
+ }
+}
diff --git a/packages/stark-ui/src/modules/action-bar/components/action.intf.ts b/packages/stark-ui/src/modules/action-bar/components/action.intf.ts
new file mode 100644
index 0000000000..fd7593e1c5
--- /dev/null
+++ b/packages/stark-ui/src/modules/action-bar/components/action.intf.ts
@@ -0,0 +1,94 @@
+/**
+ * Stark Action Base interface
+ */
+export interface StarkActionBase {
+ /**
+ * Path to SVG icon from iconSets to display inside the action button. Ex: "pencil" (optional)
+ */
+ icon?: string;
+
+ /**
+ * Text to be displayed as label of the action button (optional)
+ */
+ label?: string;
+
+ /**
+ * The second label if this action has two possible states: activated and deactivated (optional)
+ */
+ labelActivated?: string;
+
+ /**
+ * In case of two label states, this function will hide one of them or show another (optional)
+ */
+ labelSwitchFunction?: () => boolean;
+
+ /**
+ * Whether the action button should be enabled for user interaction or not (optional)
+ */
+ isEnabled?: boolean;
+
+ /**
+ * The second icon if this action has two possible states: activated and deactivated (optional)
+ */
+ iconActivated?: string;
+
+ /**
+ * In case of two icon states, this function will hide one of them or show another (optional)
+ */
+ iconSwitchFunction?: () => boolean;
+
+ /**
+ * Custom CSS class to be set to the action button (optional)
+ */
+ className?: string;
+}
+
+/**
+ * Definition of an action to be used in an Stark Action Bar
+ */
+export interface StarkAction extends StarkActionBase {
+ /**
+ * The HTML id to be set to the action button
+ */
+ id: string;
+
+ /**
+ * Text to be displayed as label of the action button
+ */
+ label: string;
+
+ /**
+ * Path to SVG icon from iconSets to display inside the action button. Ex: "pencil"
+ */
+ icon: string;
+
+ /**
+ * Function to be fired when action button is clicked
+ */
+ actionCall: Function;
+
+ /**
+ * Whether the action button should be enabled for user interaction or not
+ */
+ isEnabled: boolean;
+
+ /**
+ * Whether the action button will be visible or not (optional)
+ */
+ isVisible?: boolean;
+}
+
+/**
+ * Definition of a action bar's default action to be used in an Stark generic form
+ */
+export interface StarkDefaultPredefinedAction extends StarkActionBase {}
+
+/**
+ * Definition of a action bar's normal action to be used in an Stark generic form
+ */
+export interface StarkCustomizablePredefinedAction extends StarkActionBase {
+ /**
+ * Whether the action button will be visible or not (optional)
+ */
+ isVisible?: boolean;
+}
diff --git a/packages/stark-ui/tsconfig.spec.json b/packages/stark-ui/tsconfig.spec.json
index b4cfe9bba6..ce781fb602 100644
--- a/packages/stark-ui/tsconfig.spec.json
+++ b/packages/stark-ui/tsconfig.spec.json
@@ -3,6 +3,7 @@
"compilerOptions": {
"module": "commonjs",
"paths": {
+ "@ngx-translate/*": ["../stark-core/node_modules/@ngx-translate/*"],
"@nationalbankbelgium/stark-core/testing": ["../../dist/packages/stark-core/testing"],
"@nationalbankbelgium/stark-core": ["../../dist/packages/stark-core"],
"@nationalbankbelgium/stark-ui": ["."]
diff --git a/packages/tsconfig.json b/packages/tsconfig.json
index e4a87d4c51..e782e35c83 100644
--- a/packages/tsconfig.json
+++ b/packages/tsconfig.json
@@ -10,6 +10,7 @@
"paths": {
"rxjs/*": ["../node_modules/rxjs/*"],
"@angular/*": ["../node_modules/@angular/*"],
+ "@ngx-translate/*": ["./stark-core/node_modules/@ngx-translate/*"],
"environments/environment": ["./stark-core/src/common/environment"],
"@nationalbankbelgium/stark-*": ["./stark-*"]
},
diff --git a/showcase/karma.conf.js b/showcase/karma.conf.js
index 12eba512ad..67aabf76fe 100644
--- a/showcase/karma.conf.js
+++ b/showcase/karma.conf.js
@@ -9,7 +9,7 @@ const helpers = require("./node_modules/@nationalbankbelgium/stark-testing/helpe
const defaultKarmaConfig = require("./node_modules/@nationalbankbelgium/stark-testing/karma.conf.js").rawKarmaConfig;
// entry files of the "@nationalbankbelgium/stark-ui" module imported in mock files
-const karmaTypescriptExclusions = [...defaultKarmaConfig.exclude, "src/assets/examples/*"];
+const karmaTypescriptExclusions = [...defaultKarmaConfig.exclude, "src/assets/examples/**"];
// start customizing the KarmaCI configuration from stark-testing
const starkShowcaseSpecificConfiguration = Object.assign({}, defaultKarmaConfig, {
diff --git a/showcase/src/app/app.component.html b/showcase/src/app/app.component.html
index 940f3d5304..cb53f2f1a6 100644
--- a/showcase/src/app/app.component.html
+++ b/showcase/src/app/app.component.html
@@ -20,6 +20,9 @@
Home
+
+ Action Bar
+
Example Viewer
diff --git a/showcase/src/app/app.module.ts b/showcase/src/app/app.module.ts
index b8acdcf651..c4169ddfe7 100644
--- a/showcase/src/app/app.module.ts
+++ b/showcase/src/app/app.module.ts
@@ -36,7 +36,7 @@ import {
StarkUser
} from "@nationalbankbelgium/stark-core";
-import { StarkAppLogoModule, StarkSliderModule } from "@nationalbankbelgium/stark-ui";
+import { StarkActionBarModule, StarkAppLogoModule, StarkSliderModule } from "@nationalbankbelgium/stark-ui";
import { routerConfigFn } from "./router.config";
import { registerMaterialIconSet } from "./material-icons.config";
import { Deserialize } from "cerialize";
@@ -55,12 +55,13 @@ import { AppComponent } from "./app.component";
import { AppState } from "./app.service";
import { HomeComponent } from "./home";
import { NoContentComponent } from "./no-content";
+import { ActionBarComponent, ExampleViewerComponent } from "./demo";
+
/* tslint:disable:no-import-side-effect */
// load PostCSS styles
import "../styles/styles.pcss";
// load SASS styles
import "../styles/styles.scss";
-import { DemoComponent } from "./demo/demo.component";
/* tslint:enable */
// Application wide providers
@@ -119,7 +120,7 @@ export const metaReducers: MetaReducer[] = ENV !== "production" ? [logger
*/
@NgModule({
bootstrap: [AppComponent],
- declarations: [AppComponent, HomeComponent, NoContentComponent, DemoComponent],
+ declarations: [AppComponent, HomeComponent, NoContentComponent, ActionBarComponent, ExampleViewerComponent],
/**
* Import Angular's modules.
*/
@@ -152,7 +153,9 @@ export const metaReducers: MetaReducer[] = ENV !== "production" ? [logger
StarkSessionModule.forRoot(),
StarkRoutingModule.forRoot(),
StarkAppLogoModule,
- StarkSliderModule
+ StarkSliderModule,
+ StarkActionBarModule,
+ StarkAppLogoModule
],
/**
* Expose our Services and Providers into Angular's dependency injection.
diff --git a/showcase/src/app/app.routes.ts b/showcase/src/app/app.routes.ts
index c7efe82a98..c2e5cdd8f1 100644
--- a/showcase/src/app/app.routes.ts
+++ b/showcase/src/app/app.routes.ts
@@ -1,10 +1,11 @@
-import { DemoComponent } from "./demo";
+import { ActionBarComponent, ExampleViewerComponent } from "./demo";
import { HomeComponent } from "./home";
import { NoContentComponent } from "./no-content";
import { Ng2StateDeclaration } from "@uirouter/angular";
export const APP_STATES: Ng2StateDeclaration[] = [
{ name: "home", url: "/", component: HomeComponent },
- { name: "demo-example-viewer", url: "/demo-example-viewer", component: DemoComponent },
+ { name: "demo-action-bar", url: "/demo/action-bar", component: ActionBarComponent },
+ { name: "demo-example-viewer", url: "/demo/example-viewer", component: ExampleViewerComponent },
{ name: "otherwise", url: "/otherwise", component: NoContentComponent }
];
diff --git a/showcase/src/app/demo/action-bar/action-bar.component.html b/showcase/src/app/demo/action-bar/action-bar.component.html
new file mode 100644
index 0000000000..38afe80414
--- /dev/null
+++ b/showcase/src/app/demo/action-bar/action-bar.component.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/showcase/src/app/demo/action-bar/action-bar.component.ts b/showcase/src/app/demo/action-bar/action-bar.component.ts
new file mode 100644
index 0000000000..4c50dc3958
--- /dev/null
+++ b/showcase/src/app/demo/action-bar/action-bar.component.ts
@@ -0,0 +1,105 @@
+import { Component, OnInit, Inject } from "@angular/core";
+import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core";
+import { StarkAction, StarkActionBarConfig } from "@nationalbankbelgium/stark-ui";
+
+@Component({
+ selector: "showcase-demo-action-bar",
+ templateUrl: "./action-bar.component.html"
+})
+export class ActionBarComponent implements OnInit {
+ public actions: StarkAction[];
+ public actionBarConfig: StarkActionBarConfig;
+ public alternativeActions: StarkAction[];
+
+ public constructor(@Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService) {}
+
+ public ngOnInit(): void {
+ this.actions = [
+ {
+ id: "actionValidate",
+ label: "STARK.ICONS.APPROVE_ITEM",
+ icon: "check",
+ actionCall: ($event: Event, data: any): void => {
+ this.logger.debug($event);
+ this.logger.debug(data);
+ },
+ isEnabled: false,
+ isVisible: true
+ },
+ {
+ id: "actionSave",
+ label: "STARK.ICONS.SAVE_ITEM",
+ icon: "content-save",
+ actionCall: ($event: Event, data: any): void => {
+ this.logger.debug($event);
+ this.logger.debug(data);
+ },
+ isEnabled: true,
+ isVisible: true
+ },
+ {
+ id: "actionDelete",
+ label: "STARK.ICONS.DELETE_ITEM",
+ icon: "delete",
+ actionCall: ($event: Event, data: any): void => {
+ this.logger.debug($event);
+ this.logger.debug(data);
+ },
+ isEnabled: false,
+ isVisible: true
+ },
+ {
+ id: "actionClose",
+ label: "STARK.ICONS.CLOSE_ITEM",
+ icon: "close",
+ actionCall: ($event: Event, data: any): void => {
+ this.logger.debug($event);
+ this.logger.debug(data);
+ },
+ isEnabled: true,
+ isVisible: true
+ }
+ ];
+
+ this.actionBarConfig = {
+ actions: this.actions,
+ isPresent: true
+ };
+
+ this.alternativeActions = [
+ {
+ id: "actionAdd",
+ label: "STARK.ICONS.ADD_ITEM",
+ icon: "account-plus",
+ actionCall: ($event: Event, data: any): void => {
+ this.logger.debug($event);
+ this.logger.debug(data);
+ },
+ isEnabled: true,
+ isVisible: true
+ },
+ {
+ id: "actionMinus",
+ label: "STARK.ICONS.DELETE_ITEM",
+ icon: "account-minus",
+ actionCall: ($event: Event, data: any): void => {
+ this.logger.debug($event);
+ this.logger.debug(data);
+ },
+ isEnabled: false,
+ isVisible: true
+ },
+ {
+ id: "actionEdit",
+ label: "STARK.ICONS.EDIT_ITEM",
+ icon: "pencil",
+ actionCall: ($event: Event, data: any): void => {
+ this.logger.debug($event);
+ this.logger.debug(data);
+ },
+ isEnabled: true,
+ isVisible: true
+ }
+ ];
+ }
+}
diff --git a/showcase/src/app/demo/demo.component.scss b/showcase/src/app/demo/demo.component.scss
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/showcase/src/app/demo/demo.component.spec.ts b/showcase/src/app/demo/demo.component.spec.ts
deleted file mode 100644
index aeafc5c4ac..0000000000
--- a/showcase/src/app/demo/demo.component.spec.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { HttpClientModule } from "@angular/common/http";
-import { async, ComponentFixture, TestBed } from "@angular/core/testing";
-import { DemoComponent } from "./demo.component";
-import { SharedModule } from "../shared/shared.module";
-import { MockStarkLoggingService } from "@nationalbankbelgium/stark-core/testing";
-import { STARK_LOGGING_SERVICE } from "@nationalbankbelgium/stark-core";
-
-describe("DemoComponent", () => {
- let component: DemoComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async(() => {
- return TestBed.configureTestingModule({
- declarations: [DemoComponent],
- imports: [HttpClientModule, SharedModule],
- providers: [{ provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }]
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(DemoComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it("should create", () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/showcase/src/app/demo/demo.component.ts b/showcase/src/app/demo/demo.component.ts
deleted file mode 100644
index 16f284c7f6..0000000000
--- a/showcase/src/app/demo/demo.component.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Component, Inject } from "@angular/core";
-import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core";
-
-@Component({
- selector: "showcase-demo",
- templateUrl: "./demo.component.html",
- styleUrls: ["./demo.component.scss"]
-})
-export class DemoComponent {
- public constructor(@Inject(STARK_LOGGING_SERVICE) public loggingService: StarkLoggingService) {}
-}
diff --git a/showcase/src/app/demo/demo.component.html b/showcase/src/app/demo/example-viewer/example-viewer.component.html
similarity index 100%
rename from showcase/src/app/demo/demo.component.html
rename to showcase/src/app/demo/example-viewer/example-viewer.component.html
diff --git a/showcase/src/app/demo/example-viewer/example-viewer.component.ts b/showcase/src/app/demo/example-viewer/example-viewer.component.ts
new file mode 100644
index 0000000000..799d49aa8b
--- /dev/null
+++ b/showcase/src/app/demo/example-viewer/example-viewer.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "showcase-demo-example-viewer",
+ templateUrl: "./example-viewer.component.html"
+})
+export class ExampleViewerComponent {}
diff --git a/showcase/src/app/demo/index.ts b/showcase/src/app/demo/index.ts
index ced8212a57..15776ea93e 100644
--- a/showcase/src/app/demo/index.ts
+++ b/showcase/src/app/demo/index.ts
@@ -1 +1,2 @@
-export * from "./demo.component";
+export * from "./action-bar/action-bar.component";
+export * from "./example-viewer/example-viewer.component";
diff --git a/showcase/src/app/shared/example-viewer/example-viewer.component.html b/showcase/src/app/shared/example-viewer/example-viewer.component.html
index 0b27a57b02..9c12c5f42d 100644
--- a/showcase/src/app/shared/example-viewer/example-viewer.component.html
+++ b/showcase/src/app/shared/example-viewer/example-viewer.component.html
@@ -1,6 +1,6 @@
-
{{ title }}
+
{{ title }}