diff --git a/commitlint.config.js b/commitlint.config.js
index 21774476e..d62795d19 100644
--- a/commitlint.config.js
+++ b/commitlint.config.js
@@ -27,6 +27,7 @@ module.exports = {
'progress-spinner',
'radio',
'select',
+ 'splitter',
'tabs',
'timepicker',
'tooltip',
diff --git a/package.json b/package.json
index a7bb58bc8..4d6054f11 100644
--- a/package.json
+++ b/package.json
@@ -156,6 +156,7 @@
"server-dev:progress-spinner": "npm run server-dev -- --env.component progress-spinner",
"server-dev:radio": "npm run server-dev -- --env.component radio",
"server-dev:select": "npm run server-dev -- --env.component select",
+ "server-dev:splitter": "npm run server-dev -- --env.component splitter",
"server-dev:tag": "npm run server-dev -- --env.component tag",
"server-dev:theme-picker": "npm run server-dev -- --env.component theme-picker",
"server-dev:tree": "npm run server-dev -- --env.component tree",
diff --git a/src/lib-dev/splitter/module.ts b/src/lib-dev/splitter/module.ts
new file mode 100644
index 000000000..1705360ed
--- /dev/null
+++ b/src/lib-dev/splitter/module.ts
@@ -0,0 +1,34 @@
+import { Component, NgModule, ViewEncapsulation } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { McSplitterModule } from '../../lib/splitter';
+
+
+@Component({
+ selector: 'app',
+ template: require('./template.html'),
+ styleUrls: ['./styles.scss'],
+ encapsulation: ViewEncapsulation.None
+})
+export class DemoComponent {}
+
+
+@NgModule({
+ declarations: [
+ DemoComponent
+ ],
+ imports: [
+ BrowserModule,
+ McSplitterModule
+ ],
+ bootstrap: [
+ DemoComponent
+ ]
+})
+export class DemoModule {}
+
+platformBrowserDynamic()
+ .bootstrapModule(DemoModule)
+ .catch((error) => console.error(error));
+
diff --git a/src/lib-dev/splitter/styles.scss b/src/lib-dev/splitter/styles.scss
new file mode 100644
index 000000000..636e2132d
--- /dev/null
+++ b/src/lib-dev/splitter/styles.scss
@@ -0,0 +1,43 @@
+@import '~@ptsecurity/mosaic-icons/dist/styles/mc-icons';
+@import '../../lib/core/theming/prebuilt/default-theme';
+@import '../../lib/core/visual/prebuilt/default-visual';
+
+.container {
+ margin: 8px;
+}
+
+.horizontal-block {
+ height: 100px;
+ border: 1px solid black;
+}
+
+.vertical-block {
+ height: 300px;
+ border: 1px solid black;
+}
+
+.min-width-enabled {
+ min-width: 200px;
+}
+
+// custom color
+mc-splitter.custom-color > mc-gutter {
+ background-color: #03A9F4;
+ color: white;
+}
+
+mc-splitter.custom-color > mc-gutter:hover {
+ background-color: #8bc34a;
+ color: black;
+}
+
+// custom gutter image
+mc-splitter.custom-gutter > mc-gutter {
+ background-repeat: no-repeat;
+ background-position: center;
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
+}
+
+mc-splitter.custom-gutter > mc-gutter > i {
+ display: none;
+}
diff --git a/src/lib-dev/splitter/template.html b/src/lib-dev/splitter/template.html
new file mode 100644
index 000000000..9c167317d
--- /dev/null
+++ b/src/lib-dev/splitter/template.html
@@ -0,0 +1,95 @@
+
+
Splitter examples
+
+
+ Import mosaic-icons to use default gutter icon.
+
+
+
+
+
Horizontal
+
+
+ first
+ second
+ third
+
+
+
+
+
Vertical
+
+
+ first
+ second
+ third
+
+
+
+
+
Default direction
+
+
+ first
+ second
+ third
+
+
+
+
+
Disabled
+
+
+ first
+ second
+ third
+
+
+
+
+
min-width for the first area
+
+
+ first (with min-width)
+ second
+ third (with min-width)
+
+
+
+
+
Nested
+
+
+ first
+
+
+ top
+ center
+ bottom
+
+
+ third
+
+
+
+
+
With custom color
+
+
+ first
+ second
+ third
+
+
+
+
+
With custom gutter image
+
+
+ first
+ second
+ third
+
+
+
+
diff --git a/src/lib/core/theming/_all-theme.scss b/src/lib/core/theming/_all-theme.scss
index 901069f08..f3c35dd07 100644
--- a/src/lib/core/theming/_all-theme.scss
+++ b/src/lib/core/theming/_all-theme.scss
@@ -18,6 +18,7 @@
@import '../option/option-theme';
@import '../../tag/tag-theme';
@import '../../tooltip/tooltip-theme';
+@import '../../splitter/splitter-theme';
@mixin mosaic-theme($theme) {
@@ -42,4 +43,5 @@
@include mc-option-theme($theme);
@include mc-tag-theme($theme);
@include mc-tooltip-theme($theme);
+ @include mc-splitter-theme($theme);
}
diff --git a/src/lib/public-api.ts b/src/lib/public-api.ts
index c5414a443..4ca3c5e9b 100644
--- a/src/lib/public-api.ts
+++ b/src/lib/public-api.ts
@@ -19,5 +19,6 @@ export * from '@ptsecurity/mosaic/radio';
export * from '@ptsecurity/mosaic/tree';
export * from '@ptsecurity/mosaic/tag';
export * from '@ptsecurity/mosaic/select';
+export * from '@ptsecurity/mosaic/splitter';
export * from '@ptsecurity/mosaic/tooltip';
diff --git a/src/lib/splitter/_splitter-theme.scss b/src/lib/splitter/_splitter-theme.scss
new file mode 100644
index 000000000..993a98d76
--- /dev/null
+++ b/src/lib/splitter/_splitter-theme.scss
@@ -0,0 +1,19 @@
+@mixin mc-splitter-theme($theme) {
+ $primary: map-get($theme, primary);
+ $second: map-get($theme, second);
+
+ mc-gutter {
+ background-color: mc-color($second, 60);
+ color: mc-color($second, 600);
+
+ &:hover {
+ background-color: mc-color($second, 100);
+ color: mc-color($second, 800);
+ }
+
+ &[disabled] {
+ background-color: mc-color($second, 60);
+ color: mc-color($second, 600);
+ }
+ }
+}
diff --git a/src/lib/splitter/index.ts b/src/lib/splitter/index.ts
new file mode 100644
index 000000000..7e1a213e3
--- /dev/null
+++ b/src/lib/splitter/index.ts
@@ -0,0 +1 @@
+export * from './public-api';
diff --git a/src/lib/splitter/public-api.ts b/src/lib/splitter/public-api.ts
new file mode 100644
index 000000000..e6d784ad5
--- /dev/null
+++ b/src/lib/splitter/public-api.ts
@@ -0,0 +1,2 @@
+export * from './splitter.module';
+export * from './splitter.component';
diff --git a/src/lib/splitter/spliltter.spec.ts b/src/lib/splitter/spliltter.spec.ts
new file mode 100644
index 000000000..d3560572a
--- /dev/null
+++ b/src/lib/splitter/spliltter.spec.ts
@@ -0,0 +1,115 @@
+import { Component, Type } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+
+import { Direction, McGutterDirective, McSplitterAreaDirective, McSplitterComponent, McSplitterModule } from './index';
+
+
+function createTestComponent(component: Type) {
+ TestBed
+ .resetTestingModule()
+ .configureTestingModule({
+ imports: [ McSplitterModule ],
+ declarations: [ component ],
+ providers: []
+ })
+ .compileComponents();
+
+ return TestBed.createComponent(component);
+}
+
+function checkDirection(fixture: ComponentFixture,
+ direction: Direction,
+ guttersCount: number,
+ gutterSize: number) {
+
+ const splitter = fixture.debugElement.query(By.directive(McSplitterComponent));
+ const gutters = fixture.debugElement.queryAll(By.directive(McGutterDirective));
+
+ const expectedDirection = direction === Direction.Vertical
+ ? 'column'
+ : 'row';
+
+ const expectedWidth = (direction === Direction.Vertical)
+ ? ''
+ : `${gutterSize}px`;
+
+ const expectedHeight = (direction === Direction.Vertical)
+ ? `${gutterSize}px`
+ : '100%';
+
+ expect(splitter.nativeElement.style.flexDirection).toBe(expectedDirection);
+
+ expect(gutters.length).toBe(guttersCount);
+ expect(gutters.every((gutter) => gutter.nativeElement.style.width === expectedWidth)).toBe(true);
+ expect(gutters.every((gutter) => gutter.nativeElement.style.height === expectedHeight)).toBe(true);
+}
+
+
+@Component({
+ selector: 'mc-demo-spllitter',
+ template: `
+
+ first
+ second
+ third
+
+ `
+})
+class McSplitterDefaultDirection {}
+
+@Component({
+ selector: 'mc-demo-spllitter',
+ template: `
+
+ first
+ second
+ third
+
+ `
+})
+class McSplitterDirection {
+ direction: Direction = Direction.Vertical;
+}
+
+describe('McSplitter', () => {
+ describe('direction', () => {
+ it('should be default', () => {
+ const fixture = createTestComponent(McSplitterDefaultDirection);
+
+ fixture.detectChanges();
+
+ const areas = fixture.debugElement.queryAll(By.directive(McSplitterAreaDirective));
+ const expectedAreasCount = 3;
+ const expectedGuttersCount = expectedAreasCount - 1;
+ const expectedGutterSize = 6;
+
+ checkDirection(fixture, Direction.Horizontal, expectedGuttersCount, expectedGutterSize);
+
+ expect(areas.length).toBe(expectedAreasCount);
+ });
+
+
+ it('should be horizontal', () => {
+ const fixture = createTestComponent(McSplitterDirection);
+ const expectedGuttersCount = 2;
+ const expectedGutterSize = 6;
+
+ fixture.componentInstance.direction = Direction.Horizontal;
+ fixture.detectChanges();
+
+ checkDirection(fixture, Direction.Horizontal, expectedGuttersCount, expectedGutterSize);
+ });
+
+ it('should be vertical', () => {
+ const fixture = createTestComponent(McSplitterDirection);
+ const expectedGuttersCount = 2;
+ const expectedGutterSize = 6;
+
+ fixture.componentInstance.direction = Direction.Vertical;
+ fixture.detectChanges();
+
+ checkDirection(fixture, Direction.Vertical, expectedGuttersCount, expectedGutterSize);
+ });
+ });
+});
diff --git a/src/lib/splitter/splitter.component.html b/src/lib/splitter/splitter.component.html
new file mode 100644
index 000000000..217983f4a
--- /dev/null
+++ b/src/lib/splitter/splitter.component.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/src/lib/splitter/splitter.component.ts b/src/lib/splitter/splitter.component.ts
new file mode 100644
index 000000000..8d8227f3a
--- /dev/null
+++ b/src/lib/splitter/splitter.component.ts
@@ -0,0 +1,440 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ Directive,
+ ElementRef,
+ Input,
+ NgZone, OnDestroy,
+ OnInit,
+ Renderer2,
+ ViewEncapsulation
+} from '@angular/core';
+
+import { coerceBooleanProperty, coerceCssPixelValue, coerceNumberProperty } from '@ptsecurity/cdk/coercion';
+
+
+interface IArea {
+ area: McSplitterAreaDirective;
+ index: number;
+ order: number;
+ initialSize: number;
+}
+
+interface IPoint {
+ x: number;
+ y: number;
+}
+
+
+const enum AttributeProperty {
+ Disabled = 'disabled'
+}
+
+const enum Cursor {
+ Default = 'default',
+ ResizeColumn = 'col-resize',
+ ResizeRow = 'row-resize'
+}
+
+const enum StyleProperty {
+ Cursor = 'cursor',
+ Flex = 'flex',
+ FlexBasis = 'flex-basis',
+ FlexDirection = 'flex-direction',
+ Height = 'height',
+ MaxWidth = 'max-width',
+ MinHeight = 'min-height',
+ MinWidth = 'minWidth',
+ OffsetHeight = 'offsetHeight',
+ OffsetWidth = 'offsetWidth',
+ Order = 'order',
+ Width = 'width'
+}
+
+const enum State {
+ Disabled = 'disabled',
+ Horizontal = 'horizontal',
+ Vertical = 'vertical'
+}
+
+export const enum Direction {
+ Horizontal = 'horizontal',
+ Vertical = 'vertical'
+}
+
+@Component({
+ selector: 'mc-splitter',
+ preserveWhitespaces: false,
+ styleUrls: ['splitter.css'],
+ templateUrl: './splitter.component.html',
+ encapsulation: ViewEncapsulation.None,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class McSplitterComponent implements OnInit {
+ readonly areas: IArea[] = [];
+
+ private _direction: Direction;
+ private _disabled: boolean = false;
+ private _gutterSize: number = 6;
+
+ private isDragging: boolean = false;
+
+ private readonly areaPositionDivider: number = 2;
+ private readonly listeners: (() => void)[] = [];
+
+ @Input()
+ set direction(direction: Direction) {
+ this._direction = direction;
+ }
+
+ get direction(): Direction {
+ return this._direction;
+ }
+
+ @Input()
+ set disabled(disabled: boolean) {
+ this._disabled = coerceBooleanProperty(disabled);
+ }
+
+ get disabled(): boolean {
+ return this._disabled;
+ }
+
+ @Input()
+ set gutterSize(gutterSize: number) {
+ const size = coerceNumberProperty(gutterSize);
+ this._gutterSize = size > 0 ? size : this.gutterSize;
+ }
+
+ get gutterSize(): number {
+ return this._gutterSize;
+ }
+
+ constructor(private elementRef: ElementRef,
+ private ngZone: NgZone,
+ private renderer: Renderer2) {}
+
+ addArea(area: McSplitterAreaDirective): void {
+ const index: number = this.areas.length;
+ const order: number = index * this.areaPositionDivider;
+ const size: number = area.getSize();
+
+ area.setOrder(order);
+
+ this.areas.push({
+ area,
+ index,
+ order,
+ initialSize: size
+ });
+ }
+
+ ngOnInit(): void {
+ if (!this.direction) {
+ this.direction = Direction.Horizontal;
+ }
+
+ this.setStyle(StyleProperty.FlexDirection, this.isVertical() ? 'column' : 'row');
+ }
+
+ onMouseDown(event: MouseEvent, leftAreaIndex: number, rightAreaIndex: number) {
+ if (this.disabled) {
+ return;
+ }
+
+ const leftArea = this.areas[leftAreaIndex];
+ const rightArea = this.areas[rightAreaIndex];
+
+ const startPoint: IPoint = {
+ x: event.screenX,
+ y: event.screenY
+ };
+
+ leftArea.initialSize = leftArea.area.getSize();
+ rightArea.initialSize = rightArea.area.getSize();
+
+ this.areas.forEach((item) => {
+ const size = item.area.getSize();
+ item.area.disableFlex();
+ item.area.setSize(size);
+ });
+
+ this.ngZone.runOutsideAngular(() => {
+ this.listeners.push(
+ this.renderer.listen(
+ 'document',
+ 'mouseup',
+ () => this.onMouseUp()
+ )
+ );
+ });
+
+ this.ngZone.runOutsideAngular(() => {
+ this.listeners.push(
+ this.renderer.listen(
+ 'document',
+ 'mousemove',
+ (e: MouseEvent) => this.onMouseMove(e, startPoint, leftArea, rightArea)
+ )
+ );
+ });
+
+ this.isDragging = true;
+ }
+
+ removeArea(area: McSplitterAreaDirective): void {
+ let indexToRemove: number = -1;
+
+ this.areas.some((item, index) => {
+ if (item.area === area) {
+ indexToRemove = index;
+
+ return true;
+ }
+
+ return false;
+ });
+
+ if (indexToRemove === -1) {
+ return;
+ }
+
+ this.areas.splice(indexToRemove, 1);
+ }
+
+ private isVertical(): boolean {
+ return this.direction === Direction.Vertical;
+ }
+
+ private onMouseMove(event: MouseEvent, startPoint: IPoint, leftArea: IArea, rightArea: IArea) {
+ if (!this.isDragging || this.disabled) {
+ return;
+ }
+
+ const endPoint: IPoint = {
+ x: event.screenX,
+ y: event.screenY
+ };
+
+ const offset = this.isVertical()
+ ? startPoint.y - endPoint.y
+ : startPoint.x - endPoint.x;
+
+ const newLeftAreaSize = leftArea.initialSize - offset;
+ const newRightAreaSize = rightArea.initialSize + offset;
+
+ const minLeftAreaSize = leftArea.area.getMinSize();
+ const minRightAreaSize = rightArea.area.getMinSize();
+
+ if (newLeftAreaSize <= minLeftAreaSize || newRightAreaSize <= minRightAreaSize) {
+ const rightAreaOffset = leftArea.initialSize - minLeftAreaSize;
+
+ leftArea.area.setSize(minLeftAreaSize);
+ rightArea.area.setSize(rightArea.initialSize + rightAreaOffset);
+ } else if (newLeftAreaSize <= 0) {
+ leftArea.area.setSize(0);
+ rightArea.area.setSize(rightArea.initialSize + leftArea.initialSize);
+ } else if (newRightAreaSize <= 0) {
+ leftArea.area.setSize(rightArea.initialSize + leftArea.initialSize);
+ rightArea.area.setSize(0);
+ } else {
+ leftArea.area.setSize(newLeftAreaSize);
+ rightArea.area.setSize(newRightAreaSize);
+ }
+ }
+
+ private onMouseUp() {
+ while (this.listeners.length > 0) {
+ const unsubscribe = this.listeners.pop();
+
+ if (unsubscribe) {
+ unsubscribe();
+ }
+ }
+
+ this.isDragging = false;
+ }
+
+ private setStyle(property: StyleProperty, value: string | number) {
+ this.renderer.setStyle(this.elementRef.nativeElement, property, value);
+ }
+}
+
+@Directive({
+ selector: 'mc-gutter'
+})
+export class McGutterDirective implements OnInit {
+ private _direction: Direction = Direction.Vertical;
+ private _disabled: boolean = false;
+ private _order: number = 0;
+ private _size: number = 6;
+
+ @Input()
+ set direction(direction: Direction) {
+ this._direction = direction;
+ }
+
+ get direction(): Direction {
+ return this._direction;
+ }
+
+ @Input()
+ set disabled(disabled: boolean) {
+ this._disabled = coerceBooleanProperty(disabled);
+ }
+
+ get disabled(): boolean {
+ return this._disabled;
+ }
+
+ @Input()
+ set order(order: number) {
+ this._order = coerceNumberProperty(order);
+ }
+
+ get order(): number {
+ return this._order;
+ }
+
+ @Input()
+ set size(size: number) {
+ this._size = coerceNumberProperty(size);
+ }
+
+ get size(): number {
+ return this._size;
+ }
+
+ constructor(private renderer: Renderer2,
+ private elementRef: ElementRef) {
+ }
+
+ ngOnInit(): void {
+ this.setStyle(StyleProperty.Cursor, this.getCursor(this.getState()));
+ this.setStyle(StyleProperty.FlexBasis, coerceCssPixelValue(this.size));
+ this.setStyle(this.isVertical() ? StyleProperty.Height : StyleProperty.Width, coerceCssPixelValue(this.size));
+ this.setStyle(StyleProperty.Order, this.order);
+
+ if (!this.isVertical()) {
+ this.setStyle(StyleProperty.Height, '100%');
+ }
+
+ if (this.disabled) {
+ this.setAttr(AttributeProperty.Disabled, 'true');
+ }
+ }
+
+ private isVertical(): boolean {
+ return this.direction === Direction.Vertical;
+ }
+
+ private getCursor(state: State): string {
+ switch (state) {
+ case State.Disabled:
+ return Cursor.Default;
+ case State.Vertical:
+ return Cursor.ResizeRow;
+ case State.Horizontal:
+ return Cursor.ResizeColumn;
+ default:
+ throw Error(`Unknown gutter state for cursor: ${state}`);
+ }
+ }
+
+ private getState(): State {
+ return this.disabled
+ ? State.Disabled
+ : this.direction === Direction.Vertical
+ ? State.Vertical
+ : State.Horizontal;
+ }
+
+ private setStyle(property: StyleProperty, value: string | number) {
+ this.renderer.setStyle(this.elementRef.nativeElement, property, value);
+ }
+
+ private setAttr(attribute: AttributeProperty, value: string) {
+ this.renderer.setAttribute(this.elementRef.nativeElement, attribute, value);
+ }
+}
+
+@Directive({
+ selector: 'mc-splitter-area'
+})
+export class McSplitterAreaDirective implements OnInit, OnDestroy {
+ constructor(private elementRef: ElementRef,
+ private renderer: Renderer2,
+ private splitter: McSplitterComponent) {}
+
+ disableFlex(): void {
+ this.renderer.removeStyle(this.elementRef.nativeElement, 'flex');
+ }
+
+ ngOnInit(): void {
+ this.splitter.addArea(this);
+
+ this.removeStyle(StyleProperty.MaxWidth);
+ this.setStyle(StyleProperty.Flex, '1');
+
+ if (this.splitter.direction === Direction.Vertical) {
+ this.setStyle(StyleProperty.Width, '100%');
+ this.removeStyle(StyleProperty.Height);
+ } else {
+ this.setStyle(StyleProperty.Height, '100%');
+ this.removeStyle(StyleProperty.Width);
+ }
+ }
+
+ ngOnDestroy(): void {
+ this.splitter.removeArea(this);
+ }
+
+ setOrder(order: number): void {
+ this.setStyle(StyleProperty.Order, order);
+ }
+
+ setSize(size: number): void {
+ const sz = coerceNumberProperty(size);
+ this.setStyle(this.getSizeProperty(), coerceCssPixelValue(sz));
+ }
+
+ getSize(): number {
+ return this.elementRef.nativeElement[this.getOffsetSizeProperty()];
+ }
+
+ getMinSize(): number {
+ const styles = getComputedStyle(this.elementRef.nativeElement);
+
+ return parseFloat(styles[this.getMinSizeProperty()]);
+ }
+
+ private isVertical(): boolean {
+ return this.splitter.direction === Direction.Vertical;
+ }
+
+ private getMinSizeProperty(): StyleProperty {
+ return this.isVertical()
+ ? StyleProperty.MinHeight
+ : StyleProperty.MinWidth;
+ }
+
+ private getOffsetSizeProperty(): StyleProperty {
+ return this.isVertical()
+ ? StyleProperty.OffsetHeight
+ : StyleProperty.OffsetWidth;
+ }
+
+ private getSizeProperty(): StyleProperty {
+ return this.isVertical()
+ ? StyleProperty.Height
+ : StyleProperty.Width;
+ }
+
+ private setStyle(style: StyleProperty, value: string | number) {
+ this.renderer.setStyle(this.elementRef.nativeElement, style, value);
+ }
+
+ private removeStyle(style: StyleProperty) {
+ this.renderer.removeStyle(this.elementRef.nativeElement, style);
+ }
+}
diff --git a/src/lib/splitter/splitter.module.ts b/src/lib/splitter/splitter.module.ts
new file mode 100644
index 000000000..6dea5667b
--- /dev/null
+++ b/src/lib/splitter/splitter.module.ts
@@ -0,0 +1,26 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+
+import { McIconModule } from '@ptsecurity/mosaic/icon';
+
+import { McGutterDirective, McSplitterAreaDirective, McSplitterComponent } from './splitter.component';
+
+
+@NgModule({
+ imports: [
+ CommonModule,
+ McIconModule
+ ],
+ exports: [
+ McGutterDirective,
+ McSplitterAreaDirective,
+ McSplitterComponent
+ ],
+ declarations: [
+ McGutterDirective,
+ McSplitterAreaDirective,
+ McSplitterComponent
+ ]
+})
+export class McSplitterModule {
+}
diff --git a/src/lib/splitter/splitter.scss b/src/lib/splitter/splitter.scss
new file mode 100644
index 000000000..d64506154
--- /dev/null
+++ b/src/lib/splitter/splitter.scss
@@ -0,0 +1,23 @@
+mc-splitter {
+ display: flex;
+ flex-wrap: nowrap;
+ align-items: stretch;
+ overflow: hidden;
+}
+
+mc-splitter-area {
+ overflow: hidden;
+}
+
+mc-gutter {
+ display: flex;
+ flex-grow: 0;
+ flex-shrink: 0;
+ overflow: hidden;
+ justify-content: center;
+ align-items: center;
+}
+
+.icon-vertical {
+ transform: rotate(90deg);
+}
diff --git a/src/lib/splitter/tsconfig.build.json b/src/lib/splitter/tsconfig.build.json
new file mode 100644
index 000000000..9b6e4f0f3
--- /dev/null
+++ b/src/lib/splitter/tsconfig.build.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../tsconfig.build",
+ "files": ["public-api.ts"],
+ "angularCompilerOptions": {
+ "strictMetadataEmit": true,
+ "flatModuleOutFile": "index.js",
+ "flatModuleId": "@ptsecurity/mosaic/splitter",
+ "skipTemplateCodegen": true,
+ "fullTemplateTypeCheck": true
+ }
+}
diff --git a/tests/karma-system-config.js b/tests/karma-system-config.js
index c92c5c04a..0ae80f12c 100644
--- a/tests/karma-system-config.js
+++ b/tests/karma-system-config.js
@@ -65,7 +65,8 @@ System.config({
'@ptsecurity/mosaic/modal': 'dist/packages/mosaic/modal/index.js',
'@ptsecurity/mosaic/tag': 'dist/packages/mosaic/tag/index.js',
'@ptsecurity/mosaic/select': 'dist/packages/mosaic/select/index.js',
- '@ptsecurity/mosaic/tooltip': 'dist/packages/mosaic/tooltip/index.js'
+ '@ptsecurity/mosaic/tooltip': 'dist/packages/mosaic/tooltip/index.js',
+ '@ptsecurity/mosaic/splitter': 'dist/packages/mosaic/splitter/index.js'
},
packages: {
// Thirdparty barrels.