Skip to content

Commit 9034dcf

Browse files
authored
Merge branch 'master' into master
2 parents 06f0679 + be171de commit 9034dcf

File tree

6 files changed

+190
-54
lines changed

6 files changed

+190
-54
lines changed

src/dialog/tooltip/tooltip.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ storiesOf("Tooltip", module)
99
.addDecorator(
1010
moduleMetadata({
1111
imports: [
12-
DialogModule,
12+
DialogModule
1313
]
1414
})
1515
)

src/select/select.component.ts

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,137 @@
1-
import { Component, Input } from "@angular/core";
1+
import {
2+
Component,
3+
Input,
4+
Output,
5+
ViewChild,
6+
ElementRef,
7+
HostListener,
8+
EventEmitter
9+
} from "@angular/core";
10+
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
211

12+
/**
13+
* `ibm-select` provides a styled `select` component.
14+
*
15+
* Example:
16+
*
17+
* ```
18+
* <ibm-select [(ngModel)]="model">
19+
* <option value="default" disabled selected hidden>Choose an option</option>
20+
* <option value="option1">Option 1</option>
21+
* <option value="option2">Option 2</option>
22+
* <option value="option3">Option 3</option>
23+
* </ibm-select>
24+
* ```
25+
26+
*/
327
@Component({
428
selector: "ibm-select",
529
template: `
630
<div class="bx--form-item">
731
<div class="bx--select">
832
<label [attr.for]="id" class="bx--label">{{label}}</label>
9-
<select [attr.id]="id" class="bx--select-input">
33+
<select
34+
#select
35+
[attr.id]="id"
36+
[disabled]="disabled"
37+
(change)="onChange($event)"
38+
class="bx--select-input">
1039
<ng-content></ng-content>
1140
</select>
1241
<svg class="bx--select__arrow" width="10" height="5" viewBox="0 0 10 5">
1342
<path d="M0 0l5 4.998L10 0z" fill-rule="evenodd" />
1443
</svg>
1544
</div>
1645
</div>
17-
`
46+
`,
47+
providers: [
48+
{
49+
provide: NG_VALUE_ACCESSOR,
50+
useExisting: Select,
51+
multi: true
52+
}
53+
]
1854
})
19-
export class Select {
55+
export class Select implements ControlValueAccessor {
56+
/**
57+
* Tracks the total number of selects instantiated. Used to generate unique IDs
58+
*/
2059
static selectCount = 0;
60+
/**
61+
* Label for the select. Appears above the input.
62+
*/
2163
@Input() label = "Select label";
64+
/**
65+
* Sets the unique ID. Defaults to `select-${total count of selects instantiated}`
66+
*/
2267
@Input() id = `select-${Select.selectCount++}`;
68+
/**
69+
* Set to true to disable component.
70+
*/
71+
@Input() disabled = false;
72+
/**
73+
* emits the selected options `value`
74+
*/
75+
@Output() selected = new EventEmitter();
76+
77+
@ViewChild("select") select: ElementRef;
78+
79+
get value() {
80+
return this.select.nativeElement.value;
81+
}
82+
83+
set value(v) {
84+
this.select.nativeElement.value = v;
85+
}
86+
87+
/**
88+
* Receives a value from the model.
89+
*/
90+
writeValue(obj: any) {
91+
this.value = obj;
92+
}
93+
94+
/**
95+
* Registers a listener that notifies the model when the control updates
96+
*/
97+
registerOnChange(fn: any) {
98+
this.onChangeHandler = fn;
99+
}
100+
101+
/**
102+
* Registers a listener that notifies the model when the control is blurred
103+
*/
104+
registerOnTouched(fn: any) {
105+
this.onTouchedHandler = fn;
106+
}
107+
108+
/**
109+
* Sets the disabled state through the model
110+
*/
111+
setDisabledState(isDisabled: boolean) {
112+
this.disabled = isDisabled;
113+
}
114+
115+
/**
116+
* Handles the change event from the `select`.
117+
* Sends events to the change handler and emits a `selected` event.
118+
*/
119+
onChange(event) {
120+
this.onChangeHandler(event.target.value);
121+
this.selected.emit(event.target.value);
122+
}
123+
124+
/**
125+
* placeholder declarations. Replaced by the functions provided to `registerOnChange` and `registerOnTouched`
126+
*/
127+
private onChangeHandler = (_: any) => { };
128+
private onTouchedHandler = () => { };
129+
130+
/**
131+
* Listens for the host blurring, and notifies the model
132+
*/
133+
@HostListener("blur")
134+
private blur() {
135+
this.onTouchedHandler();
136+
}
23137
}

src/select/select.stories.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,30 @@ storiesOf("Select", module).addDecorator(
1414
template: `
1515
<ibm-select>
1616
<option value="" disabled selected hidden>Choose an option</option>
17-
<option value="solong">A much longer option that is worth having around to check how text flows</option>
18-
<optgroup label="Category 1">
19-
<option value="option1">Option 1</option>
20-
<option value="option2">Option 2</option>
21-
</optgroup>
22-
<optgroup label="Category 2">
23-
<option value="option1">Option 1</option>
24-
<option value="option2">Option 2</option>
25-
</optgroup>
17+
<option value="solong">A much longer option that is worth having around to check how text flows</option>
18+
<optgroup label="Category 1">
19+
<option value="option1">Option 1</option>
20+
<option value="option2">Option 2</option>
21+
</optgroup>
22+
<optgroup label="Category 2">
23+
<option value="option1">Option 1</option>
24+
<option value="option2">Option 2</option>
25+
</optgroup>
2626
</ibm-select>
2727
`
28+
}))
29+
.add("With ngModel", () => ({
30+
template: `
31+
<ibm-select [(ngModel)]="model">
32+
<option value="default" disabled selected hidden>Choose an option</option>
33+
<option value="option1">Option 1</option>
34+
<option value="option2">Option 2</option>
35+
<option value="option3">Option 3</option>
36+
</ibm-select>
37+
<br>
38+
<span>Selected: {{ model }}</span>
39+
`,
40+
props: {
41+
model: "default"
42+
}
2843
}));

src/switch/switch.component.spec.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import { DebugElement } from "@angular/core";
55
import { StaticIconModule } from "../icon/static-icon.module";
66

77
import { SwitchComponent } from "./switch.component";
8+
import { CheckboxComponent } from "../checkbox/checkbox.module";
89

910
describe("SwitchComponent", () => {
1011
let component: SwitchComponent;
1112
let fixture: ComponentFixture<SwitchComponent>;
12-
let de: DebugElement;
13-
let el: HTMLElement;
13+
let labelElement: HTMLElement;
1414
let buttonElement: HTMLElement;
15+
let svgElement: HTMLElement;
1516

1617
beforeEach(() => {
1718
TestBed.configureTestingModule({
@@ -22,15 +23,22 @@ describe("SwitchComponent", () => {
2223

2324
fixture = TestBed.createComponent(SwitchComponent);
2425
component = fixture.componentInstance;
25-
de = fixture.debugElement.query(By.css("label"));
26-
el = de.nativeElement;
26+
fixture.detectChanges();
27+
labelElement = fixture.debugElement.query(By.css("label")).nativeElement;
2728
buttonElement = fixture.debugElement.query(By.css("input")).nativeElement;
2829
});
2930

3031
it("should work", () => {
3132
expect(component instanceof SwitchComponent).toBe(true);
3233
});
3334

35+
it("should have input with class 'bx--toggle'", () => {
36+
expect(buttonElement.className.includes("bx--toggle")).toEqual(true);
37+
component.size = "sm";
38+
fixture.detectChanges();
39+
expect(buttonElement.className.includes("bx--toggle")).toEqual(true);
40+
});
41+
3442
it("should change state", () => {
3543
buttonElement.click();
3644
fixture.detectChanges();
@@ -40,4 +48,20 @@ describe("SwitchComponent", () => {
4048
fixture.detectChanges();
4149
expect(component.checked).toBe(false, "setting to off");
4250
});
51+
52+
it("should display small version of switch when size equals sm", () => {
53+
expect(buttonElement.className.includes("bx--toggle--small")).toEqual(false);
54+
component.size = "sm";
55+
fixture.detectChanges();
56+
expect(buttonElement.className.includes("bx--toggle--small")).toEqual(true);
57+
});
58+
59+
it("should display SVG in small version of switch", () => {
60+
component.size = "sm";
61+
fixture.detectChanges();
62+
labelElement = fixture.debugElement.query(By.css("label")).nativeElement;
63+
expect(fixture.debugElement.query(By.css("svg")).nativeElement).not.toBeNull();
64+
expect(labelElement.innerHTML).toContain("bx--toggle__check");
65+
});
66+
4367
});

src/switch/switch.component.ts

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
import { CheckboxComponent } from "../checkbox/checkbox.component";
22
import {
3-
ChangeDetectionStrategy,
43
ChangeDetectorRef,
54
Component,
6-
ElementRef,
7-
EventEmitter,
8-
forwardRef,
9-
Input,
10-
OnInit,
11-
Output,
12-
Renderer2,
13-
ViewChild
5+
Input
146
} from "@angular/core";
15-
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from "@angular/forms";
7+
import { NG_VALUE_ACCESSOR } from "@angular/forms";
168

179

1810
/**
@@ -61,16 +53,26 @@ export class SwitchChange {
6153
template: `
6254
<input
6355
class="bx--toggle"
56+
[ngClass]="{
57+
'bx--toggle--small': size === 'sm'
58+
}"
6459
[id]="id"
6560
type="checkbox"
6661
(click)="onClick($event)"
6762
[disabled]="disabled"
6863
[attr.aria-checked]="checked">
69-
<label class="bx--toggle__label" [for]="id">
64+
<label *ngIf="size === 'md'" class="bx--toggle__label" [for]="id">
7065
<span class="bx--toggle__text--left">Off</span>
7166
<span class="bx--toggle__appearance"></span>
7267
<span class="bx--toggle__text--right">On</span>
7368
</label>
69+
<label *ngIf="size === 'sm'" class="bx--toggle__label" [for]="id">
70+
<span class="bx--toggle__appearance">
71+
<svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5">
72+
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z"/>
73+
</svg>
74+
</span>
75+
</label>
7476
`,
7577
providers: [
7678
{
@@ -80,7 +82,7 @@ export class SwitchChange {
8082
}
8183
]
8284
})
83-
export class SwitchComponent extends CheckboxComponent implements OnInit {
85+
export class SwitchComponent extends CheckboxComponent {
8486
/**
8587
* Variable used for creating unique ids for switch components.
8688
* @type {number}
@@ -107,32 +109,10 @@ export class SwitchComponent extends CheckboxComponent implements OnInit {
107109
/**
108110
* Creates an instance of SwitchComponent.
109111
* @param {ChangeDetectorRef} changeDetectorRef
110-
* @param {ElementRef} elementRef
111-
* @param {Renderer2} renderer
112112
* @memberof SwitchComponent
113113
*/
114-
constructor(protected changeDetectorRef: ChangeDetectorRef, private elementRef: ElementRef, private renderer: Renderer2) {
114+
constructor(protected changeDetectorRef: ChangeDetectorRef) {
115115
super(changeDetectorRef);
116116
SwitchComponent.switchCount++;
117117
}
118-
119-
/**
120-
* Builds variant classes and appends them to the switch and label elements.
121-
* @memberof SwitchComponent
122-
*/
123-
ngOnInit() {
124-
/* TODO: remove and extend in neutrino
125-
// Build variant classes
126-
const labelClass = `toggle-label${this.size !== "md" ? `--${this.size}` : ""}`;
127-
const buttonClass = `toggle${this.size !== "md" ? `--${this.size}` : ""}`;
128-
129-
// Get elements
130-
const labelEl = this.elementRef.nativeElement.querySelector("label");
131-
const buttonEl = this.elementRef.nativeElement.querySelector("button");
132-
133-
// Add classes to elements
134-
this.renderer.addClass(labelEl, labelClass);
135-
this.renderer.addClass(buttonEl, buttonClass);
136-
*/
137-
}
138118
}

src/switch/switch.stories.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ storiesOf("Switch", module).addDecorator(
1010
)
1111
.addDecorator(withKnobs)
1212
.add("Basic", () => ({
13-
template: `<ibm-switch [disabled]="disabled"></ibm-switch>`,
13+
template: `
14+
<ibm-switch [disabled]="disabled"></ibm-switch>
15+
<ibm-switch [disabled]="disabled" size="sm"></ibm-switch>
16+
`,
1417
props: {
1518
disabled: boolean("disabled", false)
1619
}

0 commit comments

Comments
 (0)