diff --git a/package.json b/package.json
index f24936638..f1dd670bf 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"@popperjs/core": "^2.4.0",
"@reduxjs/toolkit": "^1.3.5",
"@types/react-redux": "^7.1.7",
+ "@types/uuid": "^8.3.0",
"axios": "^0.19.2",
"box-ui-elements": "^12.0.0-beta.146",
"classnames": "^2.2.5",
@@ -34,7 +35,8 @@
"react-tether": "1.0.5",
"react-textarea-autosize": "^7.1.2",
"redux": "^4.0.5",
- "scroll-into-view-if-needed": "^2.2.24"
+ "scroll-into-view-if-needed": "^2.2.24",
+ "uuid": "^8.3.1"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
diff --git a/src/common/__tests__/useWindowSize-test.tsx b/src/common/__tests__/useWindowSize-test.tsx
deleted file mode 100644
index e5e60e40a..000000000
--- a/src/common/__tests__/useWindowSize-test.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import * as React from 'react';
-import { act } from 'react-dom/test-utils';
-import { mount, ReactWrapper } from 'enzyme';
-import useWindowSize from '../useWindowSize';
-
-describe('useWindowSize', () => {
- function TestComponent(): JSX.Element {
- const windowSize = useWindowSize();
-
- return (
-
- {windowSize?.height}
- {windowSize?.width}
-
- );
- }
-
- const getWrapper = (): ReactWrapper =>
- mount(
-
-
-
,
- { attachTo: document.getElementById('test') },
- );
-
- beforeEach(() => {
- document.body.innerHTML = '';
- global.window.innerHeight = 100;
- global.window.innerWidth = 100;
- });
-
- test('should return the window size', () => {
- const wrapper = getWrapper();
-
- expect(wrapper.find('#height').text()).toBe('100');
- expect(wrapper.find('#width').text()).toBe('100');
-
- global.window.innerHeight = 200;
- global.window.innerWidth = 200;
-
- act(() => {
- global.window.dispatchEvent(new Event('resize'));
- });
-
- expect(wrapper.find('#height').text()).toBe('200');
- expect(wrapper.find('#width').text()).toBe('200');
- });
-});
diff --git a/src/common/useWindowSize.ts b/src/common/useWindowSize.ts
deleted file mode 100644
index 80ff29384..000000000
--- a/src/common/useWindowSize.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import * as React from 'react';
-
-type WindowSize = {
- height: number;
- width: number;
-};
-
-export default function useWindowSize(): WindowSize | null {
- const [windowSize, setWindowSize] = React.useState(null);
-
- const handleResize = (): void => {
- // Set window width/height to state
- setWindowSize({
- width: window.innerWidth,
- height: window.innerHeight,
- });
- };
-
- React.useEffect(() => {
- // Add event listener
- window.addEventListener('resize', handleResize);
-
- // Call handler right away so state gets updated with initial window size
- handleResize();
-
- // Remove event listener on cleanup
- return () => window.removeEventListener('resize', handleResize);
- }, []); // Empty array ensures that effect is only run on mount
-
- return windowSize;
-}
diff --git a/src/highlight/HighlightAnnotations.tsx b/src/highlight/HighlightAnnotations.tsx
index 8923ee104..ba72fdd5b 100644
--- a/src/highlight/HighlightAnnotations.tsx
+++ b/src/highlight/HighlightAnnotations.tsx
@@ -5,7 +5,6 @@ import HighlightSvg from './HighlightSvg';
import HighlightTarget from './HighlightTarget';
import PopupHighlight from '../components/Popups/PopupHighlight';
import PopupHighlightError from '../components/Popups/PopupHighlightError';
-import useWindowSize from '../common/useWindowSize';
import { AnnotationHighlight } from '../@types';
import { CreateArg } from './actions';
import { CreatorItemHighlight, CreatorStatus, SelectionArg, SelectionItem } from '../store';
@@ -23,7 +22,7 @@ type Props = {
selection: SelectionItem | null;
setActiveAnnotationId: (annotationId: string | null) => void;
setIsPromoting: (isPromoting: boolean) => void;
- setReferenceShape: (rect: DOMRect) => void;
+ setReferenceId: (uuid: string) => void;
setSelection: (selection: SelectionArg | null) => void;
setStaged: (staged: CreatorItemHighlight | null) => void;
setStatus: (status: CreatorStatus) => void;
@@ -40,15 +39,12 @@ const HighlightAnnotations = (props: Props): JSX.Element => {
selection,
setActiveAnnotationId,
setIsPromoting,
- setReferenceShape,
+ setReferenceId,
setSelection,
setStaged,
setStatus,
staged,
} = props;
- const [highlightRef, setHighlightRef] = React.useState(null);
- const windowSize = useWindowSize();
-
const canCreate = isCreating || isPromoting;
const handleAnnotationActive = (annotationId: string | null): void => {
@@ -82,6 +78,10 @@ const HighlightAnnotations = (props: Props): JSX.Element => {
setSelection(null);
};
+ const handleStagedMount = (uuid: string): void => {
+ setReferenceId(uuid);
+ };
+
React.useEffect(() => {
if (!isSelecting) {
return;
@@ -99,14 +99,6 @@ const HighlightAnnotations = (props: Props): JSX.Element => {
stageSelection();
}, [isCreating, selection]); // eslint-disable-line react-hooks/exhaustive-deps
- React.useEffect(() => {
- if (highlightRef === null) {
- return;
- }
-
- setReferenceShape(highlightRef.getBoundingClientRect());
- }, [highlightRef, windowSize]); // eslint-disable-line react-hooks/exhaustive-deps
-
return (
<>
{/* Layer 1: Saved annotations */}
@@ -117,7 +109,12 @@ const HighlightAnnotations = (props: Props): JSX.Element => {
-
+
)}
diff --git a/src/highlight/HighlightContainer.tsx b/src/highlight/HighlightContainer.tsx
index 95d50520b..8d0f4146e 100644
--- a/src/highlight/HighlightContainer.tsx
+++ b/src/highlight/HighlightContainer.tsx
@@ -17,7 +17,7 @@ import {
SelectionItem,
setActiveAnnotationIdAction,
setIsPromotingAction,
- setReferenceShapeAction,
+ setReferenceIdAction,
setSelectionAction,
setStagedAction,
setStatusAction,
@@ -51,7 +51,7 @@ export const mapStateToProps = (state: AppState, { location }: { location: numbe
export const mapDispatchToProps = {
setActiveAnnotationId: setActiveAnnotationIdAction,
setIsPromoting: setIsPromotingAction,
- setReferenceShape: setReferenceShapeAction,
+ setReferenceId: setReferenceIdAction,
setSelection: setSelectionAction,
setStaged: setStagedAction,
setStatus: setStatusAction,
diff --git a/src/highlight/HighlightTarget.tsx b/src/highlight/HighlightTarget.tsx
index 61502b577..77a3ca77c 100644
--- a/src/highlight/HighlightTarget.tsx
+++ b/src/highlight/HighlightTarget.tsx
@@ -1,5 +1,6 @@
-import * as React from 'react';
+import React from 'react';
import * as ReactRedux from 'react-redux';
+import * as uuid from 'uuid';
import classNames from 'classnames';
import noop from 'lodash/noop';
import { getIsCurrentFileVersion } from '../store';
@@ -12,6 +13,7 @@ type Props = {
className?: string;
isActive?: boolean;
onHover?: (annotationId: string | null) => void;
+ onMount?: (uuid: string) => void;
onSelect?: (annotationId: string) => void;
shapes: Array;
};
@@ -19,7 +21,8 @@ type Props = {
export type HighlightTargetRef = HTMLAnchorElement;
const HighlightTarget = (props: Props, ref: React.Ref): JSX.Element => {
- const { annotationId, className, isActive, onHover = noop, onSelect = noop, shapes } = props;
+ const { annotationId, className, isActive, onHover = noop, onMount = noop, onSelect = noop, shapes } = props;
+ const uuidRef = React.useRef(uuid.v4());
const isCurrentFileVersion = ReactRedux.useSelector(getIsCurrentFileVersion);
const handleClick = (event: React.MouseEvent): void => {
@@ -61,11 +64,16 @@ const HighlightTarget = (props: Props, ref: React.Ref): JSX.
event.currentTarget.focus();
};
+ React.useEffect(() => {
+ onMount(uuidRef.current);
+ }, [onMount]);
+
return (
// eslint-disable-next-line jsx-a11y/anchor-is-valid
{
selection: null,
setActiveAnnotationId: jest.fn(),
setIsPromoting: jest.fn(),
- setReferenceShape: jest.fn(),
+ setReferenceId: jest.fn(),
setSelection: jest.fn(),
setStaged: jest.fn(),
setStatus: jest.fn(),
diff --git a/src/highlight/__tests__/HighlightContainer-test.tsx b/src/highlight/__tests__/HighlightContainer-test.tsx
index 1af57996b..8dc96cbe3 100644
--- a/src/highlight/__tests__/HighlightContainer-test.tsx
+++ b/src/highlight/__tests__/HighlightContainer-test.tsx
@@ -42,7 +42,7 @@ describe('HighlightContainer', () => {
selection: null,
setActiveAnnotationId: expect.any(Function),
setIsPromoting: expect.any(Function),
- setReferenceShape: expect.any(Function),
+ setReferenceId: expect.any(Function),
setStaged: expect.any(Function),
setStatus: expect.any(Function),
staged: null,
diff --git a/src/highlight/__tests__/HighlightTarget-test.tsx b/src/highlight/__tests__/HighlightTarget-test.tsx
index 604890792..847ab252e 100644
--- a/src/highlight/__tests__/HighlightTarget-test.tsx
+++ b/src/highlight/__tests__/HighlightTarget-test.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { MutableRefObject } from 'react';
import * as ReactRedux from 'react-redux';
import { shallow, ShallowWrapper } from 'enzyme';
import HighlightTarget from '../HighlightTarget';
@@ -23,12 +23,14 @@ describe('HighlightTarget', () => {
},
],
};
- const mockSetIsHover = jest.fn();
+
const getWrapper = (props = {}): ShallowWrapper => shallow();
+ const mockInitalRef = { current: '123' } as MutableRefObject;
beforeEach(() => {
+ jest.spyOn(React, 'useEffect').mockImplementation(f => f());
+ jest.spyOn(React, 'useRef').mockImplementation(() => mockInitalRef);
jest.spyOn(ReactRedux, 'useSelector').mockImplementation(() => true);
- jest.spyOn(React, 'useState').mockImplementation(() => [false, mockSetIsHover]);
});
describe('render()', () => {
@@ -43,9 +45,10 @@ describe('HighlightTarget', () => {
test.each([true, false])('should render classNames correctly when isActive is %s', isActive => {
const wrapper = getWrapper({ isActive });
+ const anchor = wrapper.find('a');
- expect(wrapper.hasClass('ba-HighlightTarget')).toBe(true);
- expect(wrapper.hasClass('is-active')).toBe(isActive);
+ expect(anchor.hasClass('ba-HighlightTarget')).toBe(true);
+ expect(anchor.hasClass('is-active')).toBe(isActive);
});
});
@@ -88,12 +91,8 @@ describe('HighlightTarget', () => {
test('should call onSelect', () => {
const wrapper = getWrapper();
const anchor = wrapper.find('a');
- const event = {
- ...mockEvent,
- buttons: 1,
- };
- anchor.simulate('mousedown', event);
+ anchor.prop('onMouseDown')!((mockEvent as unknown) as React.MouseEvent);
expect(defaults.onSelect).toHaveBeenCalledWith('123');
expect(mockEvent.preventDefault).toHaveBeenCalled();
@@ -140,4 +139,13 @@ describe('HighlightTarget', () => {
});
});
});
+
+ describe('onMount()', () => {
+ test('should call onMount with a generated uuid', () => {
+ const handleMount = jest.fn();
+ getWrapper({ onMount: handleMount });
+
+ expect(handleMount).toHaveBeenCalledWith(expect.any(String));
+ });
+ });
});
diff --git a/src/popup/PopupContainer.tsx b/src/popup/PopupContainer.tsx
index 2b34e2ef0..559f168b4 100644
--- a/src/popup/PopupContainer.tsx
+++ b/src/popup/PopupContainer.tsx
@@ -13,17 +13,16 @@ import {
Mode,
resetCreatorAction,
setMessageAction,
- getCreatorReferenceShape,
+ getCreatorReferenceId,
} from '../store';
import { createHighlightAction } from '../highlight/actions';
-import { Shape } from '../@types';
import { createRegionAction } from '../region';
export type Props = {
isPromoting: boolean;
message: string;
mode: Mode;
- popupReference?: Shape;
+ referenceId: string | null;
staged: CreatorItem | null;
status: CreatorStatus;
};
@@ -33,7 +32,7 @@ export const mapStateToProps = (state: AppState, { location }: { location: numbe
isPromoting: getIsPromoting(state),
message: getCreatorMessage(state),
mode: getAnnotationMode(state),
- popupReference: getCreatorReferenceShape(state),
+ referenceId: getCreatorReferenceId(state),
staged: getCreatorStagedForLocation(state, location),
status: getCreatorStatus(state),
};
diff --git a/src/popup/PopupLayer.tsx b/src/popup/PopupLayer.tsx
index 92bb0b98e..28a31adbb 100644
--- a/src/popup/PopupLayer.tsx
+++ b/src/popup/PopupLayer.tsx
@@ -5,7 +5,6 @@ import { CreateArg as HighlightCreateArg } from '../highlight/actions';
import { CreateArg as RegionCreateArg } from '../region/actions';
import { CreatorItem, CreatorStatus, isCreatorStagedHighlight, isCreatorStagedRegion, Mode } from '../store';
import { PopupReference } from '../components/Popups/Popper';
-import { Shape } from '../@types';
import './PopupLayer.scss';
type Props = {
@@ -15,7 +14,7 @@ type Props = {
location: number;
message: string;
mode: Mode;
- popupReference?: Shape;
+ referenceId: string | null;
resetCreator: () => void;
setMessage: (message: string) => void;
staged?: CreatorItem | null;
@@ -34,7 +33,7 @@ const PopupLayer = (props: Props): JSX.Element | null => {
isPromoting = false,
message,
mode,
- popupReference,
+ referenceId,
resetCreator,
setMessage,
staged,
@@ -67,25 +66,8 @@ const PopupLayer = (props: Props): JSX.Element | null => {
};
React.useEffect(() => {
- if (!popupReference) {
- return;
- }
-
- const { height, width, x, y } = popupReference;
-
- const virtualElement = {
- getBoundingClientRect: () => ({
- bottom: y + height,
- height,
- left: x,
- right: x + width,
- top: y,
- width,
- }),
- };
-
- setReference(virtualElement);
- }, [popupReference]);
+ setReference(referenceId ? document.querySelector(`[data-ba-reference-id="${referenceId}"]`) : null);
+ }, [referenceId]);
return (
<>
diff --git a/src/popup/__tests__/PopupContainer-test.tsx b/src/popup/__tests__/PopupContainer-test.tsx
index 70d6aba0f..7b53f2c5e 100644
--- a/src/popup/__tests__/PopupContainer-test.tsx
+++ b/src/popup/__tests__/PopupContainer-test.tsx
@@ -24,6 +24,7 @@ describe('PopupContainer', () => {
expect(wrapper.find(PopupLayer).props()).toMatchObject({
isPromoting: false,
mode: Mode.NONE,
+ referenceId: null,
staged: null,
status: CreatorStatus.init,
store: defaults.store,
diff --git a/src/popup/__tests__/PopupLayer-test.tsx b/src/popup/__tests__/PopupLayer-test.tsx
index 105bf210a..7effa1964 100644
--- a/src/popup/__tests__/PopupLayer-test.tsx
+++ b/src/popup/__tests__/PopupLayer-test.tsx
@@ -8,7 +8,6 @@ import { Rect } from '../../@types';
jest.mock('../../components/Popups/PopupReply');
describe('PopupLayer', () => {
- const popupReference = { height: 10, width: 10, x: 10, y: 10 };
const getRect = (): Rect => ({
type: 'rect',
height: 50,
@@ -31,7 +30,7 @@ describe('PopupLayer', () => {
location: 1,
message: '',
mode: Mode.HIGHLIGHT,
- popupReference,
+ referenceId: '123',
resetCreator: jest.fn(),
setMessage: jest.fn(),
staged: getStagedHighlight(),
@@ -39,18 +38,8 @@ describe('PopupLayer', () => {
};
const getWrapper = (props = {}): ReactWrapper => mount();
- const mockSetReference = jest.fn();
- const mockReference = {
- getBoundingClientRect: () => ({
- height: 10,
- width: 10,
- top: 10,
- left: 10,
- }),
- };
-
beforeEach(() => {
- jest.spyOn(React, 'useState').mockImplementation(() => [mockReference, mockSetReference]);
+ document.body.innerHTML = ``;
});
describe('render()', () => {
diff --git a/src/region/RegionCreation.tsx b/src/region/RegionCreation.tsx
index 528d5a99a..82b6a10ca 100644
--- a/src/region/RegionCreation.tsx
+++ b/src/region/RegionCreation.tsx
@@ -12,7 +12,7 @@ type Props = {
isRotated: boolean;
location: number;
resetCreator: () => void;
- setReferenceShape: (rect: DOMRect) => void;
+ setReferenceId: (uuid: string) => void;
setStaged: (staged: CreatorItemRegion | null) => void;
setStatus: (status: CreatorStatus) => void;
staged?: CreatorItemRegion | null;
@@ -31,16 +31,6 @@ export default class RegionCreation extends React.PureComponent {
state: State = {};
- componentDidUpdate(_prevProps: Props, prevState: State): void {
- const { setReferenceShape } = this.props;
- const { rectRef } = this.state;
- const { rectRef: prevRectRef } = prevState;
-
- if (prevRectRef !== rectRef && rectRef) {
- setReferenceShape(rectRef.getBoundingClientRect());
- }
- }
-
handleAbort = (): void => {
const { resetCreator } = this.props;
resetCreator();
@@ -52,16 +42,17 @@ export default class RegionCreation extends React.PureComponent {
setStatus(CreatorStatus.started);
};
+ handleStagedMount = (uuid: string): void => {
+ const { setReferenceId } = this.props;
+ setReferenceId(uuid);
+ };
+
handleStop = (shape: Rect): void => {
const { location, setStaged, setStatus } = this.props;
setStaged({ location, shape });
setStatus(CreatorStatus.staged);
};
- setRectRef = (rectRef: RegionRectRef): void => {
- this.setState({ rectRef });
- };
-
render(): JSX.Element | null {
const { isCreating, isDiscoverabilityEnabled, isRotated, staged } = this.props;
const canCreate = isCreating && !isRotated;
@@ -83,7 +74,7 @@ export default class RegionCreation extends React.PureComponent {
{staged && (
-
+
)}
>
diff --git a/src/region/RegionCreationContainer.tsx b/src/region/RegionCreationContainer.tsx
index 58b8530f4..d89be0c9c 100644
--- a/src/region/RegionCreationContainer.tsx
+++ b/src/region/RegionCreationContainer.tsx
@@ -9,7 +9,7 @@ import {
isFeatureEnabled,
Mode,
resetCreatorAction,
- setReferenceShapeAction,
+ setReferenceIdAction,
setStagedAction,
setStatusAction,
} from '../store';
@@ -36,7 +36,7 @@ export const mapStateToProps = (state: AppState, { location }: { location: numbe
export const mapDispatchToProps = {
resetCreator: resetCreatorAction,
- setReferenceShape: setReferenceShapeAction,
+ setReferenceId: setReferenceIdAction,
setStaged: setStagedAction,
setStatus: setStatusAction,
};
diff --git a/src/region/RegionRect.tsx b/src/region/RegionRect.tsx
index 1c1d2dde2..9ff64214c 100644
--- a/src/region/RegionRect.tsx
+++ b/src/region/RegionRect.tsx
@@ -1,4 +1,6 @@
-import * as React from 'react';
+import React from 'react';
+import * as uuid from 'uuid';
+import noop from 'lodash/noop';
import classNames from 'classnames';
import { Shape } from '../@types';
import { styleShape } from './regionUtil';
@@ -7,18 +9,25 @@ import './RegionRect.scss';
type Props = {
className?: string;
isActive?: boolean;
+ onMount?: (uuid: string) => void;
shape?: Shape;
};
export type RegionRectRef = HTMLDivElement;
export function RegionRect(props: Props, ref: React.Ref): JSX.Element {
- const { className, isActive, shape } = props;
+ const uuidRef = React.useRef(uuid.v4());
+ const { className, isActive, onMount = noop, shape } = props;
+
+ React.useEffect(() => {
+ onMount(uuidRef.current);
+ }, [onMount]);
return (
);
diff --git a/src/region/__tests__/RegionCreation-test.tsx b/src/region/__tests__/RegionCreation-test.tsx
index 89186715d..fd52d56e2 100644
--- a/src/region/__tests__/RegionCreation-test.tsx
+++ b/src/region/__tests__/RegionCreation-test.tsx
@@ -15,7 +15,7 @@ describe('RegionCreation', () => {
location: 1,
resetCreator: jest.fn(),
setMessage: jest.fn(),
- setReferenceShape: jest.fn(),
+ setReferenceId: jest.fn(),
setStaged: jest.fn(),
setStatus: jest.fn(),
staged: null,
@@ -78,6 +78,14 @@ describe('RegionCreation', () => {
expect(defaults.setStatus).toHaveBeenCalledWith(CreatorStatus.staged);
});
});
+
+ describe('handleStagedMount()', () => {
+ test('should dispatch setReferenceId with received uuid', () => {
+ instance.handleStagedMount('123');
+
+ expect(defaults.setReferenceId).toHaveBeenCalledWith('123');
+ });
+ });
});
describe('render()', () => {
@@ -132,43 +140,4 @@ describe('RegionCreation', () => {
},
);
});
-
- describe('componentDidUpdate', () => {
- const mockRectRef = {
- getBoundingClientRect: () => ({
- height: 10,
- width: 10,
- top: 10,
- left: 10,
- }),
- };
-
- test('should call setReferenceShape if current rectRef and staged exist', () => {
- const wrapper = getWrapper({ staged: {} });
-
- wrapper.setState({ rectRef: mockRectRef });
-
- expect(defaults.setReferenceShape).toHaveBeenCalled();
- });
-
- test('should not call setReferenceShape if prev and current rectRef are the same', () => {
- const wrapper = getWrapper();
-
- wrapper.setProps({ staged: {} });
-
- expect(defaults.setReferenceShape).not.toHaveBeenCalled();
- });
-
- test('should not call setReferenceShape if rectRef does not exist', () => {
- const wrapper = getWrapper();
-
- wrapper.setState({ rectRef: mockRectRef });
-
- expect(defaults.setReferenceShape).toHaveBeenCalledTimes(1);
-
- wrapper.setState({ rectRef: undefined });
-
- expect(defaults.setReferenceShape).toHaveBeenCalledTimes(1);
- });
- });
});
diff --git a/src/region/__tests__/RegionCreationContainer-test.tsx b/src/region/__tests__/RegionCreationContainer-test.tsx
index 5b0dd3bd2..b6bacb4a9 100644
--- a/src/region/__tests__/RegionCreationContainer-test.tsx
+++ b/src/region/__tests__/RegionCreationContainer-test.tsx
@@ -26,7 +26,7 @@ describe('RegionCreationContainer', () => {
isDiscoverabilityEnabled: false,
location: 1,
staged: null,
- setReferenceShape: expect.any(Function),
+ setReferenceId: expect.any(Function),
setStaged: expect.any(Function),
setStatus: expect.any(Function),
store: defaults.store,
diff --git a/src/region/__tests__/RegionRect-test.tsx b/src/region/__tests__/RegionRect-test.tsx
index 5a706965b..b785cda6a 100644
--- a/src/region/__tests__/RegionRect-test.tsx
+++ b/src/region/__tests__/RegionRect-test.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { MutableRefObject } from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import RegionRect from '../RegionRect';
import { styleShape } from '../regionUtil';
@@ -9,6 +9,12 @@ jest.mock('../regionUtil', () => ({
describe('RegionRect', () => {
const getWrapper = (props = {}): ShallowWrapper => shallow();
+ const mockInitalRef = { current: '123' } as MutableRefObject;
+
+ beforeEach(() => {
+ jest.spyOn(React, 'useEffect').mockImplementation(f => f());
+ jest.spyOn(React, 'useRef').mockImplementation(() => mockInitalRef);
+ });
describe('render', () => {
test('should call styleShape with the provided shape prop value', () => {
@@ -16,14 +22,24 @@ describe('RegionRect', () => {
const wrapper = getWrapper({ shape });
expect(styleShape).toHaveBeenCalledWith(shape);
- expect(wrapper.prop('style')).toEqual(shape);
+ expect(wrapper.find('div').prop('style')).toEqual(shape);
});
test.each([true, false])('should render classNames correctly when isActive is %s', isActive => {
const wrapper = getWrapper({ isActive });
+ const divEl = wrapper.find('div');
+
+ expect(divEl.hasClass('ba-RegionRect')).toBe(true);
+ expect(divEl.hasClass('is-active')).toBe(isActive);
+ });
+ });
+
+ describe('onMount()', () => {
+ test('should call onMount with generated uuid', () => {
+ const handleMount = jest.fn();
+ getWrapper({ onMount: handleMount });
- expect(wrapper.hasClass('ba-RegionRect')).toBe(true);
- expect(wrapper.hasClass('is-active')).toBe(isActive);
+ expect(handleMount).toHaveBeenCalledWith(expect.any(String));
});
});
});
diff --git a/src/store/creator/__mocks__/creatorState.ts b/src/store/creator/__mocks__/creatorState.ts
index 86368f3fc..517c9b4ba 100644
--- a/src/store/creator/__mocks__/creatorState.ts
+++ b/src/store/creator/__mocks__/creatorState.ts
@@ -4,12 +4,7 @@ export default {
cursor: 0,
error: null,
message: 'test',
- referenceShape: {
- height: 10,
- width: 10,
- x: 10,
- y: 10,
- },
+ referenceId: '100001',
staged: {
location: 1,
shape: {
diff --git a/src/store/creator/__tests__/actions-test.ts b/src/store/creator/__tests__/actions-test.ts
deleted file mode 100644
index c95339251..000000000
--- a/src/store/creator/__tests__/actions-test.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import state from '../__mocks__/creatorState';
-import { setReferenceShapeAction } from '../actions';
-
-describe('creator/actions', () => {
- describe('setReferenceShapeAction', () => {
- const arg = {
- height: 10,
- width: 10,
- left: 10,
- top: 10,
- } as DOMRect;
- test('should prepare the argument for the payload', async () => {
- expect(setReferenceShapeAction(arg)).toEqual({
- payload: state.referenceShape,
- type: 'SET_REFERENCE_SHAPE',
- });
- });
- });
-});
diff --git a/src/store/creator/__tests__/reducer-test.ts b/src/store/creator/__tests__/reducer-test.ts
index 245a6643e..991f8ec53 100644
--- a/src/store/creator/__tests__/reducer-test.ts
+++ b/src/store/creator/__tests__/reducer-test.ts
@@ -4,9 +4,10 @@ import { createAnnotationAction } from '../../annotations';
import { CreatorStatus } from '../types';
import { NewAnnotation } from '../../../@types';
import {
+ resetCreatorAction,
setCursorAction,
setMessageAction,
- setReferenceShapeAction,
+ setReferenceIdAction,
setStagedAction,
setStatusAction,
} from '../actions';
@@ -58,12 +59,12 @@ describe('store/creator/reducer', () => {
});
});
- describe('setReferenceShapeAction', () => {
+ describe('setReferenceIdAction', () => {
test('should set the reference shape in state', () => {
- const payload = { height: 10, left: 10, top: 10, width: 10 } as DOMRect;
- const newState = reducer(state, setReferenceShapeAction(payload));
+ const payload = '123123';
+ const newState = reducer(state, setReferenceIdAction(payload));
- expect(newState.referenceShape).toEqual({ height: 10, width: 10, x: 10, y: 10 });
+ expect(newState.referenceId).toEqual('123123');
});
});
@@ -104,11 +105,39 @@ describe('store/creator/reducer', () => {
toggleAnnotationModeAction,
);
- expect(newState.cursor).toEqual(0);
- expect(newState.error).toEqual(null);
- expect(newState.message).toEqual('');
- expect(newState.staged).toEqual(null);
- expect(newState.status).toEqual(CreatorStatus.init);
+ expect(newState).toEqual({
+ cursor: 0,
+ error: null,
+ message: '',
+ referenceId: null,
+ staged: null,
+ status: CreatorStatus.init,
+ });
+ });
+ });
+
+ describe('resetCreatorAction', () => {
+ test('should reset some of the creator state', () => {
+ const error = new Error('error');
+ const newState = reducer(
+ {
+ ...state,
+ cursor: 1,
+ error,
+ referenceId: '123',
+ status: CreatorStatus.rejected,
+ },
+ resetCreatorAction,
+ );
+
+ expect(newState).toEqual({
+ cursor: 1,
+ error,
+ message: '',
+ referenceId: null,
+ staged: null,
+ status: CreatorStatus.init,
+ });
});
});
});
diff --git a/src/store/creator/__tests__/selectors-test.ts b/src/store/creator/__tests__/selectors-test.ts
index 397e7029d..41a4a8f99 100644
--- a/src/store/creator/__tests__/selectors-test.ts
+++ b/src/store/creator/__tests__/selectors-test.ts
@@ -2,7 +2,7 @@ import creatorState from '../__mocks__/creatorState';
import { CreatorStatus } from '../types';
import {
getCreatorMessage,
- getCreatorReferenceShape,
+ getCreatorReferenceId,
getCreatorStaged,
getCreatorStagedForLocation,
getCreatorStatus,
@@ -17,14 +17,9 @@ describe('store/annotations/selectors', () => {
});
});
- describe('getCreatorReferenceShape', () => {
- test('should return the current creator reference shape', () => {
- expect(getCreatorReferenceShape(state)).toEqual({
- height: 10,
- width: 10,
- x: 10,
- y: 10,
- });
+ describe('getCreatorReferenceId', () => {
+ test('should return the current creator reference id', () => {
+ expect(getCreatorReferenceId(state)).toEqual('100001');
});
});
diff --git a/src/store/creator/actions.ts b/src/store/creator/actions.ts
index 063555439..c4d4bd2c0 100644
--- a/src/store/creator/actions.ts
+++ b/src/store/creator/actions.ts
@@ -1,27 +1,9 @@
import { createAction } from '@reduxjs/toolkit';
import { CreatorItem, CreatorStatus } from './types';
-import { Shape } from '../../@types';
-
-type Payload = {
- payload: Shape;
-};
export const resetCreatorAction = createAction('RESET_CREATOR');
export const setCursorAction = createAction('SET_CREATOR_CURSOR');
export const setMessageAction = createAction('SET_CREATOR_MESSAGE');
-export const setReferenceShapeAction = createAction(
- 'SET_REFERENCE_SHAPE',
- (arg: DOMRect): Payload => {
- const { height, left, top, width } = arg;
- return {
- payload: {
- height,
- width,
- x: left,
- y: top,
- },
- };
- },
-);
+export const setReferenceIdAction = createAction('SET_CREATOR_REFERENCE_ID');
export const setStagedAction = createAction('SET_CREATOR_STAGED');
export const setStatusAction = createAction('SET_CREATOR_STATUS');
diff --git a/src/store/creator/reducer.ts b/src/store/creator/reducer.ts
index f7826d460..1d36a9dd5 100644
--- a/src/store/creator/reducer.ts
+++ b/src/store/creator/reducer.ts
@@ -5,7 +5,7 @@ import {
resetCreatorAction,
setCursorAction,
setMessageAction,
- setReferenceShapeAction,
+ setReferenceIdAction,
setStagedAction,
setStatusAction,
} from './actions';
@@ -15,6 +15,7 @@ export const initialState = {
cursor: 0,
error: null,
message: '',
+ referenceId: null,
staged: null,
status: CreatorStatus.init,
};
@@ -32,14 +33,15 @@ export default createReducer(initialState, builder =>
})
.addCase(resetCreatorAction, state => {
state.message = '';
+ state.referenceId = null;
state.staged = null;
state.status = CreatorStatus.init;
})
.addCase(setMessageAction, (state, { payload }) => {
state.message = payload;
})
- .addCase(setReferenceShapeAction, (state, { payload }) => {
- state.referenceShape = payload;
+ .addCase(setReferenceIdAction, (state, { payload }) => {
+ state.referenceId = payload;
})
.addCase(setStagedAction, (state, { payload }) => {
state.staged = payload;
diff --git a/src/store/creator/selectors.ts b/src/store/creator/selectors.ts
index a7166f51e..da2b0c1da 100644
--- a/src/store/creator/selectors.ts
+++ b/src/store/creator/selectors.ts
@@ -1,12 +1,11 @@
import { AppState } from '../types';
import { CreatorItem, CreatorItemHighlight, CreatorItemRegion, CreatorStatus } from './types';
-import { Shape } from '../../@types';
type State = Pick;
export const getCreatorCursor = (state: State): number => state.creator.cursor;
export const getCreatorMessage = (state: State): string => state.creator.message;
-export const getCreatorReferenceShape = (state: State): Shape | undefined => state.creator.referenceShape;
+export const getCreatorReferenceId = (state: State): string | null => state.creator.referenceId;
export const getCreatorStaged = (state: State): CreatorItem | null => state.creator.staged;
export const getCreatorStagedForLocation = (state: State, location: number): CreatorItem | null => {
const staged = getCreatorStaged(state);
diff --git a/src/store/creator/types.ts b/src/store/creator/types.ts
index 0ce619649..ad2d2c2e0 100644
--- a/src/store/creator/types.ts
+++ b/src/store/creator/types.ts
@@ -1,4 +1,4 @@
-import { Rect, SerializedError, Shape } from '../../@types';
+import { Rect, SerializedError } from '../../@types';
export enum CreatorStatus {
init = 'init',
@@ -26,7 +26,7 @@ export type CreatorState = {
cursor: number;
error: SerializedError | null;
message: string;
- referenceShape?: Shape;
+ referenceId: string | null;
staged: CreatorItem;
status: CreatorStatus;
};
diff --git a/yarn.lock b/yarn.lock
index 01c06a79e..9e7b2adaf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1943,6 +1943,11 @@
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==
+"@types/uuid@^8.3.0":
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
+ integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==
+
"@types/vfile-message@*":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/vfile-message/-/vfile-message-2.0.0.tgz#690e46af0fdfc1f9faae00cd049cc888957927d5"
@@ -13504,6 +13509,11 @@ uuid@^3.3.3:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+uuid@^8.3.1:
+ version "8.3.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31"
+ integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==
+
v8-compile-cache@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"