Skip to content

Commit

Permalink
feat(checkbox): add outline on focus (#731)
Browse files Browse the repository at this point in the history
Adds visual representation of focus.
  • Loading branch information
yggg authored and nnixaa committed Sep 20, 2018
1 parent 64b7ff6 commit cc892d5
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 51 deletions.
84 changes: 41 additions & 43 deletions e2e/checkbox.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,23 @@

import { browser, by, element } from 'protractor';

describe('nb-search', () => {
function getComputedProperty(property: string, selector: string) {
const script = `
return window.getComputedStyle(
document.querySelector('${selector}'),
':before'
).${property};
`;

return browser.executeScript(script);
}

describe('nb-checkbox', () => {
const transparent = 'rgba(0, 0, 0, 0)';

const border_color = 'rgb(218, 223, 230)';
const checked_color = 'rgb(64, 220, 126)';
const hover_color = 'rgb(107, 228, 155)';
const outline_color = 'rgb(107, 228, 155)';

const warning_color = 'rgb(255, 161, 0)';
const warning_hover = 'rgb(255, 180, 51)';
Expand Down Expand Up @@ -49,52 +60,35 @@ describe('nb-search', () => {
it('should apply style if checked/unchecked', () => {
const input = element(by.css('#first input'));
const indicator = element(by.css('#first .customised-control-indicator'));
const otherElement = element(by.css('#danger'));
const otherElement = element(by.css('#danger .customised-control-indicator'));

// unchecked
expect(input.getAttribute('checked')).toBeFalsy();
expect(indicator.getCssValue('background-color')).toEqual(transparent);
expect(indicator.getCssValue('border')).toEqual('2px solid ' + border_color);

// check ::before styles
browser.executeScript(
'return ' +
'window.getComputedStyle(document.querySelector(' +
'"#first .customised-control-indicator"' +
'), ":before").content')
getComputedProperty('content', '#first .customised-control-indicator')
.then(data => expect(data).toBe('""'));

browser.executeScript(
'return ' +
'window.getComputedStyle(document.querySelector(' +
'"#first .customised-control-indicator"' +
'), ":before").borderTopColor')
getComputedProperty('borderTopColor', '#first .customised-control-indicator')
.then(data => expect(data).toBe(transparent));

indicator.click();
browser.actions().mouseMove(otherElement).perform();
// change focus to another input, so .focus styles removed.
otherElement.click();

// checked
expect(input.getAttribute('checked')).toBeTruthy();
expect(indicator.getCssValue('background-color')).toEqual(transparent);
expect(indicator.getCssValue('border')).toEqual('2px solid ' + checked_color);

// check ::before styles
browser.executeScript(
'return ' +
'window.getComputedStyle(document.querySelector(' +
'"#first .customised-control-indicator"' +
'), ":before").content')
getComputedProperty('content', '#first .customised-control-indicator')
.then(data => expect(data).toBe('""'));

browser.executeScript(
'return ' +
'window.getComputedStyle(document.querySelector(' +
'"#first .customised-control-indicator"' +
'), ":before").borderTopColor')
.then(data => {
expect(data).toBe('rgb(42, 42, 42)');
});
getComputedProperty('borderTopColor', '#first .customised-control-indicator')
.then(data => expect(data).toBe('rgb(42, 42, 42)'));
});

it('should apply style if hover', () => {
Expand All @@ -106,23 +100,22 @@ describe('nb-search', () => {
browser.actions().mouseMove(indicator).perform();

// hover
expect(indicator.getCssValue('border')).toEqual('2px solid ' + hover_color);
expect(indicator.getCssValue('border')).toEqual('2px solid ' + outline_color);
});

it('should apply style if status success', () => {
it('should apply status style', () => {
const success = element(by.css('#success .customised-control-indicator'));
const other = element(by.css('#first .customised-control-indicator'));

// without hover
expect(success.getCssValue('border-color')).toEqual(border_color);

// checked & focus
success.click();
expect(success.getCssValue('border-color')).toEqual(outline_color);

// hover
expect(success.getCssValue('border-color')).toEqual(hover_color);

// checked
browser.actions().mouseMove(other).perform();
// checked w/o focus
other.click();
expect(success.getCssValue('border-color')).toEqual(checked_color);

});
Expand All @@ -134,13 +127,12 @@ describe('nb-search', () => {
// without hover
expect(warning.getCssValue('border-color')).toEqual(border_color);

// checked & focus
warning.click();

// hover
expect(warning.getCssValue('border-color')).toEqual(warning_hover);

// checked
browser.actions().mouseMove(other).perform();
// checked w/o focus
other.click();
expect(warning.getCssValue('border-color')).toEqual(warning_color);
});

Expand All @@ -151,15 +143,21 @@ describe('nb-search', () => {
// without hover
expect(danger.getCssValue('border-color')).toEqual(border_color);

// checked & focus
danger.click();

// hover
expect(danger.getCssValue('border-color')).toEqual(danger_hover);

// checked
browser.actions().mouseMove(other).perform();

// checked w/o focus
other.click();
expect(danger.getCssValue('border-color')).toEqual(danger_color);

});

it('should apply focus class when receive focus', () => {
const firstCheckbox = element(by.css('nb-checkbox#first'));
const firstCheckboxInput = element(by.css('#first .customised-control-indicator'));

firstCheckboxInput.click();
expect(firstCheckbox.getAttribute('class')).toContain('focus');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
*/

// locally used mixin
@mixin hover-border($color) {
@mixin outline-border($color) {
.customised-control-input:checked ~ .customised-control-indicator {
border-color: $color;
}
.customised-control-input:hover:enabled ~ .customised-control-indicator {
border-color: lighten($color, 10%);

&.focus .customised-control-input:enabled,
.customised-control-input:hover:enabled {
& ~ .customised-control-indicator {
border-color: lighten($color, 10%);
}
}
}
// locally used mixin
Expand Down Expand Up @@ -150,15 +154,15 @@
}
}

@include hover-border(nb-theme(checkbox-checked-border-color));
@include outline-border(nb-theme(checkbox-checked-border-color));
&.success {
@include hover-border(nb-theme(color-success));
@include outline-border(nb-theme(color-success));
}
&.warning {
@include hover-border(nb-theme(color-warning));
@include outline-border(nb-theme(color-warning));
}
&.danger {
@include hover-border(nb-theme(color-danger));
@include outline-border(nb-theme(color-danger));
}

.customised-control-description {
Expand Down
15 changes: 14 additions & 1 deletion src/framework/theme/components/checkbox/checkbox.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ import { convertToBoolProperty } from '../helpers';
<input type="checkbox" class="customised-control-input"
[disabled]="disabled"
[checked]="value"
(change)="value = !value">
(change)="value = !value"
(focus)="setFocus()"
(blur)="removeFocus()">
<span class="customised-control-indicator"></span>
<span class="customised-control-description">
<ng-content></ng-content>
Expand Down Expand Up @@ -98,6 +100,9 @@ export class NbCheckboxComponent implements ControlValueAccessor {
return this.status === 'danger';
}

@HostBinding('class.focus')
focus: boolean = false;

onChange: any = () => { };
onTouched: any = () => { };

Expand Down Expand Up @@ -126,4 +131,12 @@ export class NbCheckboxComponent implements ControlValueAccessor {
setDisabledState(val: boolean) {
this.disabled = convertToBoolProperty(val);
}

setFocus() {
this.focus = true;
}

removeFocus() {
this.focus = false;
}
}

0 comments on commit cc892d5

Please sign in to comment.