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,157 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import DecoratedDrawingPath from './DecoratedDrawingPath';
|
|
4
|
+
import DrawingList from './DrawingList';
|
|
5
|
+
import DrawingCreator from './DrawingCreator';
|
|
6
|
+
import DrawingPathGroup from './DrawingPathGroup';
|
|
7
|
+
import DrawingSVG, { DrawingSVGRef } from './DrawingSVG';
|
|
8
|
+
import DrawingSVGGroup from './DrawingSVGGroup';
|
|
9
|
+
import PopupDrawingToolbar, { PopupBaseRef } from '../components/Popups/PopupDrawingToolbar';
|
|
10
|
+
import { AnnotationDrawing, PathGroup } from '../@types';
|
|
11
|
+
import { CreatorItemDrawing, CreatorStatus } from '../store';
|
|
12
|
+
import './DrawingAnnotations.scss';
|
|
13
|
+
|
|
14
|
+
export type Props = {
|
|
15
|
+
activeAnnotationId: string | null;
|
|
16
|
+
addDrawingPathGroup: (pathGroup: PathGroup) => void;
|
|
17
|
+
annotations: AnnotationDrawing[];
|
|
18
|
+
canShowPopupToolbar: boolean;
|
|
19
|
+
color: string;
|
|
20
|
+
drawnPathGroups: Array<PathGroup>;
|
|
21
|
+
isCreating: boolean;
|
|
22
|
+
location: number;
|
|
23
|
+
redoDrawingPathGroup: () => void;
|
|
24
|
+
resetDrawing: () => void;
|
|
25
|
+
setActiveAnnotationId: (annotationId: string | null) => void;
|
|
26
|
+
setReferenceId: (uuid: string) => void;
|
|
27
|
+
setStaged: (staged: CreatorItemDrawing | null) => void;
|
|
28
|
+
setStatus: (status: CreatorStatus) => void;
|
|
29
|
+
setupDrawing: (location: number) => void;
|
|
30
|
+
stashedPathGroups: Array<PathGroup>;
|
|
31
|
+
undoDrawingPathGroup: () => void;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const DrawingAnnotations = (props: Props): JSX.Element => {
|
|
35
|
+
const {
|
|
36
|
+
activeAnnotationId,
|
|
37
|
+
addDrawingPathGroup,
|
|
38
|
+
annotations,
|
|
39
|
+
canShowPopupToolbar,
|
|
40
|
+
color,
|
|
41
|
+
drawnPathGroups,
|
|
42
|
+
isCreating,
|
|
43
|
+
location,
|
|
44
|
+
redoDrawingPathGroup,
|
|
45
|
+
resetDrawing,
|
|
46
|
+
setActiveAnnotationId,
|
|
47
|
+
setReferenceId,
|
|
48
|
+
setStaged,
|
|
49
|
+
setStatus,
|
|
50
|
+
setupDrawing,
|
|
51
|
+
stashedPathGroups,
|
|
52
|
+
undoDrawingPathGroup,
|
|
53
|
+
} = props;
|
|
54
|
+
const [isDrawing, setIsDrawing] = React.useState<boolean>(false);
|
|
55
|
+
const [stagedRootEl, setStagedRootEl] = React.useState<DrawingSVGRef | null>(null);
|
|
56
|
+
const hasDrawnPathGroups = drawnPathGroups.length > 0;
|
|
57
|
+
const hasStashedPathGroups = stashedPathGroups.length > 0;
|
|
58
|
+
const hasPathGroups = hasDrawnPathGroups || hasStashedPathGroups;
|
|
59
|
+
const popupDrawingToolbarRef = React.useRef<PopupBaseRef>(null);
|
|
60
|
+
const stagedGroupRef = React.useRef<SVGGElement>(null);
|
|
61
|
+
const { current: drawingSVGGroup } = stagedGroupRef;
|
|
62
|
+
|
|
63
|
+
const handleAnnotationActive = (annotationId: string | null): void => {
|
|
64
|
+
setActiveAnnotationId(annotationId);
|
|
65
|
+
};
|
|
66
|
+
const handleDelete = (): void => {
|
|
67
|
+
resetDrawing();
|
|
68
|
+
};
|
|
69
|
+
const handleDrawingMount = (uuid: string): void => {
|
|
70
|
+
setReferenceId(uuid);
|
|
71
|
+
};
|
|
72
|
+
const handleRedo = (): void => {
|
|
73
|
+
redoDrawingPathGroup();
|
|
74
|
+
};
|
|
75
|
+
const handleReply = (): void => {
|
|
76
|
+
setStaged({ location, pathGroups: drawnPathGroups });
|
|
77
|
+
setStatus(CreatorStatus.staged);
|
|
78
|
+
};
|
|
79
|
+
const handleStart = (): void => {
|
|
80
|
+
setupDrawing(location);
|
|
81
|
+
setStatus(CreatorStatus.started);
|
|
82
|
+
setIsDrawing(true);
|
|
83
|
+
};
|
|
84
|
+
const handleStop = (pathGroup: PathGroup): void => {
|
|
85
|
+
addDrawingPathGroup(pathGroup);
|
|
86
|
+
setIsDrawing(false);
|
|
87
|
+
};
|
|
88
|
+
const handleUndo = (): void => {
|
|
89
|
+
undoDrawingPathGroup();
|
|
90
|
+
};
|
|
91
|
+
React.useEffect(() => {
|
|
92
|
+
const { current: popup } = popupDrawingToolbarRef;
|
|
93
|
+
if (popup?.popper && drawnPathGroups.length) {
|
|
94
|
+
popup.popper.update();
|
|
95
|
+
}
|
|
96
|
+
}, [drawnPathGroups]);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<>
|
|
100
|
+
<DrawingList
|
|
101
|
+
activeId={activeAnnotationId}
|
|
102
|
+
annotations={annotations}
|
|
103
|
+
className="ba-DrawingAnnotations-list"
|
|
104
|
+
onSelect={handleAnnotationActive}
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
{hasPathGroups && (
|
|
108
|
+
<DrawingSVG ref={setStagedRootEl} className="ba-DrawingAnnotations-target">
|
|
109
|
+
{/* Group element to capture the bounding box around the drawn path groups */}
|
|
110
|
+
<DrawingSVGGroup ref={stagedGroupRef} onMount={handleDrawingMount}>
|
|
111
|
+
{drawnPathGroups.map(({ clientId: pathGroupClientId, paths, stroke }) => (
|
|
112
|
+
<DrawingPathGroup key={pathGroupClientId} rootEl={stagedRootEl} stroke={stroke}>
|
|
113
|
+
{/* Use the children render function to pass down the calculated strokeWidthWithBorder value */}
|
|
114
|
+
{strokeWidthWithBorder =>
|
|
115
|
+
paths.map(({ clientId: pathClientId, points }) => (
|
|
116
|
+
<DecoratedDrawingPath
|
|
117
|
+
key={pathClientId}
|
|
118
|
+
borderStrokeWidth={strokeWidthWithBorder}
|
|
119
|
+
isDecorated
|
|
120
|
+
points={points}
|
|
121
|
+
/>
|
|
122
|
+
))
|
|
123
|
+
}
|
|
124
|
+
</DrawingPathGroup>
|
|
125
|
+
))}
|
|
126
|
+
</DrawingSVGGroup>
|
|
127
|
+
</DrawingSVG>
|
|
128
|
+
)}
|
|
129
|
+
|
|
130
|
+
{isCreating && (
|
|
131
|
+
<DrawingCreator
|
|
132
|
+
className="ba-DrawingAnnotations-creator"
|
|
133
|
+
color={color}
|
|
134
|
+
onStart={handleStart}
|
|
135
|
+
onStop={handleStop}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
|
|
139
|
+
{isCreating && hasPathGroups && drawingSVGGroup && canShowPopupToolbar && (
|
|
140
|
+
<PopupDrawingToolbar
|
|
141
|
+
ref={popupDrawingToolbarRef}
|
|
142
|
+
canComment={hasDrawnPathGroups}
|
|
143
|
+
canRedo={hasStashedPathGroups}
|
|
144
|
+
canUndo={hasDrawnPathGroups}
|
|
145
|
+
className={classNames('ba-DrawingAnnotations-toolbar', { 'ba-is-drawing': isDrawing })}
|
|
146
|
+
onDelete={handleDelete}
|
|
147
|
+
onRedo={handleRedo}
|
|
148
|
+
onReply={handleReply}
|
|
149
|
+
onUndo={handleUndo}
|
|
150
|
+
reference={drawingSVGGroup}
|
|
151
|
+
/>
|
|
152
|
+
)}
|
|
153
|
+
</>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export default DrawingAnnotations;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { connect } from 'react-redux';
|
|
2
|
+
import DrawingAnnotations from './DrawingAnnotations';
|
|
3
|
+
import withProviders from '../common/withProviders';
|
|
4
|
+
import {
|
|
5
|
+
addDrawingPathGroupAction,
|
|
6
|
+
getDrawingDrawnPathGroupsForLocation,
|
|
7
|
+
getStashedDrawnPathGroupsForLocation,
|
|
8
|
+
redoDrawingPathGroupAction,
|
|
9
|
+
resetDrawingAction,
|
|
10
|
+
undoDrawingPathGroupAction,
|
|
11
|
+
} from '../store/drawing';
|
|
12
|
+
import { AnnotationDrawing, PathGroup } from '../@types';
|
|
13
|
+
import {
|
|
14
|
+
AppState,
|
|
15
|
+
CreatorStatus,
|
|
16
|
+
getActiveAnnotationId,
|
|
17
|
+
getAnnotationMode,
|
|
18
|
+
getAnnotationsForLocation,
|
|
19
|
+
getColor,
|
|
20
|
+
getCreatorStatus,
|
|
21
|
+
Mode,
|
|
22
|
+
setActiveAnnotationIdAction,
|
|
23
|
+
setReferenceIdAction,
|
|
24
|
+
setStagedAction,
|
|
25
|
+
setStatusAction,
|
|
26
|
+
} from '../store';
|
|
27
|
+
import { isDrawing } from './drawingUtil';
|
|
28
|
+
import { setupDrawingAction } from './actions';
|
|
29
|
+
|
|
30
|
+
export type Props = {
|
|
31
|
+
activeAnnotationId: string | null;
|
|
32
|
+
annotations: AnnotationDrawing[];
|
|
33
|
+
color: string;
|
|
34
|
+
canShowPopupToolbar: boolean;
|
|
35
|
+
drawnPathGroups: Array<PathGroup>;
|
|
36
|
+
isCreating: boolean;
|
|
37
|
+
stashedPathGroups: Array<PathGroup>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const mapStateToProps = (state: AppState, { location }: { location: number }): Props => {
|
|
41
|
+
const creatorStatus = getCreatorStatus(state);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
activeAnnotationId: getActiveAnnotationId(state),
|
|
45
|
+
annotations: getAnnotationsForLocation(state, location).filter(isDrawing),
|
|
46
|
+
color: getColor(state),
|
|
47
|
+
canShowPopupToolbar: creatorStatus === CreatorStatus.started,
|
|
48
|
+
drawnPathGroups: getDrawingDrawnPathGroupsForLocation(state, location),
|
|
49
|
+
isCreating: getAnnotationMode(state) === Mode.DRAWING && creatorStatus !== CreatorStatus.pending,
|
|
50
|
+
stashedPathGroups: getStashedDrawnPathGroupsForLocation(state, location),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const mapDispatchToProps = {
|
|
55
|
+
addDrawingPathGroup: addDrawingPathGroupAction,
|
|
56
|
+
redoDrawingPathGroup: redoDrawingPathGroupAction,
|
|
57
|
+
resetDrawing: resetDrawingAction,
|
|
58
|
+
setActiveAnnotationId: setActiveAnnotationIdAction,
|
|
59
|
+
setReferenceId: setReferenceIdAction,
|
|
60
|
+
setStaged: setStagedAction,
|
|
61
|
+
setStatus: setStatusAction,
|
|
62
|
+
setupDrawing: setupDrawingAction,
|
|
63
|
+
undoDrawingPathGroup: undoDrawingPathGroupAction,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default connect(mapStateToProps, mapDispatchToProps)(withProviders(DrawingAnnotations));
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { bdlBoxBlue } from 'box-ui-elements/es/styles/variables';
|
|
4
|
+
import DrawingPath, { DrawingPathRef } from './DrawingPath';
|
|
5
|
+
import DrawingPathGroup from './DrawingPathGroup';
|
|
6
|
+
import DrawingSVG, { DrawingSVGRef } from './DrawingSVG';
|
|
7
|
+
import PointerCapture, { PointerCaptureRef, Status as DrawingStatus } from '../components/PointerCapture';
|
|
8
|
+
import { getDrawingCursor } from './DrawingCursor';
|
|
9
|
+
import { getPathCommands } from './drawingUtil';
|
|
10
|
+
import { PathGroup, Position } from '../@types';
|
|
11
|
+
import './DrawingCreator.scss';
|
|
12
|
+
|
|
13
|
+
export type Props = {
|
|
14
|
+
className?: string;
|
|
15
|
+
color?: string;
|
|
16
|
+
onStart: () => void;
|
|
17
|
+
onStop: (pathGroup: PathGroup) => void;
|
|
18
|
+
size?: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const defaultStrokeColor = bdlBoxBlue;
|
|
22
|
+
export const defaultStrokeSize = 4;
|
|
23
|
+
|
|
24
|
+
export default function DrawingCreator({
|
|
25
|
+
className,
|
|
26
|
+
color = defaultStrokeColor,
|
|
27
|
+
onStart,
|
|
28
|
+
onStop,
|
|
29
|
+
size = defaultStrokeSize,
|
|
30
|
+
}: Props): JSX.Element {
|
|
31
|
+
const [drawingStatus, setDrawingStatus] = React.useState<DrawingStatus>(DrawingStatus.init);
|
|
32
|
+
const capturedPointsRef = React.useRef<Array<Position>>([]);
|
|
33
|
+
const creatorElRef = React.useRef<PointerCaptureRef>(null);
|
|
34
|
+
const drawingDirtyRef = React.useRef<boolean>(false);
|
|
35
|
+
const drawingPathRef = React.useRef<DrawingPathRef>(null);
|
|
36
|
+
const drawingSVGRef = React.useRef<DrawingSVGRef>(null);
|
|
37
|
+
const renderHandleRef = React.useRef<number | null>(null);
|
|
38
|
+
const stroke = { color, size };
|
|
39
|
+
|
|
40
|
+
const getPoints = React.useCallback((): Array<Position> => {
|
|
41
|
+
const { current: creatorEl } = creatorElRef;
|
|
42
|
+
const { current: points } = capturedPointsRef;
|
|
43
|
+
|
|
44
|
+
if (!creatorEl || !points.length) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const { height, width } = creatorEl.getBoundingClientRect();
|
|
49
|
+
const { size: minSize } = stroke;
|
|
50
|
+
const MAX_X = width - minSize;
|
|
51
|
+
const MAX_Y = height - minSize;
|
|
52
|
+
|
|
53
|
+
return points.map(({ x, y }) => ({
|
|
54
|
+
x: (Math.min(MAX_X, Math.max(minSize, x)) / width) * 100,
|
|
55
|
+
y: (Math.min(MAX_Y, Math.max(minSize, y)) / height) * 100,
|
|
56
|
+
}));
|
|
57
|
+
}, [stroke]);
|
|
58
|
+
|
|
59
|
+
const getPosition = (x: number, y: number): [number, number] => {
|
|
60
|
+
const { current: creatorEl } = creatorElRef;
|
|
61
|
+
|
|
62
|
+
if (!creatorEl) {
|
|
63
|
+
return [x, y];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Calculate the new position based on the mouse position less the page offset
|
|
67
|
+
const { left, top } = creatorEl.getBoundingClientRect();
|
|
68
|
+
return [x - left, y - top];
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Drawing Lifecycle Callbacks
|
|
72
|
+
const startDraw = (x: number, y: number): void => {
|
|
73
|
+
const [x1, y1] = getPosition(x, y);
|
|
74
|
+
|
|
75
|
+
setDrawingStatus(DrawingStatus.dragging);
|
|
76
|
+
|
|
77
|
+
capturedPointsRef.current = [{ x: x1, y: y1 }];
|
|
78
|
+
drawingDirtyRef.current = true;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const stopDraw = React.useCallback((): void => {
|
|
82
|
+
const adjustedPoints = getPoints();
|
|
83
|
+
|
|
84
|
+
// If there is only one point in the points array, it is likely the user clicked
|
|
85
|
+
// instead of dragging a path so this is not considered a path group.
|
|
86
|
+
if (!adjustedPoints || adjustedPoints.length <= 1) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
setDrawingStatus(DrawingStatus.init);
|
|
91
|
+
|
|
92
|
+
capturedPointsRef.current = [];
|
|
93
|
+
drawingDirtyRef.current = true;
|
|
94
|
+
|
|
95
|
+
onStop({
|
|
96
|
+
paths: [{ points: adjustedPoints }],
|
|
97
|
+
stroke,
|
|
98
|
+
});
|
|
99
|
+
}, [getPoints, onStop, setDrawingStatus, stroke]);
|
|
100
|
+
|
|
101
|
+
const updateDraw = React.useCallback(
|
|
102
|
+
(x: number, y: number): void => {
|
|
103
|
+
const [x2, y2] = getPosition(x, y);
|
|
104
|
+
const { current: points } = capturedPointsRef;
|
|
105
|
+
|
|
106
|
+
points.push({ x: x2, y: y2 });
|
|
107
|
+
drawingDirtyRef.current = true;
|
|
108
|
+
|
|
109
|
+
if (drawingStatus !== DrawingStatus.drawing) {
|
|
110
|
+
setDrawingStatus(DrawingStatus.drawing);
|
|
111
|
+
onStart();
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
[drawingStatus, onStart, setDrawingStatus],
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Event Handlers
|
|
118
|
+
const renderStep = (callback: () => void): void => {
|
|
119
|
+
renderHandleRef.current = window.requestAnimationFrame(callback);
|
|
120
|
+
};
|
|
121
|
+
const renderPath = (): void => {
|
|
122
|
+
const { current: isDirty } = drawingDirtyRef;
|
|
123
|
+
const { current: svgPath } = drawingPathRef;
|
|
124
|
+
|
|
125
|
+
if (isDirty && svgPath) {
|
|
126
|
+
svgPath.setAttribute('d', getPathCommands(getPoints()));
|
|
127
|
+
|
|
128
|
+
drawingDirtyRef.current = false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
renderStep(renderPath);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
React.useEffect(() => {
|
|
135
|
+
if (drawingStatus !== DrawingStatus.init) {
|
|
136
|
+
renderStep(renderPath);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return () => {
|
|
140
|
+
const { current: renderHandle } = renderHandleRef;
|
|
141
|
+
|
|
142
|
+
// Cancel the render loop
|
|
143
|
+
if (renderHandle) {
|
|
144
|
+
window.cancelAnimationFrame(renderHandle);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}, [drawingStatus]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
148
|
+
|
|
149
|
+
React.useEffect(() => {
|
|
150
|
+
const { current: element } = creatorElRef;
|
|
151
|
+
|
|
152
|
+
if (!element) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Safari doesn't support continuous switching custom cursors
|
|
157
|
+
// So we do "custom -> crosshair -> custom" to solve it
|
|
158
|
+
// The UX is the same, since it's too fast to feel the switching
|
|
159
|
+
element.style.cursor = 'crosshair';
|
|
160
|
+
element.style.cursor = getDrawingCursor(color);
|
|
161
|
+
}, [color, creatorElRef]);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
|
|
165
|
+
<PointerCapture
|
|
166
|
+
ref={creatorElRef}
|
|
167
|
+
className={classNames(className, 'ba-DrawingCreator')}
|
|
168
|
+
data-testid="ba-DrawingCreator"
|
|
169
|
+
onDrawStart={startDraw}
|
|
170
|
+
onDrawStop={stopDraw}
|
|
171
|
+
onDrawUpdate={updateDraw}
|
|
172
|
+
status={drawingStatus}
|
|
173
|
+
>
|
|
174
|
+
{drawingStatus !== DrawingStatus.init && (
|
|
175
|
+
<DrawingSVG ref={drawingSVGRef} className="ba-DrawingCreator-current">
|
|
176
|
+
<DrawingPathGroup rootEl={drawingSVGRef.current} stroke={stroke}>
|
|
177
|
+
<DrawingPath ref={drawingPathRef} />
|
|
178
|
+
</DrawingPathGroup>
|
|
179
|
+
</DrawingSVG>
|
|
180
|
+
)}
|
|
181
|
+
</PointerCapture>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const getDrawingCursor = (color: string): string => {
|
|
2
|
+
const encodedSvg = encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='32' height='32' viewBox='0 0 32 32'>
|
|
3
|
+
<defs>
|
|
4
|
+
<path id='ba-DrawingCursor-b' d='M23.0868949,12.6610542 L21.7362465,14.0116939 C21.5985448,14.1493947 21.3758783,14.1493947 21.2381766,14.0116939 L17.9860729,10.7596114 C17.8483713,10.6219106 17.8483713,10.3992455 17.9860729,10.2615447 L19.3367214,8.91090502 C19.8845983,8.36303166 20.7752645,8.36303166 21.3260713,8.91090502 L23.0868949,10.6717173 C23.6377017,11.2195906 23.6377017,12.1102511 23.0868949,12.6610542 Z M16.825863,11.4217471 L9.13214756,19.1154126 L8.51102507,22.6751246 C8.4260602,23.1556124 8.8450249,23.5716446 9.32551588,23.4896101 L12.8852509,22.8655618 L20.5789664,15.1718963 C20.7166681,15.0341955 20.7166681,14.8115304 20.5789664,14.6738296 L17.3268627,11.4217471 C17.1862312,11.2840463 16.9635647,11.2840463 16.825863,11.4217471 Z M12.1352162,18.4562067 C11.974076,18.2950675 11.974076,18.0372447 12.1352162,17.8761055 L16.6471438,13.3642072 C16.8082841,13.203068 17.0661085,13.203068 17.2272488,13.3642072 C17.388389,13.5253464 17.388389,13.7831692 17.2272488,13.9443084 L12.7153212,18.4562067 C12.5541809,18.6173459 12.2963565,18.6173459 12.1352162,18.4562067 L12.1352162,18.4562067 Z M11.0775501,20.9201719 L12.4838652,20.9201719 L12.4838652,21.9836908 L10.5941293,22.3147587 L9.6829543,21.4035896 L10.0140243,19.513866 L11.0775501,19.513866 L11.0775501,20.9201719 Z'/>
|
|
5
|
+
<filter id='ba-DrawingCursor-a' width='196.7%' height='196.7%' x='-48.3%' y='-41.7%' filterUnits='objectBoundingBox'>
|
|
6
|
+
<feMorphology in='SourceAlpha' operator='dilate' radius='.75' result='shadowSpreadOuter1'/>
|
|
7
|
+
<feOffset dy='1' in='shadowSpreadOuter1' result='shadowOffsetOuter1'/>
|
|
8
|
+
<feGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='2'/>
|
|
9
|
+
<feComposite in='shadowBlurOuter1' in2='SourceAlpha' operator='out' result='shadowBlurOuter1'/>
|
|
10
|
+
<feColorMatrix in='shadowBlurOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24647618 0'/>
|
|
11
|
+
</filter>
|
|
12
|
+
</defs>
|
|
13
|
+
<g fill='none' stroke-linejoin='round'>
|
|
14
|
+
<use fill='#000' filter='url(#ba-DrawingCursor-a)' xlink:href='#ba-DrawingCursor-b'/>
|
|
15
|
+
<path fill='${color}' fill-rule='evenodd' stroke='#FFF' stroke-width='.75' d='M16.8075762,10.9097054 L21.119532,14.6460363 L13.0730631,23.2133559 L9.38862666,23.8592613 C9.02061417,23.9220923 8.67630709,23.7937251 8.44046,23.5578795 C8.23387707,23.3512979 8.11025348,23.0623685 8.12610763,22.7471873 L8.14160649,22.6106659 L8.78311611,18.9341134 L16.8075762,10.9097054 Z M10.3290377,19.888866 L10.0859707,21.276275 L10.7214427,21.9117429 L12.1088652,21.6686767 L12.1088652,21.2951719 L10.7025501,21.2951719 L10.3290377,19.888866 Z M16.912308,13.6293731 L12.4003804,18.1412714 L12.3922785,18.1528739 L12.3922785,18.1528739 L12.389361,18.1661561 C12.389361,18.1753081 12.3934679,18.1841284 12.4003804,18.1910408 C12.4072938,18.1979542 12.4161155,18.2020611 12.4252687,18.2020611 C12.4344219,18.2020611 12.4432436,18.1979542 12.450157,18.1910408 L12.450157,18.1910408 L16.9620846,13.6791425 L16.9701864,13.66754 L16.9701864,13.66754 L16.973104,13.6542578 C16.973104,13.6384287 16.9537538,13.6286304 16.912308,13.6293731 L16.912308,13.6293731 Z M20.3302976,8.125 C20.7859086,8.125 21.2419828,8.29834457 21.5912354,8.64573912 L21.5912354,8.64573912 L23.3513511,10.4058452 C23.7004504,10.7530854 23.875,11.2089541 23.875,11.6652871 C23.875,12.1211084 23.7008005,12.577481 23.3520591,12.9262201 L23.3520591,12.9262201 L21.7544376,14.5238313 L17.4797801,10.8169258 L19.0500461,8.66761683 C19.3996549,8.30599451 19.8646885,8.125 20.3302976,8.125 Z'/>
|
|
16
|
+
</g>
|
|
17
|
+
</svg>`);
|
|
18
|
+
|
|
19
|
+
// x-offset is 6, y-offset is 22, fallback cursor is crosshair
|
|
20
|
+
return `url("data:image/svg+xml,${encodedSvg}") 6 22, crosshair`;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { getDrawingCursor };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import noop from 'lodash/noop';
|
|
4
|
+
import DrawingSVG, { DrawingSVGRef } from './DrawingSVG';
|
|
5
|
+
import DrawingTarget from './DrawingTarget';
|
|
6
|
+
import useIsListInteractive from '../common/useIsListInteractive';
|
|
7
|
+
import { AnnotationDrawing } from '../@types';
|
|
8
|
+
import { checkValue } from '../utils/util';
|
|
9
|
+
import { getShape } from './drawingUtil';
|
|
10
|
+
|
|
11
|
+
export type Props = {
|
|
12
|
+
activeId?: string | null;
|
|
13
|
+
annotations: AnnotationDrawing[];
|
|
14
|
+
className?: string;
|
|
15
|
+
onSelect?: (annotationId: string | null) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function filterDrawing({ target: { path_groups: pathGroups } }: AnnotationDrawing): boolean {
|
|
19
|
+
return pathGroups.every(({ paths }) =>
|
|
20
|
+
paths.every(({ points }) => points.every(({ x, y }) => checkValue(x) && checkValue(y))),
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function sortDrawing({ target: targetA }: AnnotationDrawing, { target: targetB }: AnnotationDrawing): number {
|
|
25
|
+
const { height: heightA, width: widthA } = getShape(targetA.path_groups);
|
|
26
|
+
const { height: heightB, width: widthB } = getShape(targetB.path_groups);
|
|
27
|
+
|
|
28
|
+
// If B is smaller, the result is negative.
|
|
29
|
+
// So, A is sorted to an index lower than B, which means A will be rendered first at bottom
|
|
30
|
+
return heightB * widthB - heightA * widthA;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function DrawingList({ activeId = null, annotations, className, onSelect = noop }: Props): JSX.Element {
|
|
34
|
+
const [rootEl, setRootEl] = React.useState<DrawingSVGRef | null>(null);
|
|
35
|
+
const isListening = useIsListInteractive();
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<DrawingSVG
|
|
39
|
+
ref={setRootEl}
|
|
40
|
+
className={classNames(className, { 'is-listening': isListening })}
|
|
41
|
+
data-resin-component="drawingList"
|
|
42
|
+
>
|
|
43
|
+
{annotations
|
|
44
|
+
.filter(filterDrawing)
|
|
45
|
+
.sort(sortDrawing)
|
|
46
|
+
.map(({ id, target }) => (
|
|
47
|
+
<DrawingTarget
|
|
48
|
+
key={id}
|
|
49
|
+
annotationId={id}
|
|
50
|
+
isActive={activeId === id}
|
|
51
|
+
onSelect={onSelect}
|
|
52
|
+
rootEl={rootEl}
|
|
53
|
+
target={target}
|
|
54
|
+
/>
|
|
55
|
+
))}
|
|
56
|
+
</DrawingSVG>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default React.memo(DrawingList);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as ReactDOM from 'react-dom';
|
|
3
|
+
import BaseManager, { Props } from '../common/BaseManager';
|
|
4
|
+
import DrawingAnnotationsContainer from './DrawingAnnotationsContainer';
|
|
5
|
+
|
|
6
|
+
export default class DrawingListManager extends BaseManager {
|
|
7
|
+
decorate(): void {
|
|
8
|
+
this.reactEl.classList.add('ba-Layer--drawing');
|
|
9
|
+
this.reactEl.dataset.testid = 'ba-Layer--drawing';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
render(props: Props): void {
|
|
13
|
+
ReactDOM.render(<DrawingAnnotationsContainer location={this.location} {...props} />, this.reactEl);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export type Props = React.SVGProps<DrawingPathRef> & {
|
|
4
|
+
pathCommands?: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type DrawingPathRef = SVGPathElement;
|
|
8
|
+
|
|
9
|
+
const DrawingPath = (props: Props, ref: React.Ref<SVGPathElement>): JSX.Element => {
|
|
10
|
+
const { pathCommands, ...rest } = props;
|
|
11
|
+
|
|
12
|
+
return <path ref={ref} d={pathCommands} strokeLinecap="round" vectorEffect="non-scaling-stroke" {...rest} />;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { DrawingPath as DrawingPathBase };
|
|
16
|
+
|
|
17
|
+
export default React.forwardRef(DrawingPath);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { DrawingSVGRef } from './DrawingSVG';
|
|
4
|
+
import { isVectorEffectSupported } from './drawingUtil';
|
|
5
|
+
import { Stroke } from '../@types';
|
|
6
|
+
|
|
7
|
+
export type ChildrenRenderFunction = (strokeWidthWithBorder: number) => React.ReactNode;
|
|
8
|
+
|
|
9
|
+
export type Props = {
|
|
10
|
+
children?: React.ReactNode | ChildrenRenderFunction;
|
|
11
|
+
isActive?: boolean;
|
|
12
|
+
rootEl: DrawingSVGRef | null;
|
|
13
|
+
stroke: Stroke;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const DRAWING_BORDER_WIDTH = 1;
|
|
17
|
+
|
|
18
|
+
export const DrawingPathGroup = ({
|
|
19
|
+
children,
|
|
20
|
+
isActive = false,
|
|
21
|
+
rootEl,
|
|
22
|
+
stroke: { color, size },
|
|
23
|
+
}: Props): JSX.Element => {
|
|
24
|
+
let strokeWidth = size;
|
|
25
|
+
// A line has two sides and each side needs a border, so add DRAWING_BORDER_WIDTH * 2
|
|
26
|
+
let strokeWidthWithBorder = strokeWidth + DRAWING_BORDER_WIDTH * 2;
|
|
27
|
+
|
|
28
|
+
// "vector-effect: non-scaling-stroke" prevents stroke width to be scaled
|
|
29
|
+
// However, IE/Edge doesn't support it, so we have to manually inverse scale the stroke width
|
|
30
|
+
if (!isVectorEffectSupported()) {
|
|
31
|
+
if (!rootEl) {
|
|
32
|
+
return <g className="ba-DrawingPathGroup" />;
|
|
33
|
+
}
|
|
34
|
+
const { clientWidth } = rootEl;
|
|
35
|
+
const scale = clientWidth / 100; // SVG viewbox is 100 * 100
|
|
36
|
+
strokeWidth /= scale;
|
|
37
|
+
strokeWidthWithBorder /= scale;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<g
|
|
42
|
+
className={classNames('ba-DrawingPathGroup', { 'is-active': isActive })}
|
|
43
|
+
fill="transparent"
|
|
44
|
+
stroke={color}
|
|
45
|
+
strokeWidth={strokeWidth}
|
|
46
|
+
>
|
|
47
|
+
{typeof children === 'function' ? children(strokeWidthWithBorder) : children}
|
|
48
|
+
</g>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default DrawingPathGroup;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import * as uuid from 'uuid';
|
|
4
|
+
import SVGFilterContext from './SVGFilterContext';
|
|
5
|
+
|
|
6
|
+
export type Props = {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type DrawingSVGRef = SVGSVGElement;
|
|
12
|
+
|
|
13
|
+
export function DrawingSVG({ className, children, ...rest }: Props, ref: React.Ref<DrawingSVGRef>): JSX.Element {
|
|
14
|
+
const { current: filterID } = React.useRef(`ba-DrawingSVG-shadow_${uuid.v4()}`);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<svg
|
|
18
|
+
ref={ref}
|
|
19
|
+
className={classNames('ba-DrawingSVG', className)}
|
|
20
|
+
preserveAspectRatio="none"
|
|
21
|
+
viewBox="0 0 100 100"
|
|
22
|
+
{...rest}
|
|
23
|
+
>
|
|
24
|
+
<defs>
|
|
25
|
+
<filter filterUnits="userSpaceOnUse" id={filterID}>
|
|
26
|
+
<feGaussianBlur in="SourceGraphic" stdDeviation="1" />
|
|
27
|
+
</filter>
|
|
28
|
+
</defs>
|
|
29
|
+
<SVGFilterContext.Provider value={filterID}>{children}</SVGFilterContext.Provider>
|
|
30
|
+
</svg>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default React.forwardRef(DrawingSVG);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import noop from 'lodash/noop';
|
|
3
|
+
import useMountId from '../common/useMountId';
|
|
4
|
+
|
|
5
|
+
export type Props = React.SVGAttributes<SVGGElement> & {
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
onMount?: (uuid: string) => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type DrawingSVGGroup = SVGGElement;
|
|
11
|
+
|
|
12
|
+
export function DrawingSVGGroup(props: Props, ref: React.Ref<DrawingSVGGroup>): JSX.Element {
|
|
13
|
+
const { children, onMount = noop, ...rest } = props;
|
|
14
|
+
const uuid = useMountId(onMount);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<g ref={ref} data-ba-reference-id={uuid} {...rest}>
|
|
18
|
+
{children}
|
|
19
|
+
</g>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default React.forwardRef(DrawingSVGGroup);
|