@manuscripts/body-editor 3.2.29 → 3.2.30

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/dist/cjs/icons.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fileCorruptedIcon = exports.imageDefaultIcon = exports.imageLeftIcon = exports.imageRightIcon = exports.addFigureBtnIcon = exports.plusIcon = exports.lockIcon = exports.scrollIcon = exports.sectionCategoryIcon = exports.editIcon = exports.deleteIcon = exports.alertIcon = exports.arrowUp = exports.arrowDown = void 0;
3
+ exports.draggableIcon = exports.fileCorruptedIcon = exports.imageDefaultIcon = exports.imageLeftIcon = exports.imageRightIcon = exports.addFigureBtnIcon = exports.plusIcon = exports.lockIcon = exports.scrollIcon = exports.sectionCategoryIcon = exports.editIcon = exports.deleteIcon = exports.alertIcon = exports.arrowUp = exports.arrowDown = void 0;
4
4
  const style_guide_1 = require("@manuscripts/style-guide");
5
5
  const react_1 = require("react");
6
6
  const server_1 = require("react-dom/server");
@@ -19,3 +19,4 @@ exports.imageRightIcon = (0, server_1.renderToStaticMarkup)((0, react_1.createEl
19
19
  exports.imageLeftIcon = (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(style_guide_1.ImageLeftIcon));
20
20
  exports.imageDefaultIcon = (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(style_guide_1.ImageDefaultIcon));
21
21
  exports.fileCorruptedIcon = (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(style_guide_1.FileCorruptedIcon));
22
+ exports.draggableIcon = (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(style_guide_1.DraggableIcon));
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MATHJAX_VERSION = exports.VERSION = void 0;
4
- exports.VERSION = '3.2.29';
4
+ exports.VERSION = '3.2.30';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -32,6 +32,7 @@ const ReactSubView_1 = __importDefault(require("./ReactSubView"));
32
32
  class FigureEditableView extends figure_1.FigureView {
33
33
  constructor() {
34
34
  super(...arguments);
35
+ this.dragAndDropInitialized = false;
35
36
  this.upload = async (file) => {
36
37
  const result = await this.props.fileManagement.upload(file);
37
38
  this.setSrc(result.id);
@@ -95,8 +96,116 @@ class FigureEditableView extends figure_1.FigureView {
95
96
  this.createDOM();
96
97
  this.updateContents();
97
98
  }
99
+ clearTargetClass(target, classes = ['drop-target-above', 'drop-target-below']) {
100
+ target.classList.remove(...classes);
101
+ }
102
+ handleDragStart() {
103
+ const figureId = this.node.attrs.id;
104
+ FigureEditableView.currentDragFigureId = figureId;
105
+ this.container.classList.add('dragging');
106
+ const parent = this.container.parentElement;
107
+ if (parent) {
108
+ const siblingFigures = parent.querySelectorAll('.figure');
109
+ siblingFigures.forEach((el) => {
110
+ if (el !== this.container) {
111
+ el.classList.add('drag-active');
112
+ }
113
+ });
114
+ }
115
+ }
116
+ setupDragAndDrop() {
117
+ this.container.draggable = true;
118
+ this.container.addEventListener('dragstart', () => {
119
+ if (this.node.attrs.id && !(0, track_changes_utils_1.isDeleted)(this.node)) {
120
+ this.handleDragStart();
121
+ }
122
+ });
123
+ if (this.dragHandle) {
124
+ this.dragHandle.addEventListener('dragstart', () => {
125
+ this.handleDragStart();
126
+ });
127
+ }
128
+ this.container.addEventListener('dragend', () => {
129
+ FigureEditableView.currentDragFigureId = null;
130
+ this.clearTargetClass(this.container, ['dragging']);
131
+ const parent = this.container.parentElement;
132
+ if (parent) {
133
+ const figures = parent.querySelectorAll('.figure');
134
+ figures.forEach((el) => {
135
+ this.clearTargetClass(el, [
136
+ 'drag-active',
137
+ 'drop-target-above',
138
+ 'drop-target-below',
139
+ ]);
140
+ });
141
+ }
142
+ });
143
+ this.container.addEventListener('dragover', (e) => {
144
+ if (FigureEditableView.currentDragFigureId) {
145
+ e.preventDefault();
146
+ e.stopPropagation();
147
+ const rect = this.container.getBoundingClientRect();
148
+ const relativeY = e.clientY - rect.top;
149
+ const isAbove = relativeY < rect.height / 2;
150
+ this.clearTargetClass(this.container);
151
+ this.container.classList.add(isAbove ? 'drop-target-above' : 'drop-target-below');
152
+ }
153
+ });
154
+ this.container.addEventListener('dragleave', (e) => {
155
+ if (!this.container.contains(e.relatedTarget)) {
156
+ this.clearTargetClass(this.container);
157
+ }
158
+ });
159
+ this.container.addEventListener('drop', (e) => {
160
+ if (!FigureEditableView.currentDragFigureId) {
161
+ return;
162
+ }
163
+ e.preventDefault();
164
+ e.stopPropagation();
165
+ const figureId = FigureEditableView.currentDragFigureId;
166
+ if (!figureId) {
167
+ return;
168
+ }
169
+ const figure = this.getFigureById(figureId);
170
+ if (!figure) {
171
+ return;
172
+ }
173
+ const toPos = this.getPos();
174
+ if (figure.pos === toPos) {
175
+ return;
176
+ }
177
+ this.moveFigure(figure.pos, figure.node, toPos);
178
+ this.clearTargetClass(this.container);
179
+ });
180
+ }
181
+ getFigureById(figureId) {
182
+ let result = null;
183
+ this.view.state.doc.descendants((node, pos) => {
184
+ if (node.type === transform_1.schema.nodes.figure && node.attrs.id === figureId) {
185
+ result = { pos, node };
186
+ return false;
187
+ }
188
+ if (result) {
189
+ return false;
190
+ }
191
+ });
192
+ return result;
193
+ }
194
+ moveFigure(fromPos, fromNode, targetPos) {
195
+ const { state } = this.view;
196
+ const { tr } = state;
197
+ tr.delete(fromPos, fromPos + fromNode.nodeSize);
198
+ tr.insert(this.view.state.tr.mapping.map(targetPos), fromNode);
199
+ this.view.dispatch(tr);
200
+ }
98
201
  updateContents() {
99
202
  super.updateContents();
203
+ this.clearTargetClass(this.container, ['dragging']);
204
+ if (this.props.getCapabilities().editArticle &&
205
+ !this.dragAndDropInitialized) {
206
+ this.setupDragAndDrop();
207
+ this.dragAndDropInitialized = true;
208
+ }
100
209
  const src = this.node.attrs.src;
101
210
  const files = this.props.getFiles();
102
211
  const file = src && files.filter((f) => f.id === src)[0];
@@ -154,6 +263,20 @@ class FigureEditableView extends figure_1.FigureView {
154
263
  }
155
264
  addTools() {
156
265
  this.manageReactTools();
266
+ const $pos = this.view.state.doc.resolve(this.getPos());
267
+ const parent = $pos.parent;
268
+ if (this.props.getCapabilities()?.editArticle &&
269
+ parent.type === transform_1.schema.nodes.figure_element &&
270
+ !(0, track_changes_utils_1.isDeleted)(this.node)) {
271
+ const dragHandle = document.createElement('div');
272
+ dragHandle.className = 'drag-handler';
273
+ dragHandle.innerHTML = icons_1.draggableIcon;
274
+ dragHandle.draggable = true;
275
+ dragHandle.addEventListener('mousedown', (e) => {
276
+ e.stopPropagation();
277
+ });
278
+ this.container.appendChild(dragHandle);
279
+ }
157
280
  }
158
281
  manageReactTools() {
159
282
  let handleDownload;
@@ -243,4 +366,5 @@ class FigureEditableView extends figure_1.FigureView {
243
366
  }
244
367
  }
245
368
  exports.FigureEditableView = FigureEditableView;
369
+ FigureEditableView.currentDragFigureId = null;
246
370
  exports.default = (0, creators_1.createEditableNodeView)(FigureEditableView);
package/dist/es/icons.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AlertIcon, ArrowDownCircleIcon, ArrowUpIcon, DeleteIcon, EditIcon, FileCorruptedIcon, ImageDefaultIcon, ImageLeftIcon, ImageRightIcon, LockIcon, PlusIcon, ScrollIcon, SectionCategoryIcon, } from '@manuscripts/style-guide';
1
+ import { AlertIcon, ArrowDownCircleIcon, ArrowUpIcon, DeleteIcon, DraggableIcon, EditIcon, FileCorruptedIcon, ImageDefaultIcon, ImageLeftIcon, ImageRightIcon, LockIcon, PlusIcon, ScrollIcon, SectionCategoryIcon, } from '@manuscripts/style-guide';
2
2
  import { createElement } from 'react';
3
3
  import { renderToStaticMarkup } from 'react-dom/server';
4
4
  const renderIcon = (c) => renderToStaticMarkup(createElement(c));
@@ -16,3 +16,4 @@ export const imageRightIcon = renderToStaticMarkup(createElement(ImageRightIcon)
16
16
  export const imageLeftIcon = renderToStaticMarkup(createElement(ImageLeftIcon));
17
17
  export const imageDefaultIcon = renderToStaticMarkup(createElement(ImageDefaultIcon));
18
18
  export const fileCorruptedIcon = renderToStaticMarkup(createElement(FileCorruptedIcon));
19
+ export const draggableIcon = renderToStaticMarkup(createElement(DraggableIcon));
@@ -1,2 +1,2 @@
1
- export const VERSION = '3.2.29';
1
+ export const VERSION = '3.2.30';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -17,7 +17,7 @@ import { schema } from '@manuscripts/transform';
17
17
  import { NodeSelection } from 'prosemirror-state';
18
18
  import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils';
19
19
  import { FigureOptions, } from '../components/views/FigureDropdown';
20
- import { fileCorruptedIcon } from '../icons';
20
+ import { draggableIcon, fileCorruptedIcon } from '../icons';
21
21
  import { isDeleted } from '../lib/track-changes-utils';
22
22
  import { createEditableNodeView } from './creators';
23
23
  import { FigureView } from './figure';
@@ -26,6 +26,7 @@ import ReactSubView from './ReactSubView';
26
26
  export class FigureEditableView extends FigureView {
27
27
  constructor() {
28
28
  super(...arguments);
29
+ this.dragAndDropInitialized = false;
29
30
  this.upload = async (file) => {
30
31
  const result = await this.props.fileManagement.upload(file);
31
32
  this.setSrc(result.id);
@@ -89,8 +90,116 @@ export class FigureEditableView extends FigureView {
89
90
  this.createDOM();
90
91
  this.updateContents();
91
92
  }
93
+ clearTargetClass(target, classes = ['drop-target-above', 'drop-target-below']) {
94
+ target.classList.remove(...classes);
95
+ }
96
+ handleDragStart() {
97
+ const figureId = this.node.attrs.id;
98
+ FigureEditableView.currentDragFigureId = figureId;
99
+ this.container.classList.add('dragging');
100
+ const parent = this.container.parentElement;
101
+ if (parent) {
102
+ const siblingFigures = parent.querySelectorAll('.figure');
103
+ siblingFigures.forEach((el) => {
104
+ if (el !== this.container) {
105
+ el.classList.add('drag-active');
106
+ }
107
+ });
108
+ }
109
+ }
110
+ setupDragAndDrop() {
111
+ this.container.draggable = true;
112
+ this.container.addEventListener('dragstart', () => {
113
+ if (this.node.attrs.id && !isDeleted(this.node)) {
114
+ this.handleDragStart();
115
+ }
116
+ });
117
+ if (this.dragHandle) {
118
+ this.dragHandle.addEventListener('dragstart', () => {
119
+ this.handleDragStart();
120
+ });
121
+ }
122
+ this.container.addEventListener('dragend', () => {
123
+ FigureEditableView.currentDragFigureId = null;
124
+ this.clearTargetClass(this.container, ['dragging']);
125
+ const parent = this.container.parentElement;
126
+ if (parent) {
127
+ const figures = parent.querySelectorAll('.figure');
128
+ figures.forEach((el) => {
129
+ this.clearTargetClass(el, [
130
+ 'drag-active',
131
+ 'drop-target-above',
132
+ 'drop-target-below',
133
+ ]);
134
+ });
135
+ }
136
+ });
137
+ this.container.addEventListener('dragover', (e) => {
138
+ if (FigureEditableView.currentDragFigureId) {
139
+ e.preventDefault();
140
+ e.stopPropagation();
141
+ const rect = this.container.getBoundingClientRect();
142
+ const relativeY = e.clientY - rect.top;
143
+ const isAbove = relativeY < rect.height / 2;
144
+ this.clearTargetClass(this.container);
145
+ this.container.classList.add(isAbove ? 'drop-target-above' : 'drop-target-below');
146
+ }
147
+ });
148
+ this.container.addEventListener('dragleave', (e) => {
149
+ if (!this.container.contains(e.relatedTarget)) {
150
+ this.clearTargetClass(this.container);
151
+ }
152
+ });
153
+ this.container.addEventListener('drop', (e) => {
154
+ if (!FigureEditableView.currentDragFigureId) {
155
+ return;
156
+ }
157
+ e.preventDefault();
158
+ e.stopPropagation();
159
+ const figureId = FigureEditableView.currentDragFigureId;
160
+ if (!figureId) {
161
+ return;
162
+ }
163
+ const figure = this.getFigureById(figureId);
164
+ if (!figure) {
165
+ return;
166
+ }
167
+ const toPos = this.getPos();
168
+ if (figure.pos === toPos) {
169
+ return;
170
+ }
171
+ this.moveFigure(figure.pos, figure.node, toPos);
172
+ this.clearTargetClass(this.container);
173
+ });
174
+ }
175
+ getFigureById(figureId) {
176
+ let result = null;
177
+ this.view.state.doc.descendants((node, pos) => {
178
+ if (node.type === schema.nodes.figure && node.attrs.id === figureId) {
179
+ result = { pos, node };
180
+ return false;
181
+ }
182
+ if (result) {
183
+ return false;
184
+ }
185
+ });
186
+ return result;
187
+ }
188
+ moveFigure(fromPos, fromNode, targetPos) {
189
+ const { state } = this.view;
190
+ const { tr } = state;
191
+ tr.delete(fromPos, fromPos + fromNode.nodeSize);
192
+ tr.insert(this.view.state.tr.mapping.map(targetPos), fromNode);
193
+ this.view.dispatch(tr);
194
+ }
92
195
  updateContents() {
93
196
  super.updateContents();
197
+ this.clearTargetClass(this.container, ['dragging']);
198
+ if (this.props.getCapabilities().editArticle &&
199
+ !this.dragAndDropInitialized) {
200
+ this.setupDragAndDrop();
201
+ this.dragAndDropInitialized = true;
202
+ }
94
203
  const src = this.node.attrs.src;
95
204
  const files = this.props.getFiles();
96
205
  const file = src && files.filter((f) => f.id === src)[0];
@@ -148,6 +257,20 @@ export class FigureEditableView extends FigureView {
148
257
  }
149
258
  addTools() {
150
259
  this.manageReactTools();
260
+ const $pos = this.view.state.doc.resolve(this.getPos());
261
+ const parent = $pos.parent;
262
+ if (this.props.getCapabilities()?.editArticle &&
263
+ parent.type === schema.nodes.figure_element &&
264
+ !isDeleted(this.node)) {
265
+ const dragHandle = document.createElement('div');
266
+ dragHandle.className = 'drag-handler';
267
+ dragHandle.innerHTML = draggableIcon;
268
+ dragHandle.draggable = true;
269
+ dragHandle.addEventListener('mousedown', (e) => {
270
+ e.stopPropagation();
271
+ });
272
+ this.container.appendChild(dragHandle);
273
+ }
151
274
  }
152
275
  manageReactTools() {
153
276
  let handleDownload;
@@ -236,4 +359,5 @@ export class FigureEditableView extends FigureView {
236
359
  }
237
360
  }
238
361
  }
362
+ FigureEditableView.currentDragFigureId = null;
239
363
  export default createEditableNodeView(FigureEditableView);
@@ -12,3 +12,4 @@ export declare const imageRightIcon: string;
12
12
  export declare const imageLeftIcon: string;
13
13
  export declare const imageDefaultIcon: string;
14
14
  export declare const fileCorruptedIcon: string;
15
+ export declare const draggableIcon: string;
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "3.2.29";
1
+ export declare const VERSION = "3.2.30";
2
2
  export declare const MATHJAX_VERSION = "3.2.2";
@@ -16,7 +16,15 @@
16
16
  import { FigureView } from './figure';
17
17
  export declare class FigureEditableView extends FigureView {
18
18
  reactTools: HTMLDivElement;
19
+ private dragHandle;
20
+ private static currentDragFigureId;
21
+ private dragAndDropInitialized;
19
22
  initialise(): void;
23
+ private clearTargetClass;
24
+ private handleDragStart;
25
+ private setupDragAndDrop;
26
+ private getFigureById;
27
+ private moveFigure;
20
28
  upload: (file: File) => Promise<void>;
21
29
  updateContents(): void;
22
30
  protected addTools(): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@manuscripts/body-editor",
3
3
  "description": "Prosemirror components for editing and viewing manuscripts",
4
- "version": "3.2.29",
4
+ "version": "3.2.30",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -39,7 +39,7 @@
39
39
  "@citation-js/plugin-ris": "0.7.18",
40
40
  "@manuscripts/json-schema": "2.2.12",
41
41
  "@manuscripts/style-guide": "3.1.6",
42
- "@manuscripts/track-changes-plugin": "2.0.5",
42
+ "@manuscripts/track-changes-plugin": "2.0.6",
43
43
  "@manuscripts/transform": "4.2.9",
44
44
  "@popperjs/core": "2.11.8",
45
45
  "citeproc": "2.4.63",
@@ -334,6 +334,45 @@
334
334
  .ProseMirror .box-element .figure-block .position-menu {
335
335
  left: calc(100% - 82px);
336
336
  }
337
+ /* Drag Figure Styles */
338
+ .ProseMirror .figure-block .drag-handler {
339
+ opacity: 0;
340
+ width: 24px;
341
+ height: 24px;
342
+ padding: 4px;
343
+ cursor: move;
344
+ border-radius: 4px;
345
+ position: absolute;
346
+ left: 0;
347
+ bottom: 20px;
348
+ text-align: center;
349
+ align-items: center;
350
+ pointer-events: auto;
351
+ transition: opacity 0.2s;
352
+ background-color: #FAFAFA;
353
+ border: 1px solid #F2F2F2;
354
+
355
+ }
356
+ .ProseMirror .figure-block .figure:hover .drag-handler {
357
+ opacity: 1;
358
+ }
359
+
360
+ /* Drop area blue dotted outline */
361
+ .ProseMirror .figure-block .figure.drop-target-above,
362
+ .ProseMirror .figure-block .figure.drop-target-below {
363
+ border: 2px dotted #20AEDF !important;
364
+ transition: border 0.2s, box-shadow 0.2s;
365
+ position: relative;
366
+ }
367
+
368
+ .ProseMirror .figure-block .figure.drop-target-above::before { top: 0; }
369
+ .ProseMirror .figure-block .figure.drop-target-below::after { bottom: 0; }
370
+
371
+ .ProseMirror .figure.dragging {
372
+ opacity: 0.6;
373
+ z-index: 1000;
374
+ transition: opacity 0.2s;
375
+ }
337
376
 
338
377
  .ProseMirror .block-container.block-box_element {
339
378
  grid-template-columns: auto;
@@ -982,8 +1021,8 @@ figure.block:has(.equation.selected-suggestion) {
982
1021
  [data-track-op='node_split'][data-track-status='pending']
983
1022
  .block, .tracking-visible
984
1023
  .selected-suggestion[data-track-op='move'][data-track-status='pending']
985
- .block {
986
- box-shadow: inset 3px 0 0 var(--updated-border-color);
1024
+ .block , .block:has(figure.selected-suggestion, [data-track-op='move'][data-track-status='pending']){
1025
+ box-shadow: inset 3px 0 0 var(--updated-border-color) ;
987
1026
  }
988
1027
 
989
1028
  .tracking-visible .selected-suggestion[data-track-op='set_attrs'] .block,