@atlaskit/renderer 115.0.2 → 115.0.4
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/CHANGELOG.md +16 -0
- package/dist/cjs/ui/Renderer/index.js +1 -1
- package/dist/cjs/ui/annotations/contexts/AnnotationManagerContext.js +421 -0
- package/dist/cjs/ui/annotations/draft/component.js +13 -1
- package/dist/cjs/ui/annotations/element/index.js +38 -6
- package/dist/cjs/ui/annotations/element/mark.js +16 -0
- package/dist/cjs/ui/annotations/hooks/use-events.js +77 -27
- package/dist/cjs/ui/annotations/hooks/use-load-annotations.js +18 -2
- package/dist/cjs/ui/annotations/index.js +49 -12
- package/dist/cjs/ui/annotations/selection/mounter.js +177 -4
- package/dist/es2019/ui/Renderer/index.js +1 -1
- package/dist/es2019/ui/annotations/contexts/AnnotationManagerContext.js +416 -0
- package/dist/es2019/ui/annotations/draft/component.js +15 -3
- package/dist/es2019/ui/annotations/element/index.js +39 -6
- package/dist/es2019/ui/annotations/element/mark.js +18 -0
- package/dist/es2019/ui/annotations/hooks/use-events.js +85 -28
- package/dist/es2019/ui/annotations/hooks/use-load-annotations.js +19 -2
- package/dist/es2019/ui/annotations/index.js +47 -10
- package/dist/es2019/ui/annotations/selection/mounter.js +177 -6
- package/dist/esm/ui/Renderer/index.js +1 -1
- package/dist/esm/ui/annotations/contexts/AnnotationManagerContext.js +411 -0
- package/dist/esm/ui/annotations/draft/component.js +14 -3
- package/dist/esm/ui/annotations/element/index.js +38 -6
- package/dist/esm/ui/annotations/element/mark.js +16 -0
- package/dist/esm/ui/annotations/hooks/use-events.js +78 -28
- package/dist/esm/ui/annotations/hooks/use-load-annotations.js +18 -2
- package/dist/esm/ui/annotations/index.js +45 -10
- package/dist/esm/ui/annotations/selection/mounter.js +179 -6
- package/dist/types/ui/annotations/contexts/AnnotationManagerContext.d.ts +71 -0
- package/dist/types/ui/annotations/draft/component.d.ts +5 -1
- package/dist/types/ui/annotations/element/mark.d.ts +6 -0
- package/dist/types/ui/annotations/index.d.ts +1 -0
- package/dist/types-ts4.5/ui/annotations/contexts/AnnotationManagerContext.d.ts +71 -0
- package/dist/types-ts4.5/ui/annotations/draft/component.d.ts +5 -1
- package/dist/types-ts4.5/ui/annotations/element/mark.d.ts +6 -0
- package/dist/types-ts4.5/ui/annotations/index.d.ts +1 -0
- package/package.json +13 -5
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import React, { createContext, useContext, useEffect, useMemo, useReducer } from 'react';
|
|
2
|
+
import { AnnotationMarkStates, AnnotationTypes } from '@atlaskit/adf-schema';
|
|
3
|
+
import { AnnotationUpdateEvent } from '@atlaskit/editor-common/types';
|
|
4
|
+
const initState = {
|
|
5
|
+
isDrafting: false,
|
|
6
|
+
draftId: undefined,
|
|
7
|
+
draftMarkRef: undefined,
|
|
8
|
+
draftActionResult: undefined,
|
|
9
|
+
annotations: {},
|
|
10
|
+
currentSelectedAnnotationId: undefined,
|
|
11
|
+
currentSelectedMarkRef: undefined,
|
|
12
|
+
currentHoveredAnnotationId: undefined
|
|
13
|
+
};
|
|
14
|
+
const AnnotationManagerStateContext = /*#__PURE__*/createContext(initState);
|
|
15
|
+
const AnnotationManagerDispatchContext = /*#__PURE__*/createContext({
|
|
16
|
+
annotationManager: undefined,
|
|
17
|
+
dispatch: () => {}
|
|
18
|
+
});
|
|
19
|
+
function reducer(state, action) {
|
|
20
|
+
switch (action.type) {
|
|
21
|
+
case 'reset':
|
|
22
|
+
{
|
|
23
|
+
return {
|
|
24
|
+
...state,
|
|
25
|
+
...initState
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
case 'loadAnnotation':
|
|
29
|
+
{
|
|
30
|
+
const currentIds = Object.keys(state.annotations);
|
|
31
|
+
const uids = Array.from(new Set(currentIds.concat(action.data.map(a => a.id))));
|
|
32
|
+
const updates = [];
|
|
33
|
+
for (const id of uids) {
|
|
34
|
+
var _state$annotations$id, _state$annotations$id2;
|
|
35
|
+
const loadedAnnotation = action.data.find(a => a.id === id);
|
|
36
|
+
if (!loadedAnnotation && ((_state$annotations$id = state.annotations[id]) === null || _state$annotations$id === void 0 ? void 0 : _state$annotations$id.markState) === AnnotationMarkStates.ACTIVE) {
|
|
37
|
+
// If the annotation is not in the loaded data, we need to remove it from the state. However,
|
|
38
|
+
// rather then removing it, we will set the mark state to resolved. This is to align it better with
|
|
39
|
+
// how the editor works.
|
|
40
|
+
updates.push({
|
|
41
|
+
id,
|
|
42
|
+
markState: AnnotationMarkStates.RESOLVED
|
|
43
|
+
});
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (!!(loadedAnnotation !== null && loadedAnnotation !== void 0 && loadedAnnotation.markState) && ((_state$annotations$id2 = state.annotations[id]) === null || _state$annotations$id2 === void 0 ? void 0 : _state$annotations$id2.markState) !== loadedAnnotation.markState) {
|
|
47
|
+
updates.push({
|
|
48
|
+
id,
|
|
49
|
+
markState: loadedAnnotation.markState
|
|
50
|
+
});
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (updates.length > 0) {
|
|
55
|
+
return {
|
|
56
|
+
...state,
|
|
57
|
+
annotations: updates.reduce((nextAnnotations, update) => {
|
|
58
|
+
return {
|
|
59
|
+
...nextAnnotations,
|
|
60
|
+
[update.id]: {
|
|
61
|
+
...nextAnnotations[update.id],
|
|
62
|
+
...update
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}, state.annotations)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return state;
|
|
69
|
+
}
|
|
70
|
+
case 'updateAnnotation':
|
|
71
|
+
{
|
|
72
|
+
const current = state.annotations[action.data.id];
|
|
73
|
+
const {
|
|
74
|
+
id,
|
|
75
|
+
selected,
|
|
76
|
+
hovered,
|
|
77
|
+
markState = current === null || current === void 0 ? void 0 : current.markState
|
|
78
|
+
} = action.data;
|
|
79
|
+
const updates = [];
|
|
80
|
+
|
|
81
|
+
// If the annotation is not currently in the state, we need to add it to the state.
|
|
82
|
+
if (!current) {
|
|
83
|
+
updates.push({
|
|
84
|
+
id,
|
|
85
|
+
markState: markState !== null && markState !== void 0 ? markState : AnnotationMarkStates.ACTIVE
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// The goal of the following is to enforce a single selection and a single hover state across all annotations.
|
|
90
|
+
let nextSelectedId = state.currentSelectedAnnotationId;
|
|
91
|
+
if (selected && nextSelectedId !== id) {
|
|
92
|
+
nextSelectedId = id;
|
|
93
|
+
}
|
|
94
|
+
// If the annotation is currently selected and it's being unselected, we need to remove it from the
|
|
95
|
+
// current selected annotation id.
|
|
96
|
+
if (selected === false && nextSelectedId === id) {
|
|
97
|
+
nextSelectedId = undefined;
|
|
98
|
+
}
|
|
99
|
+
let nextHoveredId = state.currentHoveredAnnotationId;
|
|
100
|
+
if (hovered && nextHoveredId !== id) {
|
|
101
|
+
nextHoveredId = id;
|
|
102
|
+
}
|
|
103
|
+
// If the annotation is currently hovered and it's being unhovered, we need to remove it from the
|
|
104
|
+
// current hovered annotation id.
|
|
105
|
+
if (hovered === false && nextHoveredId === id) {
|
|
106
|
+
nextHoveredId = undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// If the annotations mark state is not the same as the current mark state, we need to update it.
|
|
110
|
+
if ((current === null || current === void 0 ? void 0 : current.markState) !== markState) {
|
|
111
|
+
updates.push({
|
|
112
|
+
id,
|
|
113
|
+
markState: markState !== null && markState !== void 0 ? markState : AnnotationMarkStates.ACTIVE
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// If the annotation is currently selected and it's being resolved, then we need to remove it from the
|
|
117
|
+
// current selected annotation id also.
|
|
118
|
+
if (markState === AnnotationMarkStates.RESOLVED && nextSelectedId === id) {
|
|
119
|
+
nextSelectedId = undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (updates.length > 0 || nextSelectedId !== state.currentSelectedAnnotationId || nextHoveredId !== state.currentHoveredAnnotationId) {
|
|
123
|
+
return {
|
|
124
|
+
...state,
|
|
125
|
+
currentSelectedAnnotationId: nextSelectedId,
|
|
126
|
+
currentHoveredAnnotationId: nextHoveredId,
|
|
127
|
+
annotations: updates.reduce((nextAnnotations, update) => {
|
|
128
|
+
return {
|
|
129
|
+
...nextAnnotations,
|
|
130
|
+
[update.id]: {
|
|
131
|
+
...nextAnnotations[update.id],
|
|
132
|
+
...update
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}, state.annotations)
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return state;
|
|
139
|
+
}
|
|
140
|
+
case 'resetSelectedAnnotation':
|
|
141
|
+
{
|
|
142
|
+
if (state.currentSelectedAnnotationId !== undefined) {
|
|
143
|
+
return {
|
|
144
|
+
...state,
|
|
145
|
+
currentSelectedAnnotationId: undefined,
|
|
146
|
+
currentSelectedMarkRef: undefined
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return state;
|
|
150
|
+
}
|
|
151
|
+
case 'resetHoveredAnnotation':
|
|
152
|
+
{
|
|
153
|
+
if (state.currentHoveredAnnotationId !== undefined) {
|
|
154
|
+
return {
|
|
155
|
+
...state,
|
|
156
|
+
currentHoveredAnnotationId: undefined
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return state;
|
|
160
|
+
}
|
|
161
|
+
case 'setDrafting':
|
|
162
|
+
{
|
|
163
|
+
if (state.isDrafting !== action.data.isDrafting || state.draftId !== action.data.draftId || state.draftActionResult !== action.data.draftActionResult) {
|
|
164
|
+
// XXX: When a draft is open the current selected annotation should no longer be selected. We need
|
|
165
|
+
// to decide what is better UX,
|
|
166
|
+
// 1 - do we want to deselct the selected annotation on draft open, if so then when draft is closed the s
|
|
167
|
+
// selected annotation will not come back
|
|
168
|
+
// 2 - do we want to still allow the selected annotation to be selected when draft is open, however the underlying
|
|
169
|
+
// mark style just shows the annotation as not selected when a draft is active. Then when a draft closes
|
|
170
|
+
// we can reopen the previous selected annotation.
|
|
171
|
+
return {
|
|
172
|
+
...state,
|
|
173
|
+
isDrafting: action.data.isDrafting,
|
|
174
|
+
draftId: action.data.draftId,
|
|
175
|
+
draftActionResult: action.data.draftActionResult
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return state;
|
|
179
|
+
}
|
|
180
|
+
case 'setDraftMarkRef':
|
|
181
|
+
{
|
|
182
|
+
if (state.draftMarkRef !== action.data.draftMarkRef) {
|
|
183
|
+
return {
|
|
184
|
+
...state,
|
|
185
|
+
draftMarkRef: action.data.draftMarkRef
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return state;
|
|
189
|
+
}
|
|
190
|
+
case 'setSelectedMarkRef':
|
|
191
|
+
{
|
|
192
|
+
if (state.currentSelectedMarkRef !== action.data.markRef) {
|
|
193
|
+
return {
|
|
194
|
+
...state,
|
|
195
|
+
currentSelectedMarkRef: action.data.markRef
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return state;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
export const AnnotationManagerProvider = ({
|
|
203
|
+
children,
|
|
204
|
+
annotationManager,
|
|
205
|
+
updateSubscriber
|
|
206
|
+
}) => {
|
|
207
|
+
const [state, dispatch] = useReducer(reducer, initState);
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
const getDraft = () => {
|
|
210
|
+
var _state$draftActionRes;
|
|
211
|
+
if (!state.isDrafting || !state.draftActionResult || !state.draftMarkRef || !state.draftId) {
|
|
212
|
+
return {
|
|
213
|
+
success: false,
|
|
214
|
+
reason: 'draft-not-started'
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
success: true,
|
|
219
|
+
inlineNodeTypes: (_state$draftActionRes = state.draftActionResult.inlineNodeTypes) !== null && _state$draftActionRes !== void 0 ? _state$draftActionRes : [],
|
|
220
|
+
targetElement: state.draftMarkRef,
|
|
221
|
+
actionResult: {
|
|
222
|
+
step: state.draftActionResult.step,
|
|
223
|
+
doc: state.draftActionResult.doc,
|
|
224
|
+
inlineNodeTypes: state.draftActionResult.inlineNodeTypes,
|
|
225
|
+
targetNodeType: state.draftActionResult.targetNodeType,
|
|
226
|
+
originalSelection: state.draftActionResult.originalSelection,
|
|
227
|
+
numMatches: state.draftActionResult.numMatches,
|
|
228
|
+
matchIndex: state.draftActionResult.matchIndex,
|
|
229
|
+
pos: state.draftActionResult.pos
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
annotationManager === null || annotationManager === void 0 ? void 0 : annotationManager.hook('getDraft', getDraft);
|
|
234
|
+
return () => {
|
|
235
|
+
annotationManager === null || annotationManager === void 0 ? void 0 : annotationManager.unhook('getDraft', getDraft);
|
|
236
|
+
};
|
|
237
|
+
}, [annotationManager, state.draftId, state.isDrafting, state.draftMarkRef, state.draftActionResult]);
|
|
238
|
+
|
|
239
|
+
// We need to watch for the draft mark element to exist, so we can inform any listeners that the draft has been started
|
|
240
|
+
// and give them a reference to the element
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
if (state.isDrafting && state.draftId && state.draftMarkRef && state.draftActionResult) {
|
|
243
|
+
var _state$draftActionRes2;
|
|
244
|
+
annotationManager === null || annotationManager === void 0 ? void 0 : annotationManager.emit({
|
|
245
|
+
name: 'draftAnnotationStarted',
|
|
246
|
+
data: {
|
|
247
|
+
inlineNodeTypes: (_state$draftActionRes2 = state.draftActionResult.inlineNodeTypes) !== null && _state$draftActionRes2 !== void 0 ? _state$draftActionRes2 : [],
|
|
248
|
+
targetElement: state.draftMarkRef,
|
|
249
|
+
actionResult: {
|
|
250
|
+
step: state.draftActionResult.step,
|
|
251
|
+
doc: state.draftActionResult.doc,
|
|
252
|
+
inlineNodeTypes: state.draftActionResult.inlineNodeTypes,
|
|
253
|
+
targetNodeType: state.draftActionResult.targetNodeType,
|
|
254
|
+
originalSelection: state.draftActionResult.originalSelection,
|
|
255
|
+
numMatches: state.draftActionResult.numMatches,
|
|
256
|
+
matchIndex: state.draftActionResult.matchIndex,
|
|
257
|
+
pos: state.draftActionResult.pos
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}, [annotationManager, state.draftId, state.isDrafting, state.draftMarkRef, state.draftActionResult]);
|
|
263
|
+
|
|
264
|
+
// useEffect(() => {
|
|
265
|
+
// const setIsAnnotationSelected = (id: AnnotationId, isSelected: boolean): SelectAnnotationResult => {
|
|
266
|
+
// if (!state.annotations?.[id]) {
|
|
267
|
+
// return {
|
|
268
|
+
// success: false,
|
|
269
|
+
// reason: 'id-not-valid',
|
|
270
|
+
// };
|
|
271
|
+
// }
|
|
272
|
+
|
|
273
|
+
// dispatch({
|
|
274
|
+
// type: 'updateAnnotation',
|
|
275
|
+
// data: {
|
|
276
|
+
// id,
|
|
277
|
+
// selected: isSelected,
|
|
278
|
+
// },
|
|
279
|
+
// })
|
|
280
|
+
|
|
281
|
+
// return {
|
|
282
|
+
// success: true,
|
|
283
|
+
// isSelected,
|
|
284
|
+
// };
|
|
285
|
+
// };
|
|
286
|
+
|
|
287
|
+
// annotationManager?.hook('setIsAnnotationSelected', setIsAnnotationSelected);
|
|
288
|
+
// return () => {
|
|
289
|
+
// annotationManager?.unhook('setIsAnnotationSelected', setIsAnnotationSelected);
|
|
290
|
+
// };
|
|
291
|
+
// }, [state.annotations]);
|
|
292
|
+
|
|
293
|
+
// useEffect(() => {
|
|
294
|
+
// console.log('annotationsSelectedChanged', state.annotationsSelectedChanged);
|
|
295
|
+
|
|
296
|
+
// // if (state.isDrafting && state.currentDraftId && state.draftMarkRef) {
|
|
297
|
+
// // annotationManager?.emit({
|
|
298
|
+
// // name: 'annotationSelectionChanged',
|
|
299
|
+
// // data: {
|
|
300
|
+
// // annotationId: state.currentDraftId,
|
|
301
|
+
// // inlineNodeTypes: [],
|
|
302
|
+
// // isSelected: true,
|
|
303
|
+
// // },
|
|
304
|
+
// // });
|
|
305
|
+
// // }
|
|
306
|
+
// }, [annotationManager, state.annotationsSelectedChanged]);
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* This is a temporary solution to ensure that the annotation manager state is in sync with the
|
|
310
|
+
* old updateSubscriber. The updateSubscriber will eventually be deprecated and the state will be managed
|
|
311
|
+
* by the annotation manager itself.
|
|
312
|
+
*/
|
|
313
|
+
useEffect(() => {
|
|
314
|
+
const onSetAnnotationState = payload => {
|
|
315
|
+
if (!payload) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
Object.values(payload).forEach(annotation => {
|
|
319
|
+
if (annotation.id && annotation.annotationType === AnnotationTypes.INLINE_COMMENT && !annotation.state) {
|
|
320
|
+
var _annotation$state;
|
|
321
|
+
dispatch({
|
|
322
|
+
type: 'updateAnnotation',
|
|
323
|
+
data: {
|
|
324
|
+
id: annotation.id,
|
|
325
|
+
markState: (_annotation$state = annotation.state) !== null && _annotation$state !== void 0 ? _annotation$state : undefined
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
const onAnnotationSelected = payload => {
|
|
332
|
+
dispatch({
|
|
333
|
+
type: 'updateAnnotation',
|
|
334
|
+
data: {
|
|
335
|
+
id: payload.annotationId,
|
|
336
|
+
selected: true
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
};
|
|
340
|
+
const onAnnotationHovered = payload => {
|
|
341
|
+
dispatch({
|
|
342
|
+
type: 'updateAnnotation',
|
|
343
|
+
data: {
|
|
344
|
+
id: payload.annotationId,
|
|
345
|
+
hovered: true
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
const onAnnotationSelectedRemoved = () => {
|
|
350
|
+
dispatch({
|
|
351
|
+
type: 'resetSelectedAnnotation'
|
|
352
|
+
});
|
|
353
|
+
};
|
|
354
|
+
const onAnnotationHoveredRemoved = () => {
|
|
355
|
+
dispatch({
|
|
356
|
+
type: 'resetHoveredAnnotation'
|
|
357
|
+
});
|
|
358
|
+
};
|
|
359
|
+
const onAnnotationClick = ({
|
|
360
|
+
annotationIds,
|
|
361
|
+
eventTarget,
|
|
362
|
+
eventTargetType,
|
|
363
|
+
viewMethod
|
|
364
|
+
}) => {
|
|
365
|
+
dispatch({
|
|
366
|
+
type: 'updateAnnotation',
|
|
367
|
+
data: {
|
|
368
|
+
id: annotationIds[0],
|
|
369
|
+
selected: true
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
dispatch({
|
|
373
|
+
type: 'setSelectedMarkRef',
|
|
374
|
+
data: {
|
|
375
|
+
markRef: eventTarget
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
};
|
|
379
|
+
const onAnnotationDeselect = () => {
|
|
380
|
+
dispatch({
|
|
381
|
+
type: 'resetSelectedAnnotation'
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.on(AnnotationUpdateEvent.SET_ANNOTATION_STATE, onSetAnnotationState);
|
|
385
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.on(AnnotationUpdateEvent.SET_ANNOTATION_FOCUS, onAnnotationSelected);
|
|
386
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.on(AnnotationUpdateEvent.SET_ANNOTATION_HOVERED, onAnnotationHovered);
|
|
387
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.on(AnnotationUpdateEvent.REMOVE_ANNOTATION_FOCUS, onAnnotationSelectedRemoved);
|
|
388
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.on(AnnotationUpdateEvent.REMOVE_ANNOTATION_HOVERED, onAnnotationHoveredRemoved);
|
|
389
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.on(AnnotationUpdateEvent.ON_ANNOTATION_CLICK, onAnnotationClick);
|
|
390
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.on(AnnotationUpdateEvent.DESELECT_ANNOTATIONS, onAnnotationDeselect);
|
|
391
|
+
return () => {
|
|
392
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.off(AnnotationUpdateEvent.SET_ANNOTATION_STATE, onSetAnnotationState);
|
|
393
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.off(AnnotationUpdateEvent.SET_ANNOTATION_FOCUS, onAnnotationSelected);
|
|
394
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.off(AnnotationUpdateEvent.SET_ANNOTATION_HOVERED, onAnnotationHovered);
|
|
395
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.off(AnnotationUpdateEvent.REMOVE_ANNOTATION_FOCUS, onAnnotationSelectedRemoved);
|
|
396
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.off(AnnotationUpdateEvent.REMOVE_ANNOTATION_HOVERED, onAnnotationHoveredRemoved);
|
|
397
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.off(AnnotationUpdateEvent.ON_ANNOTATION_CLICK, onAnnotationClick);
|
|
398
|
+
updateSubscriber === null || updateSubscriber === void 0 ? void 0 : updateSubscriber.off(AnnotationUpdateEvent.DESELECT_ANNOTATIONS, onAnnotationDeselect);
|
|
399
|
+
};
|
|
400
|
+
}, [updateSubscriber]);
|
|
401
|
+
const dispatchData = useMemo(() => ({
|
|
402
|
+
annotationManager,
|
|
403
|
+
dispatch
|
|
404
|
+
}), [annotationManager, dispatch]);
|
|
405
|
+
return /*#__PURE__*/React.createElement(AnnotationManagerStateContext.Provider, {
|
|
406
|
+
value: state
|
|
407
|
+
}, /*#__PURE__*/React.createElement(AnnotationManagerDispatchContext.Provider, {
|
|
408
|
+
value: dispatchData
|
|
409
|
+
}, children));
|
|
410
|
+
};
|
|
411
|
+
export const useAnnotationManagerState = () => {
|
|
412
|
+
return useContext(AnnotationManagerStateContext);
|
|
413
|
+
};
|
|
414
|
+
export const useAnnotationManagerDispatch = () => {
|
|
415
|
+
return useContext(AnnotationManagerDispatchContext);
|
|
416
|
+
};
|
|
@@ -3,8 +3,7 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
3
3
|
* @jsxRuntime classic
|
|
4
4
|
* @jsx jsx
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import React, { Fragment } from 'react';
|
|
6
|
+
import React, { Fragment, useCallback } from 'react';
|
|
8
7
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
9
8
|
import { css, jsx } from '@emotion/react';
|
|
10
9
|
import { InsertDraftPosition } from '../types';
|
|
@@ -14,6 +13,7 @@ import { calcInsertDraftPositionOnText } from './position';
|
|
|
14
13
|
import { dataAttributes } from './dom';
|
|
15
14
|
import { segmentText } from '../../../react/utils/segment-text';
|
|
16
15
|
import { renderTextSegments } from '../../../react/utils/render-text-segments';
|
|
16
|
+
import { useAnnotationManagerDispatch } from '../contexts/AnnotationManagerContext';
|
|
17
17
|
|
|
18
18
|
// Localized AnnotationSharedCSSByState().common and AnnotationSharedCSSByState().focus
|
|
19
19
|
const markStyles = css({
|
|
@@ -39,12 +39,24 @@ export const AnnotationDraft = ({
|
|
|
39
39
|
draftPosition,
|
|
40
40
|
children
|
|
41
41
|
}) => {
|
|
42
|
+
const {
|
|
43
|
+
dispatch
|
|
44
|
+
} = useAnnotationManagerDispatch();
|
|
45
|
+
const markRef = useCallback(node => {
|
|
46
|
+
dispatch({
|
|
47
|
+
type: 'setDraftMarkRef',
|
|
48
|
+
data: {
|
|
49
|
+
draftMarkRef: node !== null && node !== void 0 ? node : undefined
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}, [dispatch]);
|
|
42
53
|
return jsx("mark", _extends({
|
|
43
54
|
"data-renderer-mark": true
|
|
44
55
|
// Ignored via go/ees005
|
|
45
56
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
46
57
|
}, dataAttributes(draftPosition), {
|
|
47
|
-
css: markStyles
|
|
58
|
+
css: markStyles,
|
|
59
|
+
ref: markRef
|
|
48
60
|
}), children);
|
|
49
61
|
};
|
|
50
62
|
export const getAnnotationIndex = (annotationPosition, fragmentCount) => {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React, { useMemo, useCallback, useContext } from 'react';
|
|
2
2
|
import { AnnotationMarkStates } from '@atlaskit/adf-schema';
|
|
3
|
+
import { AnnotationUpdateEvent } from '@atlaskit/editor-common/types';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
5
|
import { MarkComponent } from './mark';
|
|
4
6
|
import { useInlineCommentsFilter } from '../hooks/use-inline-comments-filter';
|
|
5
7
|
import { useInlineCommentSubscriberContext } from '../hooks/use-inline-comment-subscriber';
|
|
6
8
|
import { useHasFocusEvent } from '../hooks/use-events';
|
|
7
9
|
import { InlineCommentsStateContext } from '../context';
|
|
8
|
-
import {
|
|
10
|
+
import { useAnnotationManagerDispatch } from '../contexts/AnnotationManagerContext';
|
|
9
11
|
const MarkElement = ({
|
|
10
12
|
annotationParentIds,
|
|
11
13
|
children,
|
|
@@ -23,6 +25,10 @@ const MarkElement = ({
|
|
|
23
25
|
updateSubscriber
|
|
24
26
|
});
|
|
25
27
|
const dataAttributesMemorized = useMemo(() => dataAttributes, [dataAttributes]);
|
|
28
|
+
const {
|
|
29
|
+
dispatch,
|
|
30
|
+
annotationManager
|
|
31
|
+
} = useAnnotationManagerDispatch();
|
|
26
32
|
const onClick = useCallback(props => {
|
|
27
33
|
if (!updateSubscriber) {
|
|
28
34
|
return;
|
|
@@ -34,11 +40,38 @@ const MarkElement = ({
|
|
|
34
40
|
eventTarget,
|
|
35
41
|
annotationIds
|
|
36
42
|
} = props;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
if (fg('platform_editor_comments_api_manager')) {
|
|
44
|
+
if (hasFocus) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
annotationManager === null || annotationManager === void 0 ? void 0 : annotationManager.checkPreemptiveGate().then(canSelect => {
|
|
48
|
+
if (canSelect) {
|
|
49
|
+
dispatch({
|
|
50
|
+
type: 'updateAnnotation',
|
|
51
|
+
data: {
|
|
52
|
+
id: annotationIds[0],
|
|
53
|
+
selected: true
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
dispatch({
|
|
57
|
+
type: 'setSelectedMarkRef',
|
|
58
|
+
data: {
|
|
59
|
+
markRef: eventTarget
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
// TODO: EDITOR-595 - If the preemptive gate returns false, should we track the analytics event?
|
|
64
|
+
}
|
|
65
|
+
}).catch(error => {
|
|
66
|
+
// TODO: EDITOR-595 - An error occurred while checking the preemptive gate. We should report this error.
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
updateSubscriber.emit(AnnotationUpdateEvent.ON_ANNOTATION_CLICK, {
|
|
70
|
+
annotationIds,
|
|
71
|
+
eventTarget
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}, [updateSubscriber, useBlockLevel, dispatch, annotationManager, hasFocus]);
|
|
42
75
|
const activeParentIds = useInlineCommentsFilter({
|
|
43
76
|
annotationIds: annotationParentIds,
|
|
44
77
|
filter: {
|
|
@@ -10,6 +10,7 @@ import { AnnotationMarkStates } from '@atlaskit/adf-schema';
|
|
|
10
10
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
11
11
|
import { useIntl } from 'react-intl-next';
|
|
12
12
|
import { inlineCommentMessages } from '../../../messages';
|
|
13
|
+
import { useAnnotationManagerDispatch, useAnnotationManagerState } from '../contexts/AnnotationManagerContext';
|
|
13
14
|
const markStyles = css({
|
|
14
15
|
color: 'inherit',
|
|
15
16
|
backgroundColor: 'unset',
|
|
@@ -131,6 +132,22 @@ export const MarkComponent = ({
|
|
|
131
132
|
}) => {
|
|
132
133
|
const intl = useIntl();
|
|
133
134
|
const annotationIds = useMemo(() => [...new Set([...annotationParentIds, id])], [id, annotationParentIds]);
|
|
135
|
+
const {
|
|
136
|
+
dispatch
|
|
137
|
+
} = useAnnotationManagerDispatch();
|
|
138
|
+
const {
|
|
139
|
+
currentSelectedAnnotationId
|
|
140
|
+
} = useAnnotationManagerState();
|
|
141
|
+
const markRef = useCallback(node => {
|
|
142
|
+
if (id === currentSelectedAnnotationId && node) {
|
|
143
|
+
dispatch({
|
|
144
|
+
type: 'setSelectedMarkRef',
|
|
145
|
+
data: {
|
|
146
|
+
markRef: node
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}, [dispatch, id, currentSelectedAnnotationId]);
|
|
134
151
|
const onMarkClick = useCallback(event => {
|
|
135
152
|
// prevent inline mark logic for media block marks
|
|
136
153
|
if (event.currentTarget instanceof HTMLElement && event.currentTarget.getAttribute('data-block-mark')) {
|
|
@@ -191,6 +208,7 @@ export const MarkComponent = ({
|
|
|
191
208
|
...desktopAccessibilityAttributes
|
|
192
209
|
};
|
|
193
210
|
return jsx(useBlockLevel ? 'div' : 'mark', {
|
|
211
|
+
ref: id === currentSelectedAnnotationId ? markRef : undefined,
|
|
194
212
|
id,
|
|
195
213
|
[fg('editor_inline_comments_on_inline_nodes') ? 'onClickCapture' : 'onClick']: onMarkClick,
|
|
196
214
|
...accessibility,
|