box-annotations 4.0.0-beta.8 → 4.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -57
- package/dist/annotations.css +1 -1
- package/dist/annotations.js +1 -1
- package/i18n/bn-IN.js +6 -0
- package/i18n/bn-IN.properties +12 -0
- package/i18n/da-DK.js +6 -0
- package/i18n/da-DK.properties +12 -0
- package/i18n/de-DE.js +6 -0
- package/i18n/de-DE.properties +12 -0
- package/i18n/en-AU.js +6 -0
- package/i18n/en-AU.properties +12 -0
- package/i18n/en-CA.js +6 -0
- package/i18n/en-CA.properties +12 -0
- package/i18n/en-GB.js +6 -0
- package/i18n/en-GB.properties +12 -0
- package/i18n/en-US.js +6 -0
- package/i18n/en-US.properties +12 -0
- package/i18n/en-x-pseudo.js +16 -9
- package/i18n/en-x-pseudo.properties +23 -9
- package/i18n/es-419.js +6 -0
- package/i18n/es-419.properties +12 -0
- package/i18n/es-ES.js +6 -0
- package/i18n/es-ES.properties +12 -0
- package/i18n/fi-FI.js +6 -0
- package/i18n/fi-FI.properties +12 -0
- package/i18n/fr-CA.js +6 -0
- package/i18n/fr-CA.properties +12 -0
- package/i18n/fr-FR.js +6 -0
- package/i18n/fr-FR.properties +12 -0
- package/i18n/hi-IN.js +6 -0
- package/i18n/hi-IN.properties +12 -0
- package/i18n/it-IT.js +6 -0
- package/i18n/it-IT.properties +12 -0
- package/i18n/ja-JP.js +6 -0
- package/i18n/ja-JP.properties +12 -0
- package/i18n/json/src/components/Popups/messages.json +1 -1
- package/i18n/ko-KR.js +6 -0
- package/i18n/ko-KR.properties +12 -0
- package/i18n/nb-NO.js +6 -0
- package/i18n/nb-NO.properties +12 -0
- package/i18n/nl-NL.js +6 -0
- package/i18n/nl-NL.properties +12 -0
- package/i18n/pl-PL.js +6 -0
- package/i18n/pl-PL.properties +12 -0
- package/i18n/pt-BR.js +6 -0
- package/i18n/pt-BR.properties +12 -0
- package/i18n/ru-RU.js +6 -0
- package/i18n/ru-RU.properties +12 -0
- package/i18n/sv-SE.js +6 -0
- package/i18n/sv-SE.properties +12 -0
- package/i18n/tr-TR.js +6 -0
- package/i18n/tr-TR.properties +12 -0
- package/i18n/zh-CN.js +6 -0
- package/i18n/zh-CN.properties +12 -0
- package/i18n/zh-TW.js +6 -0
- package/i18n/zh-TW.properties +12 -0
- package/package.json +29 -29
- package/src/@types/events.ts +8 -2
- package/src/@types/global.ts +1 -0
- package/src/@types/model.ts +20 -7
- package/src/BoxAnnotations.ts +16 -2
- package/src/common/BaseAnnotator.scss +0 -1
- package/src/common/BaseAnnotator.ts +125 -19
- package/src/common/BaseManager.ts +67 -4
- package/src/common/DeselectListener.tsx +21 -0
- package/src/common/DeselectManager.tsx +30 -0
- package/src/common/useIsListInteractive.ts +10 -0
- package/src/common/useMountId.ts +14 -0
- package/src/common/useOutsideEvent.ts +9 -4
- package/src/common/usePrevious.ts +13 -0
- package/src/components/ItemList/ItemList.scss +7 -2
- package/src/components/ItemList/ItemList.tsx +45 -26
- package/src/components/ItemList/ItemRow.scss +19 -7
- package/src/components/ItemList/ItemRow.tsx +33 -12
- package/src/components/PointerCapture/PointerCapture.tsx +116 -0
- package/src/components/PointerCapture/index.ts +2 -0
- package/src/components/Popups/Popper.ts +1 -0
- package/src/components/Popups/PopupArrow.scss +91 -0
- package/src/components/Popups/PopupBase.scss +12 -81
- package/src/components/Popups/PopupBase.tsx +0 -1
- package/src/components/Popups/PopupCursor.tsx +1 -1
- package/src/components/Popups/PopupDrawingToolbar.scss +76 -0
- package/src/components/Popups/PopupDrawingToolbar.tsx +109 -0
- package/src/components/Popups/PopupHighlight.scss +39 -0
- package/src/components/Popups/PopupHighlight.tsx +97 -0
- package/src/components/Popups/PopupHighlightError.scss +23 -0
- package/src/components/Popups/PopupHighlightError.tsx +74 -0
- package/src/components/Popups/PopupList.scss +1 -4
- package/src/components/Popups/PopupList.tsx +2 -2
- package/src/components/Popups/PopupReply.tsx +51 -6
- package/src/components/Popups/messages.ts +30 -0
- package/src/components/ReplyField/ReplyField.scss +6 -1
- package/src/components/ReplyField/ReplyField.tsx +43 -42
- package/src/components/ReplyField/ReplyFieldContainer.tsx +2 -1
- package/src/components/ReplyForm/ReplyButton.tsx +38 -0
- package/src/components/ReplyForm/ReplyForm.scss +3 -0
- package/src/components/ReplyForm/ReplyForm.tsx +49 -12
- package/src/components/ReplyForm/ReplyFormContainer.tsx +6 -4
- package/src/constants.js +1 -8
- package/src/document/DocumentAnnotator.scss +15 -0
- package/src/document/DocumentAnnotator.ts +110 -53
- package/src/document/docUtil.ts +61 -0
- package/src/drawing/DecoratedDrawingPath.scss +9 -0
- package/src/drawing/DecoratedDrawingPath.tsx +43 -0
- package/src/drawing/DrawingAnnotations.scss +39 -0
- package/src/drawing/DrawingAnnotations.tsx +157 -0
- package/src/drawing/DrawingAnnotationsContainer.tsx +66 -0
- package/src/drawing/DrawingCreator.scss +9 -0
- package/src/drawing/DrawingCreator.tsx +183 -0
- package/src/drawing/DrawingCursor.ts +23 -0
- package/src/drawing/DrawingList.tsx +60 -0
- package/src/drawing/DrawingManager.tsx +15 -0
- package/src/drawing/DrawingPath.tsx +17 -0
- package/src/drawing/DrawingPathGroup.tsx +52 -0
- package/src/drawing/DrawingSVG.tsx +34 -0
- package/src/drawing/DrawingSVGGroup.tsx +23 -0
- package/src/drawing/DrawingTarget.scss +11 -0
- package/src/drawing/DrawingTarget.tsx +100 -0
- package/src/drawing/SVGFilterContext.js +5 -0
- package/src/drawing/actions.ts +48 -0
- package/src/drawing/drawingUtil.ts +106 -0
- package/src/drawing/index.ts +2 -0
- package/src/highlight/HighlightAnnotations.scss +12 -0
- package/src/highlight/HighlightAnnotations.tsx +144 -0
- package/src/highlight/HighlightCanvas.scss +9 -0
- package/src/highlight/HighlightCanvas.tsx +109 -0
- package/src/highlight/HighlightContainer.tsx +64 -0
- package/src/highlight/HighlightCreator.scss +12 -0
- package/src/highlight/HighlightCreatorManager.ts +79 -0
- package/src/highlight/HighlightList.scss +13 -0
- package/src/highlight/HighlightList.tsx +92 -0
- package/src/highlight/HighlightListener.ts +37 -0
- package/src/highlight/HighlightManager.tsx +15 -0
- package/src/highlight/HighlightSvg.scss +7 -0
- package/src/highlight/HighlightSvg.tsx +18 -0
- package/src/highlight/HighlightTarget.scss +5 -0
- package/src/highlight/HighlightTarget.tsx +106 -0
- package/src/highlight/actions.ts +36 -0
- package/src/highlight/highlightUtil.ts +143 -0
- package/src/highlight/index.ts +4 -0
- package/src/image/ImageAnnotator.scss +20 -0
- package/src/image/ImageAnnotator.ts +137 -0
- package/src/polyfill.ts +19 -0
- package/src/popup/PopupContainer.tsx +50 -0
- package/src/popup/PopupLayer.scss +3 -0
- package/src/popup/PopupLayer.tsx +103 -0
- package/src/popup/PopupManager.tsx +15 -0
- package/src/region/RegionAnnotation.scss +4 -0
- package/src/region/RegionAnnotation.tsx +15 -16
- package/src/region/RegionAnnotations.scss +1 -15
- package/src/region/RegionAnnotations.tsx +14 -115
- package/src/region/RegionAnnotationsContainer.tsx +24 -0
- package/src/region/RegionCreation.scss +17 -0
- package/src/region/RegionCreation.tsx +79 -0
- package/src/region/RegionCreationContainer.tsx +43 -0
- package/src/region/RegionCreationManager.tsx +15 -0
- package/src/region/RegionCreator.scss +9 -2
- package/src/region/RegionCreator.tsx +50 -71
- package/src/region/RegionList.tsx +8 -12
- package/src/region/RegionManager.tsx +7 -39
- package/src/region/RegionRect.scss +41 -9
- package/src/region/RegionRect.tsx +9 -3
- package/src/region/index.ts +1 -0
- package/src/region/regionUtil.ts +1 -8
- package/src/region/transformUtil.ts +28 -0
- package/src/store/annotations/actions.ts +1 -0
- package/src/store/annotations/reducer.ts +9 -2
- package/src/store/annotations/selectors.ts +1 -0
- package/src/store/annotations/types.ts +1 -0
- package/src/store/common/actions.ts +1 -0
- package/src/store/common/reducer.ts +16 -10
- package/src/store/common/selectors.ts +1 -0
- package/src/store/common/types.ts +3 -0
- package/src/store/createRootReducer.ts +4 -0
- package/src/store/creator/actions.ts +2 -0
- package/src/store/creator/reducer.ts +22 -3
- package/src/store/creator/selectors.ts +9 -1
- package/src/store/creator/types.ts +18 -3
- package/src/store/drawing/actions.ts +10 -0
- package/src/store/drawing/index.ts +4 -0
- package/src/store/drawing/reducer.ts +50 -0
- package/src/store/drawing/selectors.ts +9 -0
- package/src/store/drawing/types.ts +7 -0
- package/src/store/eventing/active.ts +4 -2
- package/src/store/eventing/fetch.ts +8 -0
- package/src/store/eventing/init.ts +14 -0
- package/src/store/eventing/middleware.ts +21 -3
- package/src/store/eventing/mode.ts +7 -0
- package/src/store/eventing/staged.ts +56 -0
- package/src/store/eventing/status.ts +19 -0
- package/src/store/highlight/actions.ts +106 -0
- package/src/store/highlight/index.ts +4 -0
- package/src/store/highlight/reducer.ts +37 -0
- package/src/store/highlight/selectors.ts +12 -0
- package/src/store/highlight/types.ts +14 -0
- package/src/store/index.ts +2 -0
- package/src/store/options/actions.ts +2 -0
- package/src/store/options/reducer.ts +17 -1
- package/src/store/options/selectors.ts +8 -0
- package/src/store/options/types.ts +5 -0
- package/src/store/types.ts +5 -1
- package/src/store/users/actions.ts +3 -2
- package/src/utils/resin.ts +22 -0
- package/src/utils/rotate.ts +131 -0
- package/src/utils/scroll.ts +45 -0
- package/src/utils/util.ts +3 -0
- package/src/region/RegionContainer.tsx +0 -49
- package/src/utils/polyfill.js +0 -161
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import noop from 'lodash/noop';
|
|
4
|
+
import DecoratedDrawingPath from './DecoratedDrawingPath';
|
|
5
|
+
import DrawingPathGroup from './DrawingPathGroup';
|
|
6
|
+
import { DrawingSVGRef } from './DrawingSVG';
|
|
7
|
+
import { getCenter, getShape } from './drawingUtil';
|
|
8
|
+
import { MOUSE_PRIMARY } from '../constants';
|
|
9
|
+
import { TargetDrawing } from '../@types';
|
|
10
|
+
import './DrawingTarget.scss';
|
|
11
|
+
|
|
12
|
+
export type Props = {
|
|
13
|
+
annotationId: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
isActive?: boolean;
|
|
16
|
+
onSelect?: (annotationId: string) => void;
|
|
17
|
+
rootEl: DrawingSVGRef | null;
|
|
18
|
+
target: TargetDrawing;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type DrawingTargetRef = HTMLAnchorElement;
|
|
22
|
+
|
|
23
|
+
export const DrawingTarget = (props: Props, ref: React.Ref<DrawingTargetRef>): JSX.Element => {
|
|
24
|
+
const {
|
|
25
|
+
annotationId,
|
|
26
|
+
className,
|
|
27
|
+
isActive = false,
|
|
28
|
+
onSelect = noop,
|
|
29
|
+
rootEl,
|
|
30
|
+
target: { path_groups: pathGroups },
|
|
31
|
+
} = props;
|
|
32
|
+
const shape = getShape(pathGroups);
|
|
33
|
+
const { x: centerX, y: centerY } = getCenter(shape);
|
|
34
|
+
|
|
35
|
+
const handleFocus = (): void => {
|
|
36
|
+
onSelect(annotationId);
|
|
37
|
+
};
|
|
38
|
+
const handleMouseDown = (event: React.MouseEvent<DrawingTargetRef>): void => {
|
|
39
|
+
if (event.buttons !== MOUSE_PRIMARY) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const activeElement = document.activeElement as HTMLElement;
|
|
43
|
+
|
|
44
|
+
event.preventDefault(); // Prevents focus from leaving the button immediately in some browsers
|
|
45
|
+
event.stopPropagation(); // Prevents document-level deselect event handlers from executing
|
|
46
|
+
|
|
47
|
+
// IE11 won't apply the focus to the SVG anchor, so this workaround attempts to blur the existing active element.
|
|
48
|
+
// If we don't blur it, we cannot re-focus it next time, since it was already focused and never got blurred.
|
|
49
|
+
if (activeElement && activeElement !== event.currentTarget && activeElement.blur) {
|
|
50
|
+
activeElement.blur();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (event.currentTarget.focus) {
|
|
54
|
+
// Buttons do not receive focus in Firefox and Safari on MacOS; triggers handleFocus
|
|
55
|
+
event.currentTarget.focus();
|
|
56
|
+
} else {
|
|
57
|
+
// IE11 does not support focus function; call handleFocus directly
|
|
58
|
+
handleFocus();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
// eslint-disable-next-line jsx-a11y/anchor-is-valid
|
|
64
|
+
<a
|
|
65
|
+
ref={ref}
|
|
66
|
+
className={classNames('ba-DrawingTarget', className, { 'is-active': isActive })}
|
|
67
|
+
data-resin-itemid={annotationId}
|
|
68
|
+
data-resin-target="highlightDrawing"
|
|
69
|
+
data-testid={`ba-AnnotationTarget-${annotationId}`}
|
|
70
|
+
href="#"
|
|
71
|
+
onFocus={handleFocus}
|
|
72
|
+
onMouseDown={handleMouseDown}
|
|
73
|
+
role="button"
|
|
74
|
+
tabIndex={0}
|
|
75
|
+
>
|
|
76
|
+
<rect
|
|
77
|
+
fill="transparent"
|
|
78
|
+
transform={`translate(-${centerX * 0.1}, -${centerY * 0.1}) scale(1.1)`}
|
|
79
|
+
{...shape}
|
|
80
|
+
/>
|
|
81
|
+
{pathGroups.map(({ clientId: pathGroupClientId, paths, stroke }) => (
|
|
82
|
+
<DrawingPathGroup key={pathGroupClientId} isActive={isActive} rootEl={rootEl} stroke={stroke}>
|
|
83
|
+
{/* Use the children render function to pass down the calculated strokeWidthWithBorder value */}
|
|
84
|
+
{strokeWidthWithBorder =>
|
|
85
|
+
paths.map(({ clientId: pathClientId, points }) => (
|
|
86
|
+
<DecoratedDrawingPath
|
|
87
|
+
key={pathClientId}
|
|
88
|
+
borderStrokeWidth={strokeWidthWithBorder}
|
|
89
|
+
isDecorated
|
|
90
|
+
points={points}
|
|
91
|
+
/>
|
|
92
|
+
))
|
|
93
|
+
}
|
|
94
|
+
</DrawingPathGroup>
|
|
95
|
+
))}
|
|
96
|
+
</a>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export default React.forwardRef(DrawingTarget);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AppThunkDispatch, AppState, getCreatorStatus, CreatorStatus } from '../store';
|
|
2
|
+
import { createAnnotationAction } from '../store/annotations';
|
|
3
|
+
import { getFileVersionId } from '../store/options';
|
|
4
|
+
import { PathGroup } from '../@types';
|
|
5
|
+
import { resetDrawingAction, setDrawingLocationAction } from '../store/drawing';
|
|
6
|
+
|
|
7
|
+
export type CreateArg = {
|
|
8
|
+
location: number;
|
|
9
|
+
message: string;
|
|
10
|
+
pathGroups: Array<PathGroup>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const createDrawingAction = (arg: CreateArg) => (dispatch: AppThunkDispatch, getState: () => AppState) => {
|
|
14
|
+
const { location, message, pathGroups } = arg;
|
|
15
|
+
const state = getState();
|
|
16
|
+
const newAnnotation = {
|
|
17
|
+
description: {
|
|
18
|
+
message,
|
|
19
|
+
type: 'reply' as const,
|
|
20
|
+
},
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
22
|
+
file_version: {
|
|
23
|
+
id: getFileVersionId(state),
|
|
24
|
+
},
|
|
25
|
+
target: {
|
|
26
|
+
location: {
|
|
27
|
+
type: 'page' as const,
|
|
28
|
+
value: location,
|
|
29
|
+
},
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
31
|
+
path_groups: pathGroups,
|
|
32
|
+
type: 'drawing' as const,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return dispatch(createAnnotationAction(newAnnotation));
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const setupDrawingAction = (location: number) => (dispatch: AppThunkDispatch, getState: () => AppState) => {
|
|
40
|
+
const state = getState();
|
|
41
|
+
const creatorStatus = getCreatorStatus(state);
|
|
42
|
+
|
|
43
|
+
if (creatorStatus === CreatorStatus.staged) {
|
|
44
|
+
dispatch(resetDrawingAction());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return dispatch(setDrawingLocationAction(location));
|
|
48
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as uuid from 'uuid';
|
|
2
|
+
import { Annotation, AnnotationDrawing, PathGroup, Position, Shape } from '../@types';
|
|
3
|
+
|
|
4
|
+
export function addClientIds({ paths, ...groupRest }: PathGroup): PathGroup {
|
|
5
|
+
return {
|
|
6
|
+
clientId: uuid.v4(),
|
|
7
|
+
paths: paths.map(path => ({
|
|
8
|
+
clientId: uuid.v4(),
|
|
9
|
+
...path,
|
|
10
|
+
})),
|
|
11
|
+
...groupRest,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formatDrawing(annotation: AnnotationDrawing): AnnotationDrawing {
|
|
16
|
+
const {
|
|
17
|
+
target: { path_groups: pathGroups, ...targetRest },
|
|
18
|
+
...rest
|
|
19
|
+
} = annotation;
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
target: {
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
24
|
+
path_groups: pathGroups.map(pathGroup => addClientIds(pathGroup)),
|
|
25
|
+
...targetRest,
|
|
26
|
+
},
|
|
27
|
+
...rest,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getCenter({ height, width, x, y }: Shape): Position {
|
|
32
|
+
return { x: x + width / 2, y: y + height / 2 };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// We use cubic Bezier curves to generate path commands for better smoothing.
|
|
36
|
+
// For every data point, we generate extra two points using adjacent data points.
|
|
37
|
+
// Then we use the first generated point and the data point as two control points
|
|
38
|
+
// and the second generated point as the destination point to form a (C)urve command.
|
|
39
|
+
export const getPathCommands = (points?: Position[]): string => {
|
|
40
|
+
if (!points || !points.length) {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const d = points
|
|
45
|
+
.map(({ x, y }, index, array) => {
|
|
46
|
+
if (index === 0) {
|
|
47
|
+
return `M ${x} ${y}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const prevPoint = array[index - 1];
|
|
51
|
+
const nextPoint = array[index + 1];
|
|
52
|
+
if (!prevPoint || !nextPoint) {
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const xc1 = (x + prevPoint.x) / 2;
|
|
57
|
+
const yc1 = (y + prevPoint.y) / 2;
|
|
58
|
+
const xc2 = (x + nextPoint.x) / 2;
|
|
59
|
+
const yc2 = (y + nextPoint.y) / 2;
|
|
60
|
+
|
|
61
|
+
return `C ${xc1} ${yc1}, ${x} ${y}, ${xc2} ${yc2}`;
|
|
62
|
+
})
|
|
63
|
+
.join(' ')
|
|
64
|
+
.trim();
|
|
65
|
+
|
|
66
|
+
return d;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export function getShape(pathGroups: PathGroup[]): Shape {
|
|
70
|
+
let maxX = 0;
|
|
71
|
+
let maxY = 0;
|
|
72
|
+
// Initialize mins with MAX_VALUE so that any possible
|
|
73
|
+
// input value of the first point can be captured by Math.min
|
|
74
|
+
let minX = Number.MAX_VALUE;
|
|
75
|
+
let minY = Number.MAX_VALUE;
|
|
76
|
+
|
|
77
|
+
pathGroups.forEach(({ paths }) => {
|
|
78
|
+
paths.forEach(({ points }) => {
|
|
79
|
+
points.forEach(({ x, y }) => {
|
|
80
|
+
maxX = Math.max(maxX, x);
|
|
81
|
+
maxY = Math.max(maxY, y);
|
|
82
|
+
minX = Math.min(minX, x);
|
|
83
|
+
minY = Math.min(minY, y);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
height: Math.max(0, maxY - minY),
|
|
90
|
+
width: Math.max(0, maxX - minX),
|
|
91
|
+
x: minX === Number.MAX_VALUE ? 0 : minX,
|
|
92
|
+
y: minY === Number.MAX_VALUE ? 0 : minY,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function isDrawing(annotation: Annotation): annotation is AnnotationDrawing {
|
|
97
|
+
return annotation?.target?.type === 'drawing';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function centerDrawing(pathGroups: PathGroup[]): Position {
|
|
101
|
+
return getCenter(getShape(pathGroups));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function isVectorEffectSupported(): boolean {
|
|
105
|
+
return 'vector-effect' in document.body.style;
|
|
106
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import HighlightCanvas from './HighlightCanvas';
|
|
3
|
+
import HighlightList from './HighlightList';
|
|
4
|
+
import HighlightSvg from './HighlightSvg';
|
|
5
|
+
import HighlightTarget from './HighlightTarget';
|
|
6
|
+
import PopupHighlight from '../components/Popups/PopupHighlight';
|
|
7
|
+
import PopupHighlightError from '../components/Popups/PopupHighlightError';
|
|
8
|
+
import { AnnotationHighlight } from '../@types';
|
|
9
|
+
import { CreateArg } from './actions';
|
|
10
|
+
import { CreatorItemHighlight, CreatorStatus, SelectionArg, SelectionItem } from '../store';
|
|
11
|
+
import { getBoundingRect, getShapeRelativeToContainer } from './highlightUtil';
|
|
12
|
+
import './HighlightAnnotations.scss';
|
|
13
|
+
|
|
14
|
+
type Props = {
|
|
15
|
+
activeAnnotationId: string | null;
|
|
16
|
+
annotations: AnnotationHighlight[];
|
|
17
|
+
createHighlight?: (arg: CreateArg) => void;
|
|
18
|
+
isCreating: boolean;
|
|
19
|
+
isPending: boolean;
|
|
20
|
+
isPromoting: boolean;
|
|
21
|
+
isSelecting: boolean;
|
|
22
|
+
location: number;
|
|
23
|
+
selection: SelectionItem | null;
|
|
24
|
+
setActiveAnnotationId: (annotationId: string | null) => void;
|
|
25
|
+
setIsPromoting: (isPromoting: boolean) => void;
|
|
26
|
+
setReferenceId: (uuid: string) => void;
|
|
27
|
+
setSelection: (selection: SelectionArg | null) => void;
|
|
28
|
+
setStaged: (staged: CreatorItemHighlight | null) => void;
|
|
29
|
+
setStatus: (status: CreatorStatus) => void;
|
|
30
|
+
staged?: CreatorItemHighlight | null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const HighlightAnnotations = (props: Props): JSX.Element => {
|
|
34
|
+
const {
|
|
35
|
+
activeAnnotationId,
|
|
36
|
+
annotations = [],
|
|
37
|
+
isCreating = false,
|
|
38
|
+
isPending = false,
|
|
39
|
+
isPromoting = false,
|
|
40
|
+
isSelecting = false,
|
|
41
|
+
selection,
|
|
42
|
+
setActiveAnnotationId,
|
|
43
|
+
setIsPromoting,
|
|
44
|
+
setReferenceId,
|
|
45
|
+
setSelection,
|
|
46
|
+
setStaged,
|
|
47
|
+
setStatus,
|
|
48
|
+
staged,
|
|
49
|
+
} = props;
|
|
50
|
+
const canCreate = isCreating || isPromoting;
|
|
51
|
+
|
|
52
|
+
const handleAnnotationActive = (annotationId: string | null): void => {
|
|
53
|
+
setActiveAnnotationId(annotationId);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const stageSelection = React.useCallback((): void => {
|
|
57
|
+
if (!selection) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { containerRect, location, rects } = selection;
|
|
62
|
+
|
|
63
|
+
setStaged({
|
|
64
|
+
location,
|
|
65
|
+
shapes: rects.map(rect => ({
|
|
66
|
+
...getShapeRelativeToContainer(rect, containerRect),
|
|
67
|
+
type: 'rect',
|
|
68
|
+
})),
|
|
69
|
+
});
|
|
70
|
+
setStatus(CreatorStatus.staged);
|
|
71
|
+
}, [selection, setStaged, setStatus]);
|
|
72
|
+
|
|
73
|
+
const handleCancel = (): void => {
|
|
74
|
+
setSelection(null);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const handlePromote = (): void => {
|
|
78
|
+
stageSelection();
|
|
79
|
+
setIsPromoting(true);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const handleStagedMount = (uuid: string): void => {
|
|
83
|
+
setReferenceId(uuid);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
React.useEffect(() => {
|
|
87
|
+
if (!isSelecting || isPending) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setStaged(null);
|
|
92
|
+
setStatus(CreatorStatus.init);
|
|
93
|
+
}, [isSelecting, isPending, setStaged, setStatus]);
|
|
94
|
+
|
|
95
|
+
React.useEffect(() => {
|
|
96
|
+
if (!isCreating || !selection || selection.hasError || isPending) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
stageSelection();
|
|
101
|
+
}, [isCreating, isPending, selection, stageSelection]);
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
105
|
+
{/* Layer 1: Saved annotations */}
|
|
106
|
+
<HighlightList activeId={activeAnnotationId} annotations={annotations} onSelect={handleAnnotationActive} />
|
|
107
|
+
|
|
108
|
+
{/* Layer 2: Staged (unsaved) highlight target, if any */}
|
|
109
|
+
{canCreate && staged && (
|
|
110
|
+
<div className="ba-HighlightAnnotations-target">
|
|
111
|
+
<HighlightCanvas shapes={staged.shapes} />
|
|
112
|
+
<HighlightSvg>
|
|
113
|
+
<HighlightTarget
|
|
114
|
+
annotationId="staged"
|
|
115
|
+
isActive
|
|
116
|
+
onMount={handleStagedMount}
|
|
117
|
+
shapes={staged.shapes}
|
|
118
|
+
/>
|
|
119
|
+
</HighlightSvg>
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
{/* Layer 3a: Annotations promoter to promote selection to staged */}
|
|
124
|
+
{!isCreating && selection && !selection.hasError && (
|
|
125
|
+
<div className="ba-HighlightAnnotations-popup">
|
|
126
|
+
<PopupHighlight
|
|
127
|
+
onCancel={handleCancel}
|
|
128
|
+
onSubmit={handlePromote}
|
|
129
|
+
shape={getBoundingRect(selection.rects)}
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
)}
|
|
133
|
+
|
|
134
|
+
{/* Layer 3b: Highlight error popup */}
|
|
135
|
+
{selection && selection.hasError && (
|
|
136
|
+
<div className="ba-HighlightAnnotations-popup">
|
|
137
|
+
<PopupHighlightError onCancel={handleCancel} shape={getBoundingRect(selection.rects)} />
|
|
138
|
+
</div>
|
|
139
|
+
)}
|
|
140
|
+
</>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default HighlightAnnotations;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { bdlYellow, black, white } from 'box-ui-elements/es/styles/variables';
|
|
3
|
+
import { Rect } from '../@types';
|
|
4
|
+
import './HighlightCanvas.scss';
|
|
5
|
+
|
|
6
|
+
export type CanvasShape = Rect & { isActive?: boolean; isHover?: boolean };
|
|
7
|
+
|
|
8
|
+
export type Props = {
|
|
9
|
+
shapes: CanvasShape[] | CanvasShape;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default class HighlightCanvas extends React.PureComponent<Props> {
|
|
13
|
+
static defaultProps = {
|
|
14
|
+
shapes: [],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
canvasRef: React.RefObject<HTMLCanvasElement> = React.createRef();
|
|
18
|
+
|
|
19
|
+
componentDidMount(): void {
|
|
20
|
+
this.scaleCanvas();
|
|
21
|
+
this.renderRects();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
componentDidUpdate(): void {
|
|
25
|
+
this.clearCanvas();
|
|
26
|
+
this.renderRects();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getContext(): CanvasRenderingContext2D | null {
|
|
30
|
+
const { current: canvasRef } = this.canvasRef;
|
|
31
|
+
return canvasRef?.getContext('2d') ?? null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
scaleCanvas(): void {
|
|
35
|
+
const { current: canvasRef } = this.canvasRef;
|
|
36
|
+
|
|
37
|
+
if (!canvasRef) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
canvasRef.width = canvasRef.offsetWidth;
|
|
42
|
+
canvasRef.height = canvasRef.offsetHeight;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
clearCanvas(): void {
|
|
46
|
+
const { current: canvasRef } = this.canvasRef;
|
|
47
|
+
const context = canvasRef && canvasRef.getContext('2d');
|
|
48
|
+
|
|
49
|
+
if (!canvasRef || !context) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
context.clearRect(0, 0, canvasRef.width, canvasRef.height);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
renderRects(): void {
|
|
57
|
+
const { shapes } = this.props;
|
|
58
|
+
const { current: canvasRef } = this.canvasRef;
|
|
59
|
+
const context = canvasRef && canvasRef.getContext('2d');
|
|
60
|
+
const canvasHeight = canvasRef?.height ?? 0;
|
|
61
|
+
const canvasWidth = canvasRef?.width ?? 0;
|
|
62
|
+
const shapesArray = Array.isArray(shapes) ? shapes : [shapes];
|
|
63
|
+
|
|
64
|
+
if (!context) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
shapesArray.forEach(rect => {
|
|
69
|
+
const { height, isActive, isHover, width, x, y } = rect;
|
|
70
|
+
const rectHeight = (height / 100) * canvasHeight;
|
|
71
|
+
const rectWidth = (width / 100) * canvasWidth;
|
|
72
|
+
const x1 = (x / 100) * canvasWidth;
|
|
73
|
+
const y1 = (y / 100) * canvasHeight;
|
|
74
|
+
|
|
75
|
+
context.save();
|
|
76
|
+
|
|
77
|
+
// Draw the highlight rect
|
|
78
|
+
context.fillStyle = bdlYellow;
|
|
79
|
+
context.globalAlpha = isActive || isHover ? 0.66 : 0.33;
|
|
80
|
+
context.fillRect(x1, y1, rectWidth, rectHeight);
|
|
81
|
+
context.restore();
|
|
82
|
+
context.save();
|
|
83
|
+
|
|
84
|
+
// Draw the white border
|
|
85
|
+
context.strokeStyle = white;
|
|
86
|
+
context.lineWidth = 1;
|
|
87
|
+
context.strokeRect(x1, y1, rectWidth, rectHeight);
|
|
88
|
+
|
|
89
|
+
// If annotation is active, apply a shadow
|
|
90
|
+
if (isActive) {
|
|
91
|
+
const imgData = context.getImageData(x1, y1, rectWidth, rectHeight);
|
|
92
|
+
|
|
93
|
+
context.save();
|
|
94
|
+
context.shadowColor = black;
|
|
95
|
+
context.shadowBlur = 10;
|
|
96
|
+
|
|
97
|
+
context.strokeRect(x1, y1, rectWidth, rectHeight);
|
|
98
|
+
context.putImageData(imgData, x1, y1);
|
|
99
|
+
context.restore();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
context.restore();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
render(): JSX.Element {
|
|
107
|
+
return <canvas ref={this.canvasRef} className="ba-HighlightCanvas" />;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { connect } from 'react-redux';
|
|
2
|
+
import HighlightAnnotations from './HighlightAnnotations';
|
|
3
|
+
import withProviders from '../common/withProviders';
|
|
4
|
+
import { AnnotationHighlight } from '../@types';
|
|
5
|
+
import {
|
|
6
|
+
AppState,
|
|
7
|
+
CreatorItemHighlight,
|
|
8
|
+
CreatorStatus,
|
|
9
|
+
getActiveAnnotationId,
|
|
10
|
+
getAnnotationMode,
|
|
11
|
+
getAnnotationsForLocation,
|
|
12
|
+
getCreatorStagedForLocation,
|
|
13
|
+
getCreatorStatus,
|
|
14
|
+
getIsPromoting,
|
|
15
|
+
getIsSelecting,
|
|
16
|
+
getSelectionForLocation,
|
|
17
|
+
isCreatorStagedHighlight,
|
|
18
|
+
Mode,
|
|
19
|
+
SelectionItem,
|
|
20
|
+
setActiveAnnotationIdAction,
|
|
21
|
+
setIsPromotingAction,
|
|
22
|
+
setReferenceIdAction,
|
|
23
|
+
setSelectionAction,
|
|
24
|
+
setStagedAction,
|
|
25
|
+
setStatusAction,
|
|
26
|
+
} from '../store';
|
|
27
|
+
import { isHighlight } from './highlightUtil';
|
|
28
|
+
|
|
29
|
+
export type Props = {
|
|
30
|
+
activeAnnotationId: string | null;
|
|
31
|
+
annotations: AnnotationHighlight[];
|
|
32
|
+
isCreating: boolean;
|
|
33
|
+
isPending: boolean;
|
|
34
|
+
isPromoting: boolean;
|
|
35
|
+
isSelecting: boolean;
|
|
36
|
+
selection: SelectionItem | null;
|
|
37
|
+
staged: CreatorItemHighlight | null;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const mapStateToProps = (state: AppState, { location }: { location: number }): Props => {
|
|
41
|
+
const staged = getCreatorStagedForLocation(state, location);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
activeAnnotationId: getActiveAnnotationId(state),
|
|
45
|
+
annotations: getAnnotationsForLocation(state, location).filter(isHighlight),
|
|
46
|
+
isCreating: getAnnotationMode(state) === Mode.HIGHLIGHT,
|
|
47
|
+
isPending: getCreatorStatus(state) === CreatorStatus.pending,
|
|
48
|
+
isPromoting: getIsPromoting(state),
|
|
49
|
+
isSelecting: getIsSelecting(state),
|
|
50
|
+
selection: getSelectionForLocation(state, location),
|
|
51
|
+
staged: isCreatorStagedHighlight(staged) ? staged : null,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const mapDispatchToProps = {
|
|
56
|
+
setActiveAnnotationId: setActiveAnnotationIdAction,
|
|
57
|
+
setIsPromoting: setIsPromotingAction,
|
|
58
|
+
setReferenceId: setReferenceIdAction,
|
|
59
|
+
setSelection: setSelectionAction,
|
|
60
|
+
setStaged: setStagedAction,
|
|
61
|
+
setStatus: setStatusAction,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export default connect(mapStateToProps, mapDispatchToProps)(withProviders(HighlightAnnotations));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
$text_cursor_32: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAIKADAAQAAAABAAAAIAAAAACPTkDJAAABrklEQVRYCWNgGAWjITAaAqMhQCAEfv36NeX///9/gBgO/v379/f716/TCWglSpqRkKq/f//+tjAxYfn8+TNcKS8vL8OJM2f+MDMzs8IFacUA+RTkY5D3NVRUYKHwBxQytLITq7nIDgBa/g3mEmz0169fP3z58qUfKMeG1TAkQRYkNlHMT58+/Q3w8eF8/vw5TvXiEhL8nd3daTq6uiA1hTgVAiWY8Elik3v86NFnZMvZ2NgY/AMCGOISEhgEBAXBWl6+eMFQUVrKxcjImIjNDGQxkh2ArBnETkpJYdDS1mYwMjb+P3vu3N8w+RdAR3BxcfHD+Lhoih0wY9o0huVLlzIcO3KEUVtHh+QoJVkDuk8mTpnyhZOT89/ZM2f4gEFOMFuj66c4BGxsbVnu3r37WkxMDB786Jbg41McAknx8RzmFhbKRw8fZrh69SrcLgkJCYZv3759hAvgYJDsAFk5OV5JSUkGWE64eOECAwiDAMwBwGzI0NHdDSor5uOwl3RhUIEDKwl//vz5HcTHBUgpiAi6BLkygjlg5FZGSEFO/8qIYFyNKhgNgdEQGKohAAD+bzKe7UZRtgAAAABJRU5ErkJggg==';
|
|
2
|
+
$text_cursor_32_2x: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAABlmWCKAAADvElEQVR4Ae2ZzUsbQRTA37a1BSkVhNjEg400h2ouQiWpaFIpftGmxP4FQqs9RLykiIj0JD3YIgVvFnvrUYppUq0kSk9Wi0URcrNgtGCKFyW9JKHZvrfNVjTJmt3R3bSdBy+zO/ve7rzfvJnMzgJw4QQ4AU6AE+AEOAFOgBPgBDgBToAT4AQ4AU5AJQFRFGtQw6hJ1JOEbMi2RuVjStc8G9BJgR+/Hi6ViATWhmBkSbzHxVuNjXBwcKB4u4qKClheXSWblCAIlxSNdbp4Tqfn/LuPKTQEbthsImkBKZkhcBoZ8Ai7N4KaKqKbyYZsyackhBkAjuVt1HYa06hKc8qXbMRtWMYKZIZSdQIvLqP2oSo9RxVYZgAqnnYTbS+qsD9uehkrnKivUCMIwXLcQMv5BS1Oan3SqZT4xO8XPi4uQjqdVusu2ZtMJnA4nTA4NCReNZvvYOUbhNCGSSdqumHWSZcMCMzMCOH5ec3BU1v39vbgfSgEXo9H+B6PU9AEoZeusYguAOLxOEsbj/jSWuPF2Jg8BzBPproMgSMR5Dmx1taCr78f6urrwVJdDVtbWzA1OQkf5ubyWAN8XlmR6+3ygdZSlwxQapzL7YZAMAj3vV4wVVWBmMmA3W6HlxMT0NHVldeVhkNWaGJkEsMBrK+twbtAAAZ8PqDldEtTE7ydnpaC6u3rYwquGGfDASQSCXg6MgKR8O/FYTKZhLnZWant1222YmJgsimJOYAisGGw7tZWuGa1ghWVpLy8XCrP8sdwAJWVldJ4p//4TCYjxmIxIYVZoJcYPgSej49LC5yN9fWNZqdTuNvRAc9GR/WKHwwH0NDQIAW7EInE9vf3pePmlhbdABg+BKLRqJQBvoGB23X490cTX7XF8hMJUOfIC54zA2J4BowMD8OnpSUK8IrL5YKvm5vwwOs9HwoGhfjubt7Aab2QlR/ygdbS8Az4trMDD3t6cto/6Pfn1MkVDodDPozKB1pLXTLAbDZrbV+OH+0r0hth9sLrHAOVFboA8HZ3i+2dnVBWVqayeYfm9Dp8z+OBQChEr8M0NyyiTh1alMgRvqNLcsKeoGymtVxAx1PZENElA7J9Q1tixewbFupKmvDoNfAxKm2E5J8hC3kXqGeeBLEn6CsPjUU3qtKWF22J/dkUxQC28dxwOY0MoODbUJWClwMlG7JlnrzkG7KWzAsNzAD+ZYi1F/5qf8wA+tqrVkrmyxAzfIz8//48zkyQ34AT4AQ4AU6AE+AEOAFOgBPgBDgBToAT4AT0JvAL80N/mFc/WlQAAAAASUVORK5CYII=';
|
|
3
|
+
$text_cursor_32_3x: 'data:image/png;base64,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';
|
|
4
|
+
|
|
5
|
+
@mixin ba-HighlightCreator-cursor {
|
|
6
|
+
/* The custom cursor focus point (10, 16) is not the center of the image (16, 16) */
|
|
7
|
+
$offset_x: 10;
|
|
8
|
+
$offset_y: 16;
|
|
9
|
+
|
|
10
|
+
cursor: url($text_cursor_32) $offset_x $offset_y, text; /* Legacy */
|
|
11
|
+
cursor: image-set(url($text_cursor_32) 1x, url($text_cursor_32_2x) 2x, url($text_cursor_32_3x) 3x) $offset_x $offset_y, text; /* Webkit */ /* stylelint-disable-line */
|
|
12
|
+
}
|