diff --git a/DEV_DOCS.md b/DEV_DOCS.md
index 4536811a35..c8a33d7d09 100644
--- a/DEV_DOCS.md
+++ b/DEV_DOCS.md
@@ -429,7 +429,7 @@ _your-component.component.theme.scss (optional, styles that depends on theme var
- register your component in framework
````
-src/framework/theme/index.ts (add exports of your component and module)
+src/framework/theme/public_api.ts (add exports of your component and module)
src/framework/theme/styles/global/_components.scss (if you create _your-component.component.theme.scss you have to register mixin)
````
diff --git a/docs/assets/images/components/toggle.svg b/docs/assets/images/components/toggle.svg
new file mode 100644
index 0000000000..628423ba76
--- /dev/null
+++ b/docs/assets/images/components/toggle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/structure.ts b/docs/structure.ts
index e1aa71d677..2318e88da6 100644
--- a/docs/structure.ts
+++ b/docs/structure.ts
@@ -475,6 +475,14 @@ export const structure = [
'NbCheckboxComponent',
],
},
+ {
+ type: 'tabs',
+ name: 'Toggle',
+ icon: 'toggle.svg',
+ source: [
+ 'NbToggleComponent',
+ ],
+ },
{
type: 'tabs',
name: 'Radio',
diff --git a/e2e/toggle.e2e-spec.ts b/e2e/toggle.e2e-spec.ts
new file mode 100644
index 0000000000..a5855b4069
--- /dev/null
+++ b/e2e/toggle.e2e-spec.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { browser, by, element } from 'protractor';
+
+describe('nb-toggle', () => {
+ beforeEach((done) => {
+ browser.get('#/toggle/toggle-test.component').then(() => done());
+ });
+
+ it('should turn on on click', () => {
+ const input = element(by.css('#first input'));
+ const indicator = element(by.css('#first .toggle'));
+
+ expect(input.getAttribute('checked')).toBeFalsy();
+ indicator.click();
+ expect(input.getAttribute('checked')).toBeTruthy();
+ indicator.click();
+ expect(input.getAttribute('checked')).toBeFalsy();
+ });
+});
diff --git a/src/app/playground-components.ts b/src/app/playground-components.ts
index d606ddc59a..0f1edd6ed0 100644
--- a/src/app/playground-components.ts
+++ b/src/app/playground-components.ts
@@ -1323,6 +1323,47 @@ export const PLAYGROUND_COMPONENTS: ComponentLink[] = [
},
],
},
+ {
+ path: 'toggle',
+ children: [
+ {
+ path: 'toggle-disabled.component',
+ link: '/toggle/toggle-disabled.component',
+ component: 'ToggleDisabledComponent',
+ name: 'Toggle Disabled',
+ },
+ {
+ path: 'toggle-showcase.component',
+ link: '/toggle/toggle-showcase.component',
+ component: 'ToggleShowcaseComponent',
+ name: 'Toggle Showcase',
+ },
+ {
+ path: 'toggle-status.component',
+ link: '/toggle/toggle-status.component',
+ component: 'ToggleStatusComponent',
+ name: 'Toggle Status',
+ },
+ {
+ path: 'toggle-test.component',
+ link: '/toggle/toggle-test.component',
+ component: 'ToggleTestComponent',
+ name: 'Toggle Test',
+ },
+ {
+ path: 'toggle-label-position.component',
+ link: '/toggle/toggle-label-position.component',
+ component: 'ToggleLabelPositionComponent',
+ name: 'Toggle Label Position',
+ },
+ {
+ path: 'toggle-form.component',
+ link: '/toggle/toggle-form.component',
+ component: 'ToggleFormComponent',
+ name: 'Toggle Form',
+ },
+ ],
+ },
{
path: 'context-menu',
children: [
diff --git a/src/framework/theme/components/checkbox/checkbox.component.ts b/src/framework/theme/components/checkbox/checkbox.component.ts
index 9a27454ec7..69d1b87920 100644
--- a/src/framework/theme/components/checkbox/checkbox.component.ts
+++ b/src/framework/theme/components/checkbox/checkbox.component.ts
@@ -198,7 +198,7 @@ export class NbCheckboxComponent implements ControlValueAccessor {
/**
* Checkbox status.
- * Possible values are: `primary` (default), `success`, `warning`, `danger`, `info`
+ * Possible values are: `primary`, `success`, `warning`, `danger`, `info`
*/
@Input()
status: '' | NbComponentStatus = '';
diff --git a/src/framework/theme/components/toggle/_toggle.component.theme.scss b/src/framework/theme/components/toggle/_toggle.component.theme.scss
new file mode 100644
index 0000000000..705e6965ca
--- /dev/null
+++ b/src/framework/theme/components/toggle/_toggle.component.theme.scss
@@ -0,0 +1,130 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@mixin nb-toggle-theme() {
+ nb-toggle {
+ .toggle {
+ height: nb-theme(toggle-height);
+ width: nb-theme(toggle-width);
+ background-color: nb-theme(toggle-background-color);
+ border: nb-theme(toggle-border-width) solid nb-theme(toggle-border-color);
+ border-radius: nb-theme(toggle-border-radius);
+ cursor: nb-theme(toggle-cursor);
+ }
+
+ .toggle.checked {
+ background-color: nb-theme(toggle-primary-checked-background-color);
+ border-color: nb-theme(toggle-primary-checked-border-color);
+ }
+
+ .native-input {
+ &:focus + .toggle {
+ border-color: nb-theme(toggle-primary-focus-border-color);
+ box-shadow: 0 0 0 nb-theme(toggle-outline-width) nb-theme(toggle-outline-color);
+ }
+
+ &:active + .toggle {
+ background-color: nb-theme(toggle-primary-active-background-color);
+ border-color: nb-theme(toggle-primary-active-border-color);
+ }
+ }
+
+ .toggle:hover {
+ background-color: nb-theme(toggle-primary-hover-background-color);
+ border-color: nb-theme(toggle-primary-hover-border-color);
+ }
+
+ .native-input:disabled {
+ & + .toggle {
+ background-color: nb-theme(toggle-disabled-background-color);
+ border-color: nb-theme(toggle-disabled-border-color);
+ cursor: nb-theme(toggle-disabled-cursor);
+
+ nb-icon {
+ color: nb-theme(toggle-disabled-switcher-checkmark-color);
+ }
+ }
+
+ & ~ .text {
+ color: nb-theme(toggle-disabled-text-color);
+ }
+ }
+
+ .toggle-switcher {
+ width: nb-theme(toggle-switcher-size);
+ height: nb-theme(toggle-switcher-size);
+ background-color: nb-theme(toggle-switcher-background-color);
+
+ nb-icon {
+ color: nb-theme(toggle-switcher-checkmark-color);
+ }
+ }
+
+ .text {
+ color: nb-theme(toggle-text-color);
+ font-family: nb-theme(toggle-text-font-family);
+ font-size: nb-theme(toggle-text-font-size);
+ font-weight: nb-theme(toggle-text-font-weight);
+ line-height: nb-theme(toggle-text-line-height);
+ }
+ }
+
+ @each $status in nb-get-statuses() {
+ @include nb-toggle-status($status);
+ }
+}
+
+@mixin nb-toggle-status($status: '') {
+ nb-toggle.status-#{$status} {
+
+ .toggle {
+ background-color: nb-theme(toggle-#{$status}-background-color);
+ border-color: nb-theme(toggle-#{$status}-border-color);
+ }
+
+ .toggle.checked {
+ background-color: nb-theme(toggle-#{$status}-checked-background-color);
+ border-color: nb-theme(toggle-#{$status}-checked-border-color);
+ }
+
+ .native-input {
+ &:focus + .toggle {
+ border-color: nb-theme(toggle-#{$status}-focus-border-color);
+ }
+
+ &:active + .toggle {
+ background-color: nb-theme(toggle-#{$status}-active-background-color);
+ border-color: nb-theme(toggle-#{$status}-active-border-color);
+ }
+ }
+
+ .toggle:hover {
+ background-color: nb-theme(toggle-#{$status}-hover-background-color);
+ border-color: nb-theme(toggle-#{$status}-hover-border-color);
+ }
+
+ .toggle-switcher {
+ nb-icon {
+ color: nb-theme(toggle-#{$status}-checked-switcher-checkmark-color);
+ }
+ }
+
+ .native-input:disabled {
+ & + .toggle {
+ background-color: nb-theme(toggle-disabled-background-color);
+ border-color: nb-theme(toggle-disabled-border-color);
+
+ nb-icon {
+ color: nb-theme(toggle-disabled-switcher-checkmark-color);
+ }
+ }
+
+ & ~ .text {
+ color: nb-theme(toggle-disabled-text-color);
+ }
+ }
+ }
+}
diff --git a/src/framework/theme/components/toggle/toggle.component.scss b/src/framework/theme/components/toggle/toggle.component.scss
new file mode 100644
index 0000000000..48d52487b8
--- /dev/null
+++ b/src/framework/theme/components/toggle/toggle.component.scss
@@ -0,0 +1,59 @@
+@import '../../styles/core/mixins';
+
+:host {
+ display: inline-flex;
+ outline: none;
+}
+
+:host(.toggle-label-left) .text {
+ padding-right: 0.6875rem;
+ @include nb-ltr(order, -1);
+ @include nb-rtl(order, 1);
+}
+
+:host(.toggle-label-right) .text {
+ padding-left: 0.6875rem;
+ @include nb-ltr(order, 1);
+ @include nb-rtl(order, -1);
+}
+
+:host(.toggle-label-start) .toggle-label {
+ flex-direction: row-reverse;
+
+ .text {
+ @include nb-ltr(padding-right, 0.6875rem);
+ @include nb-rtl(padding-left, 0.6875rem);
+ }
+}
+
+:host(.toggle-label-end) .text {
+ @include nb-ltr(padding-left, 0.6875rem);
+ @include nb-rtl(padding-right, 0.6875rem);
+}
+
+.toggle-label {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+}
+
+.toggle {
+ position: relative;
+ display: inline-flex;
+ box-sizing: content-box;
+ @include nb-component-animation(background-color, border, box-shadow);
+}
+
+.toggle-switcher {
+ position: absolute;
+ border-radius: 50%;
+ margin: 1px;
+
+ nb-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 40%;
+ }
+}
diff --git a/src/framework/theme/components/toggle/toggle.component.ts b/src/framework/theme/components/toggle/toggle.component.ts
new file mode 100644
index 0000000000..4be25c5344
--- /dev/null
+++ b/src/framework/theme/components/toggle/toggle.component.ts
@@ -0,0 +1,333 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import {
+ Component,
+ Input,
+ HostBinding,
+ forwardRef,
+ ChangeDetectorRef,
+ OnInit,
+ Output,
+ EventEmitter,
+ OnDestroy,
+ ChangeDetectionStrategy,
+} from '@angular/core';
+import { trigger, state, style, animate, transition } from '@angular/animations';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { NbLayoutDirectionService, NbLayoutDirection } from '../../services/direction.service';
+import { NbComponentStatus } from '../component-status';
+
+import { convertToBoolProperty } from '../helpers';
+
+/**
+ * Styled toggle component
+ *
+ * @stacked-example(Showcase, toggle/toggle-showcase.component)
+ *
+ * ### Installation
+ *
+ * Import `NbToggleComponent` to your feature module.
+ * ```ts
+ * @NgModule({
+ * imports: [
+ * // ...
+ * NbToggleModule,
+ * ],
+ * })
+ * export class PageModule { }
+ * ```
+ * ### Usage
+ *
+ * Toggle may have one of the following statuses: `primary`, `success`, `warning`, `danger`, `info`
+ *
+ * @stacked-example(Colored Toggles, toggle/toggle-status.component)
+ *
+ * You can disable toggle
+ *
+ * @stacked-example(Disabled Toggles, toggle/toggle-disabled.component)
+ *
+ * Toggle may have a label with following positions: `left`, `right`, `start`, `end` (default)
+ *
+ * @stacked-example(Toggles With Labels, toggle/toggle-label-position.component.ts)
+ *
+ * You can set checked state via `checked` binding:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Or you can set control value via reactive forms or ngModel bindings:
+ *
+ * @stacked-example(Toggle form binding, toggle/toggle-form.component)
+ *
+ * @styles
+ *
+ * toggle-height:
+ * toggle-width:
+ * toggle-border-width:
+ * toggle-border-radius:
+ * toggle-border-color:
+ * toggle-background-color:
+ * toggle-outline-width:
+ * toggle-outline-color:
+ * toggle-switcher-size:
+ * toggle-switcher-background-color:
+ * toggle-switcher-checkmark-color:
+ * toggle-text-color:
+ * toggle-text-font-family:
+ * toggle-text-font-size:
+ * toggle-text-font-weight:
+ * toggle-text-line-height:
+ * toggle-cursor:
+ * toggle-disabled-background-color:
+ * toggle-disabled-border-color:
+ * toggle-disabled-switcher-checkmark-color:
+ * toggle-disabled-text-color:
+ * toggle-disabled-cursor:
+ * toggle-primary-background-color:
+ * toggle-primary-border-color:
+ * toggle-primary-checked-background-color:
+ * toggle-primary-checked-border-color:
+ * toggle-primary-checked-switcher-checkmark-color:
+ * toggle-primary-focus-border-color:
+ * toggle-primary-hover-background-color:
+ * toggle-primary-hover-border-color:
+ * toggle-primary-active-background-color:
+ * toggle-primary-active-border-color:
+ * toggle-success-background-color:
+ * toggle-success-border-color:
+ * toggle-success-checked-background-color:
+ * toggle-success-checked-border-color:
+ * toggle-success-checked-switcher-checkmark-color:
+ * toggle-success-focus-border-color:
+ * toggle-success-hover-background-color:
+ * toggle-success-hover-border-color:
+ * toggle-success-active-background-color:
+ * toggle-success-active-border-color:
+ * toggle-info-background-color:
+ * toggle-info-border-color:
+ * toggle-info-checked-background-color:
+ * toggle-info-checked-border-color:
+ * toggle-info-checked-switcher-checkmark-color:
+ * toggle-info-focus-border-color:
+ * toggle-info-hover-background-color:
+ * toggle-info-hover-border-color:
+ * toggle-info-active-background-color:
+ * toggle-info-active-border-color:
+ * toggle-warning-background-color:
+ * toggle-warning-border-color:
+ * toggle-warning-checked-background-color:
+ * toggle-warning-checked-border-color:
+ * toggle-warning-checked-switcher-checkmark-color:
+ * toggle-warning-focus-border-color:
+ * toggle-warning-hover-background-color:
+ * toggle-warning-hover-border-color:
+ * toggle-warning-active-background-color:
+ * toggle-warning-active-border-color:
+ * toggle-danger-background-color:
+ * toggle-danger-border-color:
+ * toggle-danger-checked-background-color:
+ * toggle-danger-checked-border-color:
+ * toggle-danger-checked-switcher-checkmark-color:
+ * toggle-danger-focus-border-color:
+ * toggle-danger-hover-background-color:
+ * toggle-danger-hover-border-color:
+ * toggle-danger-active-background-color:
+ * toggle-danger-active-border-color:
+ */
+@Component({
+ selector: 'nb-toggle',
+ animations: [
+ trigger('onOff', [
+ state('ltrOn', style({ right: 0 })),
+ state('rtlOn', style({ left: 0 })),
+ transition(':enter', [animate(0)]),
+ transition('* <=> *', [animate('0.15s')]),
+ ]),
+ ],
+ template: `
+
+ `,
+ styleUrls: [ `./toggle.component.scss` ],
+ providers: [{
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => NbToggleComponent),
+ multi: true,
+ }],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NbToggleComponent implements OnInit, OnDestroy, ControlValueAccessor {
+
+ onChange: any = () => { };
+ onTouched: any = () => { };
+
+ private destroy$ = new Subject();
+
+ /**
+ * Toggle checked
+ * @type {boolean}
+ */
+ @Input()
+ get checked(): boolean {
+ return this._checked;
+ }
+ set checked(value: boolean) {
+ this._checked = value;
+ }
+ private _checked: boolean = false;
+
+ /**
+ * Controls input disabled state
+ */
+ @Input()
+ get disabled(): boolean {
+ return this._disabled;
+ }
+ set disabled(value: boolean) {
+ this._disabled = convertToBoolProperty(value);
+ }
+ private _disabled: boolean = false;
+
+ /**
+ * Toggle status.
+ * Possible values are: `primary`, `success`, `warning`, `danger`, `info`
+ */
+ @Input()
+ status: '' | NbComponentStatus = '';
+
+ /**
+ * Toggle label position.
+ * Possible values are: `left`, `right`, `start`, `end` (default)
+ */
+ @Input() labelPosition: 'left' | 'right' | 'start' | 'end' = 'end';
+
+ /**
+ * Output when checked state is changed by a user
+ * @type EventEmitter
+ */
+ @Output() checkedChange = new EventEmitter();
+
+ @HostBinding('class.status-primary')
+ get primary() {
+ return this.status === 'primary';
+ }
+
+ @HostBinding('class.status-success')
+ get success() {
+ return this.status === 'success';
+ }
+
+ @HostBinding('class.status-warning')
+ get warning() {
+ return this.status === 'warning';
+ }
+
+ @HostBinding('class.status-danger')
+ get danger() {
+ return this.status === 'danger';
+ }
+
+ @HostBinding('class.status-info')
+ get info() {
+ return this.status === 'info';
+ }
+
+ @HostBinding('class.toggle-label-left')
+ get labelLeft() {
+ return this.labelPosition === 'left';
+ }
+
+ @HostBinding('class.toggle-label-right')
+ get labelRight() {
+ return this.labelPosition === 'right';
+ }
+
+ @HostBinding('class.toggle-label-start')
+ get labelStart() {
+ return this.labelPosition === 'start';
+ }
+
+ @HostBinding('class.toggle-label-end')
+ get labelEnd() {
+ return this.labelPosition === 'end';
+ }
+
+ constructor(
+ private changeDetector: ChangeDetectorRef,
+ private layoutDirection: NbLayoutDirectionService,
+ ) {}
+
+ ngOnInit(): void {
+ this.layoutDirection.onDirectionChange()
+ .pipe(takeUntil(this.destroy$))
+ .subscribe(() => this.changeDetector.detectChanges());
+ }
+
+ ngOnDestroy() {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
+ checkState(): string {
+ if (this.checked) {
+ if (this.layoutDirection.getDirection() === NbLayoutDirection.LTR) {
+ return 'ltrOn';
+ } else {
+ return 'rtlOn';
+ }
+ }
+ }
+
+ registerOnChange(fn: any) {
+ this.onChange = fn;
+ }
+
+ registerOnTouched(fn: any) {
+ this.onTouched = fn;
+ }
+
+ writeValue(val: any) {
+ this.checked = val;
+ this.changeDetector.markForCheck();
+ }
+
+ setDisabledState(val: boolean) {
+ this.disabled = convertToBoolProperty(val);
+ this.changeDetector.markForCheck();
+ }
+
+ updateValue(event: Event): void {
+ const input = (event.target as HTMLInputElement);
+ this.checked = input.checked;
+ this.checkedChange.emit(this.checked);
+ this.onChange(this.checked);
+ }
+
+ onInputClick(event: Event) {
+ event.stopPropagation();
+ }
+}
diff --git a/src/framework/theme/components/toggle/toggle.module.ts b/src/framework/theme/components/toggle/toggle.module.ts
new file mode 100644
index 0000000000..cb1f04b571
--- /dev/null
+++ b/src/framework/theme/components/toggle/toggle.module.ts
@@ -0,0 +1,21 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { NbIconModule } from '../icon/icon.module';
+
+import { NbToggleComponent } from './toggle.component';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ NbIconModule,
+ ],
+ declarations: [NbToggleComponent],
+ exports: [NbToggleComponent],
+})
+export class NbToggleModule { }
diff --git a/src/framework/theme/components/toggle/toggle.spec.ts b/src/framework/theme/components/toggle/toggle.spec.ts
new file mode 100644
index 0000000000..fc3efc11a1
--- /dev/null
+++ b/src/framework/theme/components/toggle/toggle.spec.ts
@@ -0,0 +1,137 @@
+import { NbToggleModule } from '@nebular/theme/components/toggle/toggle.module';
+import { NbToggleComponent } from './toggle.component';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { Component, DebugElement } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { ReactiveFormsModule, FormControl } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { NbLayoutDirectionService } from '../../services/direction.service';
+
+
+describe('Component: NbToggle', () => {
+ let toggle: NbToggleComponent;
+ let fixture: ComponentFixture;
+ let toggleInput: DebugElement;
+ let testContainerEl: HTMLElement;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [BrowserAnimationsModule, NbToggleModule],
+ providers: [NbLayoutDirectionService],
+ });
+
+ fixture = TestBed.createComponent(NbToggleComponent);
+ toggle = fixture.componentInstance;
+ testContainerEl = fixture.elementRef.nativeElement;
+
+ toggleInput = fixture.debugElement.query(By.css('input'));
+ });
+
+ it('Setting `disabled` to `true` disables toggle input', () => {
+ toggle.disabled = true;
+ fixture.detectChanges();
+ expect(toggleInput.nativeElement.disabled).toBeTruthy();
+ });
+
+ it('Setting `disabled` to `false` enables toggle input', () => {
+ toggle.disabled = false;
+ fixture.detectChanges();
+ expect(toggleInput.nativeElement.disabled).toBeFalsy();
+ });
+
+ it('Setting `checked` to `true` makes toggle input on', () => {
+ toggle.checked = true;
+ fixture.detectChanges();
+ expect(toggleInput.nativeElement.checked).toBeTruthy();
+ });
+
+ it('Setting `checked` to `false` makes toggle input off', () => {
+ toggle.checked = false;
+ fixture.detectChanges();
+ expect(toggleInput.nativeElement.checked).toBeFalsy();
+ });
+
+ it('Setting `status` to `primary` apply corresponding class to host element', () => {
+ toggle.status = 'primary';
+ fixture.detectChanges();
+ expect(testContainerEl.classList.contains('status-primary')).toBeTruthy();
+ });
+
+ it('Setting `status` to `success` apply corresponding class to host element', () => {
+ toggle.status = 'success';
+ fixture.detectChanges();
+ expect(testContainerEl.classList.contains('status-success')).toBeTruthy();
+ });
+
+ it('Setting `status` to `warning` apply corresponding class to host element', () => {
+ toggle.status = 'warning';
+ fixture.detectChanges();
+ expect(testContainerEl.classList.contains('status-warning')).toBeTruthy();
+ });
+
+ it('Setting `status` to `danger` apply corresponding class to host element', () => {
+ toggle.status = 'danger';
+ fixture.detectChanges();
+ expect(testContainerEl.classList.contains('status-danger')).toBeTruthy();
+ });
+
+ it('Setting `status` to `info` apply corresponding class to host element', () => {
+ toggle.status = 'info';
+ fixture.detectChanges();
+ expect(testContainerEl.classList.contains('status-info')).toBeTruthy();
+ });
+});
+
+// Test component with reactive forms
+@Component({
+ template: ``,
+})
+class ToggleWithFormControlComponent {
+ formControl = new FormControl();
+}
+
+describe('Component: NbToggle with form control', () => {
+ let fixture: ComponentFixture;
+ let toggleComponent: DebugElement;
+ let toggleInstance: NbToggleComponent;
+ let testComponent: ToggleWithFormControlComponent;
+ let inputElement: HTMLInputElement;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [ReactiveFormsModule, BrowserAnimationsModule, NbToggleModule],
+ providers: [NbLayoutDirectionService],
+ declarations: [ToggleWithFormControlComponent],
+ });
+
+ fixture = TestBed.createComponent(ToggleWithFormControlComponent);
+ fixture.detectChanges();
+
+ toggleComponent = fixture.debugElement.query(
+ By.directive(NbToggleComponent),
+ );
+
+ toggleInstance = toggleComponent.componentInstance;
+ testComponent = fixture.debugElement.componentInstance;
+
+ inputElement = (
+ toggleComponent.nativeElement.querySelector('input')
+ );
+ });
+
+ it('Toggling form control `disabled` state properly applied', () => {
+ expect(toggleInstance.disabled).toBeFalsy();
+
+ testComponent.formControl.disable();
+ fixture.detectChanges();
+
+ expect(toggleInstance.disabled).toBeTruthy();
+ expect(inputElement.disabled).toBeTruthy();
+
+ testComponent.formControl.enable();
+ fixture.detectChanges();
+
+ expect(toggleInstance.disabled).toBeFalsy();
+ expect(inputElement.disabled).toBeFalsy();
+ });
+});
diff --git a/src/framework/theme/public_api.ts b/src/framework/theme/public_api.ts
index 14a1a5099b..59f3da2f89 100644
--- a/src/framework/theme/public_api.ts
+++ b/src/framework/theme/public_api.ts
@@ -205,3 +205,5 @@ export * from './components/icon/icon.component';
export * from './components/icon/icon';
export * from './components/icon/icon-pack';
export * from './components/icon/icon-libraries';
+export * from './components/toggle/toggle.module';
+export * from './components/toggle/toggle.component';
diff --git a/src/framework/theme/styles/global/_components.scss b/src/framework/theme/styles/global/_components.scss
index e000132e8b..1479c6c6c3 100644
--- a/src/framework/theme/styles/global/_components.scss
+++ b/src/framework/theme/styles/global/_components.scss
@@ -18,6 +18,7 @@
@import '../../components/actions/actions.component.theme';
@import '../../components/search/search.component.theme';
@import '../../components/checkbox/checkbox.component.theme';
+@import '../../components/toggle/toggle.component.theme';
@import '../../components/progress-bar/progress-bar.component.theme';
@import '../../components/badge/badge.component.theme';
@import '../../components/alert/alert.component.theme';
@@ -56,6 +57,7 @@
@include nb-search-theme();
@include nb-spinner-theme();
@include nb-checkbox-theme();
+ @include nb-toggle-theme();
@include nb-progress-bar-theme();
@include nb-badge-theme();
@include nb-stepper-theme();
diff --git a/src/framework/theme/styles/themes/_mapping.scss b/src/framework/theme/styles/themes/_mapping.scss
index f7ab0d6e49..dff793f7b8 100644
--- a/src/framework/theme/styles/themes/_mapping.scss
+++ b/src/framework/theme/styles/themes/_mapping.scss
@@ -1761,4 +1761,84 @@ $eva-mapping: (
icon-success-color: color-success-default,
icon-warning-color: color-warning-default,
icon-danger-color: color-danger-default,
+
+ toggle-height: 1.875rem,
+ toggle-width: 3.125rem,
+ toggle-border-width: 1px,
+ toggle-border-radius: 100px,
+ toggle-border-color: border-basic-color-4,
+ toggle-background-color: background-basic-color-3,
+ toggle-outline-width: outline-width,
+ toggle-outline-color: outline-color,
+ toggle-switcher-size: 1.75rem,
+ toggle-switcher-background-color: background-basic-color-1,
+ toggle-switcher-checkmark-color: color-primary-default,
+ toggle-text-color: text-basic-color,
+ toggle-text-font-family: text-subtitle-2-font-family,
+ toggle-text-font-size: text-subtitle-2-font-size,
+ toggle-text-font-weight: text-subtitle-2-font-weight,
+ toggle-text-line-height: text-subtitle-2-line-height,
+ toggle-cursor: pointer,
+
+ toggle-disabled-background-color: background-basic-color-2,
+ toggle-disabled-border-color: border-basic-color-3,
+ toggle-disabled-switcher-checkmark-color: border-basic-color-3,
+ toggle-disabled-text-color: text-disabled-color,
+ toggle-disabled-cursor: default,
+
+ toggle-primary-background-color: background-basic-color-2,
+ toggle-primary-border-color: color-primary-default,
+ toggle-primary-checked-background-color: color-primary-default,
+ toggle-primary-checked-border-color: color-primary-default,
+ toggle-primary-checked-switcher-checkmark-color: color-primary-default,
+ toggle-primary-focus-border-color: color-primary-700,
+ toggle-primary-hover-background-color: color-primary-400,
+ toggle-primary-hover-border-color: color-primary-400,
+ toggle-primary-active-background-color: color-primary-600,
+ toggle-primary-active-border-color: color-primary-600,
+
+ toggle-success-background-color: background-basic-color-2,
+ toggle-success-border-color: color-success-default,
+ toggle-success-checked-background-color: color-success-default,
+ toggle-success-checked-border-color: color-success-default,
+ toggle-success-checked-switcher-checkmark-color: color-success-default,
+ toggle-success-focus-border-color: color-success-700,
+ toggle-success-hover-background-color: color-success-400,
+ toggle-success-hover-border-color: color-success-400,
+ toggle-success-active-background-color: color-success-600,
+ toggle-success-active-border-color: color-success-600,
+
+ toggle-info-background-color: background-basic-color-2,
+ toggle-info-border-color: color-info-default,
+ toggle-info-checked-background-color: color-info-default,
+ toggle-info-checked-border-color: color-info-default,
+ toggle-info-checked-switcher-checkmark-color: color-info-default,
+ toggle-info-focus-border-color: color-info-700,
+ toggle-info-hover-background-color: color-info-400,
+ toggle-info-hover-border-color: color-info-400,
+ toggle-info-active-background-color: color-info-600,
+ toggle-info-active-border-color: color-info-600,
+
+ toggle-warning-background-color: background-basic-color-2,
+ toggle-warning-border-color: color-warning-default,
+ toggle-warning-checked-background-color: color-warning-default,
+ toggle-warning-checked-border-color: color-warning-default,
+ toggle-warning-checked-switcher-checkmark-color: color-warning-default,
+ toggle-warning-focus-border-color: color-warning-700,
+ toggle-warning-hover-background-color: color-warning-400,
+ toggle-warning-hover-border-color: color-warning-400,
+ toggle-warning-active-background-color: color-warning-600,
+ toggle-warning-active-border-color: color-warning-600,
+
+ toggle-danger-background-color: background-basic-color-2,
+ toggle-danger-border-color: color-danger-default,
+ toggle-danger-checked-background-color: color-danger-default,
+ toggle-danger-checked-border-color: color-danger-default,
+ toggle-danger-checked-switcher-checkmark-color: color-danger-default,
+ toggle-danger-focus-border-color: color-danger-700,
+ toggle-danger-hover-background-color: color-danger-400,
+ toggle-danger-hover-border-color: color-danger-400,
+ toggle-danger-active-background-color: color-danger-600,
+ toggle-danger-active-border-color: color-danger-600,
+
);
diff --git a/src/playground/with-layout/toggle/toggle-disabled.component.ts b/src/playground/with-layout/toggle/toggle-disabled.component.ts
new file mode 100644
index 0000000000..83d8cf79ca
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle-disabled.component.ts
@@ -0,0 +1,21 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nb-toggle-disabled',
+ template: `
+
+
+
+
+
+
+ `,
+})
+export class ToggleDisabledComponent {
+}
diff --git a/src/playground/with-layout/toggle/toggle-form.component.ts b/src/playground/with-layout/toggle/toggle-form.component.ts
new file mode 100644
index 0000000000..ba3daf1f72
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle-form.component.ts
@@ -0,0 +1,27 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+import { FormControl } from '@angular/forms';
+
+@Component({
+ selector: 'nb-toggle-form',
+ template: `
+
+
+ Toggle with NgModel
+ Toggle with FormControl
+
+
+ `,
+})
+export class ToggleFormComponent {
+
+ toggleNgModel = true;
+
+ toggleFormControl = new FormControl();
+
+}
diff --git a/src/playground/with-layout/toggle/toggle-label-position.component.ts b/src/playground/with-layout/toggle/toggle-label-position.component.ts
new file mode 100644
index 0000000000..92b826c31e
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle-label-position.component.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nb-toggle-label-position',
+ template: `
+
+
+ Label Start
+ Label End
+ Label Right
+ Label Left
+ Label Default Disabled
+
+
+ `,
+})
+export class ToggleLabelPositionComponent {
+}
diff --git a/src/playground/with-layout/toggle/toggle-routing.module.ts b/src/playground/with-layout/toggle/toggle-routing.module.ts
new file mode 100644
index 0000000000..17e707da92
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle-routing.module.ts
@@ -0,0 +1,47 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgModule } from '@angular/core';
+import { RouterModule, Route} from '@angular/router';
+import { ToggleDisabledComponent } from './toggle-disabled.component';
+import { ToggleFormComponent } from './toggle-form.component';
+import { ToggleLabelPositionComponent } from './toggle-label-position.component';
+import { ToggleShowcaseComponent } from './toggle-showcase.component';
+import { ToggleStatusComponent } from './toggle-status.component';
+import { ToggleTestComponent } from './toggle-test.component';
+
+const routes: Route[] = [
+ {
+ path: 'toggle-disabled.component',
+ component: ToggleDisabledComponent,
+ },
+ {
+ path: 'toggle-showcase.component',
+ component: ToggleShowcaseComponent,
+ },
+ {
+ path: 'toggle-status.component',
+ component: ToggleStatusComponent,
+ },
+ {
+ path: 'toggle-test.component',
+ component: ToggleTestComponent,
+ },
+ {
+ path: 'toggle-label-position.component',
+ component: ToggleLabelPositionComponent,
+ },
+ {
+ path: 'toggle-form.component',
+ component: ToggleFormComponent,
+ },
+];
+
+@NgModule({
+ imports: [ RouterModule.forChild(routes) ],
+ exports: [ RouterModule ],
+})
+export class ToggleRoutingModule {}
diff --git a/src/playground/with-layout/toggle/toggle-showcase.component.ts b/src/playground/with-layout/toggle/toggle-showcase.component.ts
new file mode 100644
index 0000000000..7d7a744932
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle-showcase.component.ts
@@ -0,0 +1,20 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nb-toggle-showcase',
+ template: `
+
+
+
+
+
+ `,
+})
+export class ToggleShowcaseComponent {
+}
diff --git a/src/playground/with-layout/toggle/toggle-status.component.ts b/src/playground/with-layout/toggle/toggle-status.component.ts
new file mode 100644
index 0000000000..48f5785741
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle-status.component.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nb-toggle-status',
+ template: `
+
+
+
+
+
+
+
+
+
+ `,
+})
+export class ToggleStatusComponent {
+}
diff --git a/src/playground/with-layout/toggle/toggle-test.component.ts b/src/playground/with-layout/toggle/toggle-test.component.ts
new file mode 100644
index 0000000000..373b8aaa00
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle-test.component.ts
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nb-app-toggle-test',
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+})
+export class ToggleTestComponent {
+}
diff --git a/src/playground/with-layout/toggle/toggle.module.ts b/src/playground/with-layout/toggle/toggle.module.ts
new file mode 100644
index 0000000000..57a6f9ec01
--- /dev/null
+++ b/src/playground/with-layout/toggle/toggle.module.ts
@@ -0,0 +1,35 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { NbToggleModule, NbCardModule } from '@nebular/theme';
+import { ToggleFormComponent } from './toggle-form.component';
+import { ToggleLabelPositionComponent } from './toggle-label-position.component';
+import { ToggleRoutingModule } from './toggle-routing.module';
+import { ToggleDisabledComponent } from './toggle-disabled.component';
+import { ToggleShowcaseComponent } from './toggle-showcase.component';
+import { ToggleStatusComponent } from './toggle-status.component';
+import { ToggleTestComponent } from './toggle-test.component';
+
+@NgModule({
+ declarations: [
+ ToggleDisabledComponent,
+ ToggleShowcaseComponent,
+ ToggleStatusComponent,
+ ToggleTestComponent,
+ ToggleLabelPositionComponent,
+ ToggleFormComponent,
+ ],
+ imports: [
+ FormsModule,
+ ReactiveFormsModule,
+ NbCardModule,
+ NbToggleModule,
+ ToggleRoutingModule,
+ ],
+})
+export class ToggleModule {}
diff --git a/src/playground/with-layout/with-layout-routing.module.ts b/src/playground/with-layout/with-layout-routing.module.ts
index ebe202eccd..f67a1ed750 100644
--- a/src/playground/with-layout/with-layout-routing.module.ts
+++ b/src/playground/with-layout/with-layout-routing.module.ts
@@ -149,6 +149,10 @@ const routes: Route[] = [
path: 'icon',
loadChildren: './icon/icon.module#IconModule',
},
+ {
+ path: 'toggle',
+ loadChildren: './toggle/toggle.module#ToggleModule',
+ },
],
},
];