Skip to content

Commit

Permalink
fix(popup): Use reference id instead of shape (#629)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conrad Chan authored Nov 2, 2020
1 parent db5e289 commit 2a0e8c6
Show file tree
Hide file tree
Showing 28 changed files with 170 additions and 285 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
48 changes: 0 additions & 48 deletions src/common/__tests__/useWindowSize-test.tsx

This file was deleted.

31 changes: 0 additions & 31 deletions src/common/useWindowSize.ts

This file was deleted.

27 changes: 12 additions & 15 deletions src/highlight/HighlightAnnotations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand All @@ -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<HTMLAnchorElement | null>(null);
const windowSize = useWindowSize();

const canCreate = isCreating || isPromoting;

const handleAnnotationActive = (annotationId: string | null): void => {
Expand Down Expand Up @@ -82,6 +78,10 @@ const HighlightAnnotations = (props: Props): JSX.Element => {
setSelection(null);
};

const handleStagedMount = (uuid: string): void => {
setReferenceId(uuid);
};

React.useEffect(() => {
if (!isSelecting) {
return;
Expand All @@ -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 */}
Expand All @@ -117,7 +109,12 @@ const HighlightAnnotations = (props: Props): JSX.Element => {
<div className="ba-HighlightAnnotations-target">
<HighlightCanvas shapes={staged.shapes} />
<HighlightSvg>
<HighlightTarget ref={setHighlightRef} annotationId="staged" isActive shapes={staged.shapes} />
<HighlightTarget
annotationId="staged"
isActive
onMount={handleStagedMount}
shapes={staged.shapes}
/>
</HighlightSvg>
</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/highlight/HighlightContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
SelectionItem,
setActiveAnnotationIdAction,
setIsPromotingAction,
setReferenceShapeAction,
setReferenceIdAction,
setSelectionAction,
setStagedAction,
setStatusAction,
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 10 additions & 2 deletions src/highlight/HighlightTarget.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -12,14 +13,16 @@ type Props = {
className?: string;
isActive?: boolean;
onHover?: (annotationId: string | null) => void;
onMount?: (uuid: string) => void;
onSelect?: (annotationId: string) => void;
shapes: Array<Rect>;
};

export type HighlightTargetRef = HTMLAnchorElement;

const HighlightTarget = (props: Props, ref: React.Ref<HighlightTargetRef>): 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<string>(uuid.v4());
const isCurrentFileVersion = ReactRedux.useSelector(getIsCurrentFileVersion);

const handleClick = (event: React.MouseEvent<HighlightTargetRef>): void => {
Expand Down Expand Up @@ -61,11 +64,16 @@ const HighlightTarget = (props: Props, ref: React.Ref<HighlightTargetRef>): JSX.
event.currentTarget.focus();
};

React.useEffect(() => {
onMount(uuidRef.current);
}, [onMount]);

return (
// eslint-disable-next-line jsx-a11y/anchor-is-valid
<a
ref={ref}
className={classNames('ba-HighlightTarget', className, { 'is-active': isActive })}
data-ba-reference-id={uuidRef.current}
data-resin-iscurrent={isCurrentFileVersion}
data-resin-itemid={annotationId}
data-resin-target="highlightText"
Expand Down
2 changes: 1 addition & 1 deletion src/highlight/__tests__/HighlightAnnotations-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('HighlightAnnotations', () => {
selection: null,
setActiveAnnotationId: jest.fn(),
setIsPromoting: jest.fn(),
setReferenceShape: jest.fn(),
setReferenceId: jest.fn(),
setSelection: jest.fn(),
setStaged: jest.fn(),
setStatus: jest.fn(),
Expand Down
2 changes: 1 addition & 1 deletion src/highlight/__tests__/HighlightContainer-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
28 changes: 18 additions & 10 deletions src/highlight/__tests__/HighlightTarget-test.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -23,12 +23,14 @@ describe('HighlightTarget', () => {
},
],
};
const mockSetIsHover = jest.fn();

const getWrapper = (props = {}): ShallowWrapper => shallow(<HighlightTarget {...defaults} {...props} />);
const mockInitalRef = { current: '123' } as MutableRefObject<string>;

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()', () => {
Expand All @@ -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);
});
});

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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));
});
});
});
7 changes: 3 additions & 4 deletions src/popup/PopupContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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),
};
Expand Down
26 changes: 4 additions & 22 deletions src/popup/PopupLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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;
Expand All @@ -34,7 +33,7 @@ const PopupLayer = (props: Props): JSX.Element | null => {
isPromoting = false,
message,
mode,
popupReference,
referenceId,
resetCreator,
setMessage,
staged,
Expand Down Expand Up @@ -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 (
<>
Expand Down
Loading

0 comments on commit 2a0e8c6

Please sign in to comment.