Skip to content

Commit

Permalink
feat(annotations): Add tests, SUIT style, and typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingze Xiao committed Mar 25, 2020
1 parent 6c2e116 commit 1b095b2
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 46 deletions.
22 changes: 22 additions & 0 deletions src/lib/AnnotationControls.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.bp-AnnotationControls-group {
padding: 0 4px 0 8px;
border-left: 1px solid $twos;

& .bp-AnnotationControls-regionBtn {
width: 32px;
height: 32px;
border-radius: 4px;

svg {
fill: $white;
}

&.is-active {
background-color: $white;

svg {
fill: $black;
}
}
}
}
37 changes: 24 additions & 13 deletions src/lib/AnnotationControls.js → src/lib/AnnotationControls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,46 @@ import noop from 'lodash/noop';
import { ICON_REGION_COMMENT } from './icons/icons';
import Controls, { CLASS_BOX_CONTROLS_GROUP_BUTTON } from './Controls';

const CLASS_ANNOTATIONS_GROUP = 'bp-annotations-group';
const CLASS_REGION_BUTTON = 'bp-region-btn';
const CLASS_BUTTON_ACTIVE = 'active';
export const CLASS_ANNOTATIONS_GROUP = 'bp-AnnotationControls-group';
export const CLASS_REGION_BUTTON = 'bp-AnnotationControls-regionBtn';
export const CLASS_BUTTON_ACTIVE = 'is-active';

class AnnotationControls {
export type Options = {
onRegionClick?: Function;
};

export default class AnnotationControls {
/** @property {Controls} - Controls object */
controls;
private controls: Controls;

/** @property {Boolean} - Region comment mode active state */
isRegionActive = false;
/** @property {bool} - Region comment mode active state */
private isRegionActive = false;

/** @property {HTMLElement} - Region comment button element */
regionButtonElement;
private regionButtonElement: HTMLElement = new HTMLButtonElement();

/**
* [constructor]
*
* @param {Controls} controls - Viewer controls
* @return {AnnotationControls} Instance of AnnotationControls
*/
constructor(controls) {
constructor(controls: Controls) {
if (!controls || !(controls instanceof Controls)) {
throw Error('controls must be an instance of Controls');
}

this.controls = controls;
}

handleRegionClick = onRegionClick => event => {
/**
* Region comment button click handler
*
* @param {Function} onRegionClick - region click handler in options
* @param {MouseEvent} event - mouse event
* @return {void}
*/
private handleRegionClick = (onRegionClick: Function) => (event: MouseEvent): void => {
this.isRegionActive = !this.isRegionActive;
if (this.isRegionActive) {
this.regionButtonElement.classList.add(CLASS_BUTTON_ACTIVE);
Expand All @@ -47,9 +58,11 @@ class AnnotationControls {
* @param {Function} [options.onRegionClick] - Callback when region comment button is clicked
* @return {void}
*/
init({ onRegionClick = noop } = {}) {
public init({ onRegionClick = noop }: Options = {}): void {
const groupElement = this.controls.addGroup(CLASS_ANNOTATIONS_GROUP);
this.regionButtonElement = this.controls.add(
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
__('region_comment'),
this.handleRegionClick(onRegionClick),
`${CLASS_BOX_CONTROLS_GROUP_BUTTON} ${CLASS_REGION_BUTTON}`,
Expand All @@ -59,5 +72,3 @@ class AnnotationControls {
);
}
}

export default AnnotationControls;
30 changes: 0 additions & 30 deletions src/lib/Controls.scss
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,6 @@
}
}

.bp-zoom-current-scale {
min-width: 48px;
color: $white;
font-size: 14px;
text-align: center;
}

.bp-controls-group {
display: flex;
align-items: center;
Expand All @@ -180,26 +173,3 @@
margin-left: 4px;
}
}

.bp-annotations-group {
padding: 0 4px 0 8px;
border-left: 1px solid $twos;
}

.bp-region-btn {
width: 32px;
height: 32px;
border-radius: 4px;

svg {
fill: $white;
}

&.active {
background-color: $white;

svg {
fill: $black;
}
}
}
2 changes: 2 additions & 0 deletions src/lib/Preview.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@import 'common';
@import 'loading';
@import 'navigation';
@import './AnnotationControls';
@import './Controls';
@import './ProgressBar';
@import './VirtualScroller';
@import './ZoomControls';
2 changes: 1 addition & 1 deletion src/lib/ZoomControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import noop from 'lodash/noop';
import { ICON_ZOOM_IN, ICON_ZOOM_OUT } from './icons/icons';
import Controls, { CLASS_BOX_CONTROLS_GROUP_BUTTON } from './Controls';

const CLASS_ZOOM_CURRENT_SCALE = 'bp-zoom-current-scale';
const CLASS_ZOOM_CURRENT_SCALE = 'bp-ZoomControls-currentScale';
const CLASS_ZOOM_CURRENT_SCALE_VALUE = 'bp-zoom-current-scale-value';
const CLASS_ZOOM_IN_BUTTON = 'bp-zoom-in-btn';
const CLASS_ZOOM_OUT_BUTTON = 'bp-zoom-out-btn';
Expand Down
6 changes: 6 additions & 0 deletions src/lib/ZoomControls.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.bp-ZoomControls-currentScale {
min-width: 48px;
color: $white;
font-size: 14px;
text-align: center;
}
1 change: 1 addition & 0 deletions src/lib/__tests__/AnnotationControls-test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div id="test-annotation-controls-container"></div>
99 changes: 99 additions & 0 deletions src/lib/__tests__/AnnotationControls-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/* eslint-disable no-unused-expressions */
import AnnotationControls, { CLASS_REGION_BUTTON, CLASS_BUTTON_ACTIVE } from '../AnnotationControls';
import Controls, { CLASS_BOX_CONTROLS_GROUP_BUTTON } from '../Controls';
import { ICON_REGION_COMMENT } from '../icons/icons';

let annotationControls;
let stubs = {};

const sandbox = sinon.sandbox.create();

describe('lib/AnnotationControls', () => {
before(() => {
fixture.setBase('src/lib');
});

beforeEach(() => {
fixture.load('__tests__/AnnotationControls-test.html');
const controls = new Controls(document.getElementById('test-annotation-controls-container'));
annotationControls = new AnnotationControls(controls);
stubs.onRegionClick = sandbox.stub();
});

afterEach(() => {
fixture.cleanup();
sandbox.verifyAndRestore();

annotationControls = null;
stubs = {};
});

describe('constructor()', () => {
it('should create the correct DOM structure', () => {
expect(annotationControls.controls).not.to.be.undefined;
});

it('should throw an exception if controls is not provided', () => {
expect(() => new AnnotationControls()).to.throw(Error, 'controls must be an instance of Controls');
});
});

describe('init()', () => {
beforeEach(() => {
stubs.add = sandbox.stub(annotationControls.controls, 'add');
stubs.regionHandler = sandbox.stub();
sandbox.stub(annotationControls, 'handleRegionClick').returns(stubs.regionHandler);
});

it('should add the controls', () => {
annotationControls.init({ onRegionClick: stubs.onRegionClick });

expect(stubs.add).to.be.calledWith(
__('region_comment'),
stubs.regionHandler,
`${CLASS_BOX_CONTROLS_GROUP_BUTTON} ${CLASS_REGION_BUTTON}`,
ICON_REGION_COMMENT,
'button',
sinon.match.any,
);
});
});

describe('handleRegionClick()', () => {
beforeEach(() => {
stubs.event = sandbox.stub({});
stubs.classListAdd = sandbox.stub();
stubs.classListRemove = sandbox.stub();
stubs.add = sandbox.stub(annotationControls.controls, 'add').returns({
classList: {
add: stubs.classListAdd,
remove: stubs.classListRemove,
},
});
});

it('should activate region button then deactivate', () => {
annotationControls.init({ onRegionClick: stubs.onRegionClick });

expect(annotationControls.isRegionActive).to.be.false;

annotationControls.handleRegionClick(stubs.onRegionClick)(stubs.event);
expect(annotationControls.isRegionActive).to.be.true;
expect(stubs.classListAdd).to.be.calledWith(CLASS_BUTTON_ACTIVE);

annotationControls.handleRegionClick(stubs.onRegionClick)(stubs.event);
expect(annotationControls.isRegionActive).to.be.false;
expect(stubs.classListRemove).to.be.calledWith(CLASS_BUTTON_ACTIVE);
});

it('should call onRegionClick', () => {
annotationControls.init({ onRegionClick: stubs.onRegionClick });
annotationControls.handleRegionClick(stubs.onRegionClick)(stubs.event);

expect(stubs.onRegionClick).to.be.calledWith({
isRegionActive: true,
event: stubs.event,
});
});
});
});
4 changes: 2 additions & 2 deletions src/lib/__tests__/ZoomControls-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe('lib/ZoomControls', () => {
expect(stubs.add).to.be.calledWith(
__('zoom_current_scale'),
undefined,
'bp-zoom-current-scale',
'bp-ZoomControls-currentScale',
sinon.match.string,
'div',
sinon.match.any,
Expand Down Expand Up @@ -125,7 +125,7 @@ describe('lib/ZoomControls', () => {
expect(stubs.add).to.be.calledWith(
__('zoom_current_scale'),
undefined,
'bp-zoom-current-scale',
'bp-ZoomControls-currentScale',
sinon.match.string,
'div',
sinon.match.any,
Expand Down

0 comments on commit 1b095b2

Please sign in to comment.