@manuscripts/body-editor 3.16.0 → 3.16.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.
Files changed (54) hide show
  1. package/dist/cjs/commands.js +45 -10
  2. package/dist/cjs/components/form/FormFooter.js +2 -2
  3. package/dist/cjs/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.js +4 -2
  4. package/dist/cjs/components/views/CrossReferenceItems.js +139 -52
  5. package/dist/cjs/components/views/DeleteSupplementDialog.js +1 -1
  6. package/dist/cjs/lib/supplements.js +9 -1
  7. package/dist/cjs/menus.js +35 -0
  8. package/dist/cjs/plugins/objects.js +1 -1
  9. package/dist/cjs/toolbar.js +6 -0
  10. package/dist/cjs/versions.js +1 -1
  11. package/dist/cjs/views/cross_reference.js +12 -2
  12. package/dist/cjs/views/cross_reference_editable.js +95 -4
  13. package/dist/cjs/views/figure_editable.js +3 -0
  14. package/dist/es/commands.js +43 -9
  15. package/dist/es/components/form/FormFooter.js +2 -2
  16. package/dist/es/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.js +4 -2
  17. package/dist/es/components/views/CrossReferenceItems.js +141 -54
  18. package/dist/es/components/views/DeleteSupplementDialog.js +2 -2
  19. package/dist/es/lib/supplements.js +8 -1
  20. package/dist/es/menus.js +36 -1
  21. package/dist/es/plugins/objects.js +1 -1
  22. package/dist/es/toolbar.js +8 -2
  23. package/dist/es/versions.js +1 -1
  24. package/dist/es/views/cross_reference.js +12 -2
  25. package/dist/es/views/cross_reference_editable.js +96 -5
  26. package/dist/es/views/figure_editable.js +3 -0
  27. package/dist/types/commands.d.ts +1 -0
  28. package/dist/types/components/form/FormFooter.d.ts +2 -1
  29. package/dist/types/components/views/CrossReferenceItems.d.ts +3 -0
  30. package/dist/types/lib/supplements.d.ts +1 -0
  31. package/dist/types/versions.d.ts +1 -1
  32. package/dist/types/views/cross_reference_editable.d.ts +6 -0
  33. package/package.json +4 -4
  34. package/src/commands.ts +52 -10
  35. package/src/components/ChangeHandlingForm.tsx +4 -2
  36. package/src/components/form/FormFooter.tsx +3 -1
  37. package/src/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.tsx +6 -7
  38. package/src/components/toolbar/InsertEmbedDialog.tsx +6 -2
  39. package/src/components/toolbar/type-selector/styles.ts +2 -1
  40. package/src/components/views/CrossReferenceItems.tsx +227 -100
  41. package/src/components/views/DeleteSupplementDialog.tsx +3 -6
  42. package/src/lib/footnotes.ts +3 -1
  43. package/src/lib/supplements.ts +13 -1
  44. package/src/lib/utils.ts +15 -4
  45. package/src/menus.tsx +39 -0
  46. package/src/plugins/add-subtitle.ts +18 -16
  47. package/src/plugins/objects.ts +2 -6
  48. package/src/toolbar.tsx +9 -0
  49. package/src/versions.ts +1 -1
  50. package/src/views/cross_reference.ts +17 -3
  51. package/src/views/cross_reference_editable.ts +123 -11
  52. package/src/views/figure_editable.ts +4 -0
  53. package/src/views/supplement.ts +0 -1
  54. package/src/views/supplements.ts +2 -2
@@ -17,10 +17,14 @@
17
17
  import {
18
18
  CrossReferenceNode,
19
19
  ManuscriptNodeView,
20
+ schema,
21
+ SupplementNode,
20
22
  Target,
21
23
  } from '@manuscripts/transform'
22
24
 
25
+ import { findNodeByID } from '../lib/doc'
23
26
  import { handleEnterKey } from '../lib/navigation-utils'
27
+ import { getSupplementDisplayLabel } from '../lib/supplements'
24
28
  import { objectsKey } from '../plugins/objects'
25
29
  import { Trackable } from '../types'
26
30
  import { BaseNodeView } from './base_node_view'
@@ -45,10 +49,20 @@ export class CrossReferenceView
45
49
  super.updateContents()
46
50
  const targets = objectsKey.getState(this.view.state) as Map<string, Target>
47
51
  const attrs = this.node.attrs
52
+ const target = attrs.rids.length ? targets.get(attrs.rids[0]) : undefined
48
53
 
49
- const label = attrs.rids.length && targets.get(attrs.rids[0])?.label
50
- // attrs.label contains custom text inserted at cross-reference creation time
51
- this.dom.textContent = attrs.label || label || ''
54
+ let derivedLabel = target?.label || ''
55
+ if (target?.type === schema.nodes.supplement.name && target.href) {
56
+ const found = findNodeByID(this.view.state.doc, target.id)
57
+ if (found) {
58
+ derivedLabel = getSupplementDisplayLabel(
59
+ found.node as SupplementNode,
60
+ this.props.getFiles()
61
+ )
62
+ }
63
+ }
64
+
65
+ this.dom.textContent = attrs.label || derivedLabel
52
66
  this.dom.addEventListener('click', this.handleClick)
53
67
  }
54
68
 
@@ -14,11 +14,15 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { skipTracking } from '@manuscripts/track-changes-plugin'
18
- import { schema, Target } from '@manuscripts/transform'
17
+ import { ContextMenu, ContextMenuProps } from '@manuscripts/style-guide'
18
+ import { isDeleted, skipTracking } from '@manuscripts/track-changes-plugin'
19
+ import { schema, SupplementNode, Target } from '@manuscripts/transform'
19
20
  import { TextSelection } from 'prosemirror-state'
20
21
 
21
22
  import { CrossReferenceItems } from '../components/views/CrossReferenceItems'
23
+ import { handleComment } from '../lib/comments'
24
+ import { findNodeByID } from '../lib/doc'
25
+ import { getSupplementDisplayLabel } from '../lib/supplements'
22
26
  import { objectsKey } from '../plugins/objects'
23
27
  import { createEditableNodeView } from './creators'
24
28
  import { CrossReferenceView } from './cross_reference'
@@ -26,6 +30,7 @@ import ReactSubView from './ReactSubView'
26
30
 
27
31
  export class CrossReferenceEditableView extends CrossReferenceView {
28
32
  protected popperContainer: HTMLDivElement
33
+ protected contextMenu: HTMLElement
29
34
 
30
35
  public selectNode = () => {
31
36
  const { getCapabilities } = this.props
@@ -37,12 +42,20 @@ export class CrossReferenceEditableView extends CrossReferenceView {
37
42
  return
38
43
  }
39
44
 
45
+ this.showPicker()
46
+ }
47
+
48
+ public showPicker = () => {
49
+ const rids = this.node.attrs.rids
50
+
40
51
  const componentProps = {
41
52
  handleSelect: this.handleSelect,
42
53
  targets: this.getTargets(),
54
+ files: this.props.getFiles(),
43
55
  handleCancel: this.handleCancel,
44
56
  currentTargetId: rids[0],
45
57
  currentCustomLabel: this.node.attrs.label,
58
+ isEdit: rids.length > 0,
46
59
  }
47
60
 
48
61
  this.popperContainer = ReactSubView(
@@ -51,8 +64,7 @@ export class CrossReferenceEditableView extends CrossReferenceView {
51
64
  componentProps,
52
65
  this.node,
53
66
  this.getPos,
54
- this.view,
55
- ['cross-reference-editor']
67
+ this.view
56
68
  )
57
69
  this.popperContainer.setAttribute('tabindex', '0')
58
70
  this.props.popper.show(this.dom, this.popperContainer, 'auto')
@@ -68,13 +80,28 @@ export class CrossReferenceEditableView extends CrossReferenceView {
68
80
  }
69
81
 
70
82
  public getTargets = () => {
71
- const excludedTypes = [schema.nodes.image_element.name]
72
-
73
83
  const targets = objectsKey.getState(this.view.state) as Map<string, Target>
74
-
75
- return Array.from(targets.values()).filter(
76
- (t) => !excludedTypes.includes(t.type)
77
- )
84
+ const files = this.props.getFiles()
85
+ const fileMap = new Map(files.map((f) => [f.id, f.name]))
86
+ const excludedTypes = [schema.nodes.image_element.name]
87
+ const supplement = schema.nodes.supplement.name
88
+
89
+ return Array.from(targets.values()).reduce<Target[]>((acc, t) => {
90
+ if (excludedTypes.includes(t.type)) {
91
+ return acc
92
+ }
93
+ // Prefer caption title, then URL / file name for supplements and weblinks.
94
+ if (t.type === supplement && t.href) {
95
+ const found = findNodeByID(this.view.state.doc, t.id)
96
+ const label = found
97
+ ? getSupplementDisplayLabel(found.node as SupplementNode, files)
98
+ : (fileMap.get(t.href) ?? t.href)
99
+ acc.push({ ...t, label, caption: '' })
100
+ } else {
101
+ acc.push(t)
102
+ }
103
+ return acc
104
+ }, [])
78
105
  }
79
106
 
80
107
  public handleCancel = () => {
@@ -82,7 +109,17 @@ export class CrossReferenceEditableView extends CrossReferenceView {
82
109
  const { state } = this.view
83
110
 
84
111
  const pos = this.getPos()
85
- const tr = state.tr.delete(pos, pos + this.node.nodeSize)
112
+ if (pos === undefined) {
113
+ return
114
+ }
115
+ const label = this.node.attrs.label
116
+ const tr = label
117
+ ? state.tr.replaceWith(
118
+ pos,
119
+ pos + this.node.nodeSize,
120
+ state.schema.text(label)
121
+ )
122
+ : state.tr.delete(pos, pos + this.node.nodeSize)
86
123
  tr.setSelection(TextSelection.create(tr.doc, pos))
87
124
  skipTracking(tr)
88
125
  this.view.dispatch(tr)
@@ -108,6 +145,81 @@ export class CrossReferenceEditableView extends CrossReferenceView {
108
145
 
109
146
  this.destroy()
110
147
  }
148
+
149
+ public handleClick = () => {
150
+ if (isDeleted(this.node)) {
151
+ return
152
+ }
153
+ if (!this.node.attrs.rids.length) {
154
+ return
155
+ }
156
+ this.showContextMenu()
157
+ }
158
+
159
+ public showContextMenu = () => {
160
+ this.props.popper.destroy()
161
+
162
+ const can = this.props.getCapabilities()
163
+
164
+ const targets = objectsKey.getState(this.view.state) as Map<string, Target>
165
+ const rid = this.node.attrs.rids[0]
166
+ const isOrphaned = !targets?.get(rid)
167
+
168
+ const actions: ContextMenuProps['actions'] = [
169
+ {
170
+ label: 'Comment',
171
+ icon: 'AddComment',
172
+ action: () => {
173
+ this.props.popper.destroy()
174
+ handleComment(this.node, this.view)
175
+ },
176
+ },
177
+ {
178
+ label: 'Go to content',
179
+ icon: 'Scroll',
180
+ action: () => this.navigateToTarget(),
181
+ disabled: isOrphaned,
182
+ },
183
+ ]
184
+
185
+ if (can?.editArticle) {
186
+ actions.unshift({
187
+ label: 'Edit',
188
+ icon: 'Edit',
189
+ action: () => this.handleEdit(),
190
+ disabled: isOrphaned,
191
+ })
192
+ }
193
+
194
+ this.contextMenu = ReactSubView(
195
+ this.props,
196
+ ContextMenu,
197
+ { actions },
198
+ this.node,
199
+ this.getPos,
200
+ this.view,
201
+ ['context-menu']
202
+ )
203
+
204
+ this.props.popper.show(this.dom, this.contextMenu, 'right-start', false)
205
+ }
206
+
207
+ private navigateToTarget = () => {
208
+ this.props.popper.destroy()
209
+ const rids = this.node.attrs.rids
210
+ if (!rids.length) {
211
+ return
212
+ }
213
+ this.props.navigate({
214
+ pathname: this.props.location.pathname,
215
+ hash: '#' + rids[0],
216
+ })
217
+ }
218
+
219
+ private handleEdit = () => {
220
+ this.props.popper.destroy()
221
+ this.showPicker()
222
+ }
111
223
  }
112
224
 
113
225
  export default createEditableNodeView(CrossReferenceEditableView)
@@ -240,6 +240,10 @@ export class FigureEditableView extends FigureView {
240
240
  }
241
241
 
242
242
  public addTools() {
243
+ if (this.getPos() === undefined) {
244
+ return
245
+ }
246
+
243
247
  this.manageReactTools()
244
248
 
245
249
  const existingDragHandlers =
@@ -25,7 +25,6 @@ import { Trackable } from '../types'
25
25
  import { BaseNodeView } from './base_node_view'
26
26
  import { createNodeView } from './creators'
27
27
 
28
-
29
28
  export class SupplementView extends BaseNodeView<Trackable<SupplementNode>> {
30
29
  private supplementInfoEl: HTMLDivElement
31
30
  private static currentDragSupplementId: string | null = null
@@ -32,7 +32,7 @@ export class SupplementsView extends BlockView<Trackable<SupplementsNode>> {
32
32
  this.toggleButton = document.createElement('button')
33
33
  this.toggleButton.classList.add('supplements-toggle-btn', 'button-reset')
34
34
  this.toggleButton.innerHTML = arrowUp
35
-
35
+
36
36
  const handleToggle = () => {
37
37
  this.collapsed = !this.collapsed
38
38
  this.toggleContent()
@@ -63,4 +63,4 @@ export class SupplementsView extends BlockView<Trackable<SupplementsNode>> {
63
63
  }
64
64
  }
65
65
 
66
- export default createNodeView(SupplementsView)
66
+ export default createNodeView(SupplementsView)