diff --git a/src/checkbox/checkbox.html b/src/checkbox/checkbox.html
index d83b639f555..492199b8164 100644
--- a/src/checkbox/checkbox.html
+++ b/src/checkbox/checkbox.html
@@ -4,7 +4,7 @@
[attr.name]="name"
[attr.value]="value"
[attr.tabindex]="tabindex"
- [disabled]="disabled"
+ [attr.disabled]="disabled ? true : null"
[checked]="checked"
(change)="onChange($event)"
(focus)="onFocus($event)"
diff --git a/src/checkbox/checkbox.spec.ts b/src/checkbox/checkbox.spec.ts
new file mode 100644
index 00000000000..f19d0ddd5dd
--- /dev/null
+++ b/src/checkbox/checkbox.spec.ts
@@ -0,0 +1,119 @@
+import {
+ async,
+ TestBed
+} from "@angular/core/testing";
+import { Component, ViewChild } from "@angular/core";
+import { FormsModule } from '@angular/forms';
+import { By } from "@angular/platform-browser";
+import { IgCheckbox } from "./checkbox";
+
+describe('IgCheckbox', function() {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ InitCheckbox,
+ CheckboxSimple,
+ CheckboxDisabled,
+ IgCheckbox
+ ],
+ imports: [FormsModule]
+ })
+ .compileComponents();
+ }));
+
+ it('Initializes a checkbox', () => {
+ let fixture = TestBed.createComponent(InitCheckbox);
+ fixture.detectChanges();
+
+ let nativeCheckbox = fixture.debugElement.query(By.css('input')).nativeElement;
+ let nativeLabel = fixture.debugElement.query(By.css('label')).nativeElement;
+
+ expect(nativeCheckbox).toBeTruthy();
+ expect(nativeLabel).toBeTruthy();
+ expect(nativeLabel.textContent.trim()).toEqual('Init');
+ });
+
+ it('Initialize with a ngModel', () => {
+ let fixture = TestBed.createComponent(CheckboxSimple);
+ fixture.detectChanges();
+
+ let nativeCheckbox = fixture.debugElement.query(By.css('input')).nativeElement;
+ let checkboxInstance = fixture.componentInstance.cb;
+ let testInstance = fixture.componentInstance;
+
+ fixture.detectChanges();
+
+ expect(nativeCheckbox.checked).toBe(false);
+ expect(checkboxInstance.checked).toBe(false);
+
+ testInstance.subscribed = true;
+ fixture.detectChanges();
+
+ expect(nativeCheckbox.checked).toBe(true);
+ expect(checkboxInstance.checked).toBe(true);
+ });
+
+ it('Disabled state', () => {
+ let fixture = TestBed.createComponent(CheckboxDisabled);
+ fixture.detectChanges();
+
+ let nativeCheckbox = fixture.debugElement.query(By.css('input')).nativeElement;
+ let checkboxInstance = fixture.componentInstance.cb;
+ let testInstance = fixture.componentInstance;
+
+ fixture.detectChanges();
+
+ expect(checkboxInstance.disabled).toBe(true);
+ expect(nativeCheckbox.getAttribute('disabled')).toBe('true');
+
+ nativeCheckbox.dispatchEvent(new Event('change'));
+ fixture.detectChanges();
+
+ // Should not update
+ expect(checkboxInstance.checked).toBe(false);
+ expect(testInstance.subscribed).toBe(false);
+ });
+
+ it('Event handling', () => {
+ let fixture = TestBed.createComponent(CheckboxSimple);
+ fixture.detectChanges();
+
+ let nativeCheckbox = fixture.debugElement.query(By.css('input')).nativeElement;
+ let checkboxInstance = fixture.componentInstance.cb;
+ let testInstance = fixture.componentInstance;
+
+ nativeCheckbox.dispatchEvent(new Event('focus'));
+ fixture.detectChanges();
+
+ expect(checkboxInstance.focused).toBe(true);
+
+ nativeCheckbox.dispatchEvent(new Event('blur'));
+ fixture.detectChanges();
+
+ expect(checkboxInstance.focused).toBe(false);
+
+ spyOn(checkboxInstance.change, 'emit');
+ nativeCheckbox.dispatchEvent(new Event('change'));
+ fixture.detectChanges();
+
+ expect(checkboxInstance.change.emit).toHaveBeenCalled();
+ expect(testInstance.subscribed).toBe(true);
+ });
+});
+
+@Component({ template: `Init`})
+class InitCheckbox {}
+
+@Component({ template: `Simple`})
+class CheckboxSimple {
+ @ViewChild('cb') cb: IgCheckbox;
+
+ subscribed: boolean = false;
+}
+
+@Component({ template: `Disabled`})
+class CheckboxDisabled {
+ @ViewChild('cb') cb: IgCheckbox;
+
+ subscribed: boolean = false;
+}
\ No newline at end of file
diff --git a/src/checkbox/checkbox.ts b/src/checkbox/checkbox.ts
index 6c762198922..d90d162c47d 100644
--- a/src/checkbox/checkbox.ts
+++ b/src/checkbox/checkbox.ts
@@ -41,7 +41,7 @@ export class IgCheckbox implements ControlValueAccessor {
protected _value: any;
- focused: boolean = false;
+ focused: boolean = false;
onChange(event) {
if (this.disabled) {
@@ -67,7 +67,7 @@ export class IgCheckbox implements ControlValueAccessor {
return;
}
this._value = value;
- this.checked = this._value;
+ this.checked = !!this._value;
}
private _onTouchedCallback: () => void = noop;
diff --git a/src/layout/layout.ts b/src/layout/layout.ts
new file mode 100644
index 00000000000..dc25b28e3ea
--- /dev/null
+++ b/src/layout/layout.ts
@@ -0,0 +1,53 @@
+import { Directive, HostBinding, Input, NgModule } from '@angular/core';
+
+
+@Directive({
+ selector: '[layout]'
+})
+export class LayoutDirective {
+
+ @Input() dir: string = "row";
+ @Input() reverse: boolean = false;
+ @Input() wrap: string = "nowrap";
+ @Input() justify: string = "flex-start";
+ @Input() itemAlign: string = "flex-start";
+
+ @HostBinding('style.display') display = 'flex';
+ @HostBinding('style.flex-wrap') get flexwrap() { return this.wrap; }
+ @HostBinding('style.justify-content') get justifycontent() { return this.justify; }
+ @HostBinding('style.align-content') get align() { return this.itemAlign; }
+
+ @HostBinding('style.flex-direction')
+ get direction() {
+ if (this.reverse) {
+ return (this.dir == 'row') ? 'row-reverse' : 'column-reverse';
+ }
+ return (this.dir == 'row') ? 'row' : 'column';
+ }
+}
+
+@Directive({
+ selector: '[flex]'
+})
+export class FlexDirective {
+ @Input() grow: number = 1;
+ @Input() shrink: number = 1;
+ @Input() flex: string;
+ @Input() order: number = 0;
+
+ @HostBinding('style.flex')
+ get style() {
+ return `${this.grow} ${this.shrink}`;
+ }
+
+ @HostBinding('style.order')
+ get itemorder() {
+ return this.order || 0;
+ }
+}
+
+@NgModule({
+ declarations: [LayoutDirective, FlexDirective],
+ exports: [FlexDirective, LayoutDirective]
+})
+export class IgLayout {}
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index 9e1e44d70f5..bd323afc01f 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -14,3 +14,5 @@ export * from './radio/radio';
export * from './label/label';
export * from './switch/switch';
export * from './avatar/avatar';
+export * from './layout/layout';
+export * from './modal/modal';
\ No newline at end of file
diff --git a/src/modal/modal.html b/src/modal/modal.html
new file mode 100644
index 00000000000..62675ef1b57
--- /dev/null
+++ b/src/modal/modal.html
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modal/modal.ts b/src/modal/modal.ts
new file mode 100644
index 00000000000..933f47bcc8d
--- /dev/null
+++ b/src/modal/modal.ts
@@ -0,0 +1,69 @@
+import { Component, ViewChild, Input, Output, EventEmitter, ElementRef, NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+ selector: 'modal',
+ moduleId: module.id,
+ templateUrl: 'modal.html',
+ styles: [`
+ .modalDialog {
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ bottom: 0;
+ background: rgba(0,0,0,.65);
+ z-index: 9999;
+ opacity: 1;
+ transition: all 400ms ease-in;
+ }
+ .modal-inner {
+ width: 400px;
+ position: relative;
+ margin: 10% auto;
+ padding: 5px 25px 10px 10px;
+ background: #fff;
+ }
+ `]
+})
+export class Modal {
+
+ @Input() closeOnClick = true;
+
+ @Output()
+ onOpen = new EventEmitter();
+
+ @Output()
+ onClose = new EventEmitter();
+
+ isOpen = false;
+
+ @ViewChild('modal') modalEl: ElementRef;
+ protected behindElement: HTMLElement;
+
+ open() {
+ if (this.isOpen) {
+ return;
+ }
+ this.isOpen = true;
+ this.onOpen.emit(this);
+ this.modalEl.nativeElement.classList.add('modalDialog');
+ }
+
+ close() {
+ if (!this.isOpen) {
+ return;
+ }
+ this.isOpen = false;
+ this.onClose.emit(this);
+ this.modalEl.nativeElement.classList.remove('modalDialog');
+ }
+
+}
+
+@NgModule({
+ declarations: [Modal],
+ exports: [Modal],
+ imports: [CommonModule]
+})
+export class ModalModule {}
\ No newline at end of file
diff --git a/src/radio/radio.spec.ts b/src/radio/radio.spec.ts
new file mode 100644
index 00000000000..fb00bd6e6a0
--- /dev/null
+++ b/src/radio/radio.spec.ts
@@ -0,0 +1,73 @@
+import {
+ async,
+ TestBed
+} from "@angular/core/testing";
+import { FormsModule } from '@angular/forms';
+import { Component, ViewChildren } from "@angular/core";
+import { By } from "@angular/platform-browser";
+import { IgRadio } from './radio';
+
+describe('IgRadio', function() {
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ InitRadio,
+ RadioWithModel,
+ IgRadio
+ ],
+ imports: [FormsModule]
+ })
+ .compileComponents();
+ }));
+
+ it('Init a radio', () => {
+ let fixture = TestBed.createComponent(InitRadio);
+ fixture.detectChanges();
+
+ let nativeRadio = fixture.debugElement.query(By.css('input')).nativeElement;
+ let nativeLabel = fixture.debugElement.query(By.css('label')).nativeElement;
+
+ expect(nativeRadio).toBeTruthy();
+ expect(nativeRadio.type).toBe('radio');
+ expect(nativeLabel).toBeTruthy();
+ expect(nativeLabel.textContent.trim()).toEqual('Radio');
+ });
+
+ it('Binding to ngModel', () => {
+ let fixture = TestBed.createComponent(RadioWithModel);
+ fixture.detectChanges();
+
+ let radios = fixture.componentInstance.radios.toArray();
+
+ expect(radios.length).toEqual(3);
+
+ fixture.whenStable().then(() => {
+ fixture.detectChanges();
+ expect(radios[0].checked).toBe(true);
+
+ radios[1].nativeRadio.nativeElement.dispatchEvent(new Event('change'));
+ fixture.detectChanges();
+ fixture.whenStable().then(() => {
+ expect(radios[1].checked).toBe(true);
+ expect(radios[0].checked).toBe(false);
+ expect(fixture.componentInstance.selected).toEqual('Bar');
+ });
+ });
+ });
+});
+
+
+@Component({ template: `
Radio` })
+class InitRadio {}
+
+@Component({
+ template: `
+
{{item}}
+ `
+})
+class RadioWithModel {
+ @ViewChildren(IgRadio) radios;
+
+ selected = "Foo";
+}
\ No newline at end of file