@manuscripts/body-editor 3.14.0 → 3.15.0
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/components/authors-affiliations/AuthorsAndAffiliationsModals.js +1 -0
- package/dist/cjs/components/cross-ref-check-modal/CrossRefWarningModal.js +182 -0
- package/dist/cjs/components/cross-ref-check-modal/openModal.js +38 -0
- package/dist/cjs/plugins/cross-references.js +160 -0
- package/dist/cjs/versions.js +1 -1
- package/dist/es/components/authors-affiliations/AuthorsAndAffiliationsModals.js +1 -0
- package/dist/es/components/cross-ref-check-modal/CrossRefWarningModal.js +142 -0
- package/dist/es/components/cross-ref-check-modal/openModal.js +31 -0
- package/dist/es/plugins/cross-references.js +162 -2
- package/dist/es/versions.js +1 -1
- package/dist/types/components/authors-affiliations/AuthorsAndAffiliationsModals.d.ts +1 -1
- package/dist/types/components/cross-ref-check-modal/CrossRefWarningModal.d.ts +29 -0
- package/dist/types/components/cross-ref-check-modal/openModal.d.ts +19 -0
- package/dist/types/versions.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/authors-affiliations/AuthorsAndAffiliationsModals.tsx +2 -0
- package/src/components/cross-ref-check-modal/CrossRefWarningModal.tsx +223 -0
- package/src/components/cross-ref-check-modal/openModal.ts +50 -0
- package/src/plugins/cross-references.ts +232 -6
- package/src/versions.ts +1 -1
|
@@ -114,5 +114,6 @@ const openAuthorsAndAffiliationsModals = (pos, view, initialModal) => {
|
|
|
114
114
|
const dialog = (0, ReactSubView_1.default)(props, exports.AuthorsAndAffiliationsModals, componentProps, state.doc, () => pos, view);
|
|
115
115
|
view.focus();
|
|
116
116
|
document.body.appendChild(dialog);
|
|
117
|
+
return dialog;
|
|
117
118
|
};
|
|
118
119
|
exports.openAuthorsAndAffiliationsModals = openAuthorsAndAffiliationsModals;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* © 2026 Atypon Systems LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
51
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
52
|
+
};
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.CrossRefWarningModal = void 0;
|
|
55
|
+
const react_1 = __importStar(require("react"));
|
|
56
|
+
const style_guide_1 = require("@manuscripts/style-guide");
|
|
57
|
+
const lodash_1 = require("lodash");
|
|
58
|
+
const styled_components_1 = __importDefault(require("styled-components"));
|
|
59
|
+
const CrossRefWarningModal = ({ onClose, xrefs, onConfirm, selectAndScrollTo }) => {
|
|
60
|
+
const [isOpen, setIsOpen] = (0, react_1.useState)(true);
|
|
61
|
+
const handleClose = () => {
|
|
62
|
+
setIsOpen(false);
|
|
63
|
+
onClose();
|
|
64
|
+
};
|
|
65
|
+
return (react_1.default.createElement(Modal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: false, hideOverlay: true },
|
|
66
|
+
react_1.default.createElement(Container, { "data-cy": "cross-reference-warning-modal" },
|
|
67
|
+
react_1.default.createElement(style_guide_1.ModalHeader, null,
|
|
68
|
+
react_1.default.createElement(style_guide_1.CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
|
|
69
|
+
react_1.default.createElement(Body, null,
|
|
70
|
+
react_1.default.createElement(Title, null,
|
|
71
|
+
react_1.default.createElement(style_guide_1.AttentionOrangeIcon, { width: 24, height: 22 }),
|
|
72
|
+
" Delete referenced content?"),
|
|
73
|
+
react_1.default.createElement("p", null, "You are deleting content referenced elsewhere in the document:"),
|
|
74
|
+
react_1.default.createElement(ScrolableItems, null, xrefs.map((group, i) => (react_1.default.createElement(XrefGroupDisplay, { key: i, group: group, selectAndScrollTo: selectAndScrollTo })))),
|
|
75
|
+
react_1.default.createElement(Actions, null,
|
|
76
|
+
react_1.default.createElement(style_guide_1.TertiaryButton, { type: "button", onClick: () => handleClose() }, "Cancel"),
|
|
77
|
+
react_1.default.createElement(style_guide_1.PrimaryButton, { "$danger": true, type: "button", onClick: () => {
|
|
78
|
+
onConfirm();
|
|
79
|
+
setIsOpen(false);
|
|
80
|
+
} }, "Delete & remove citation"))))));
|
|
81
|
+
};
|
|
82
|
+
exports.CrossRefWarningModal = CrossRefWarningModal;
|
|
83
|
+
const XrefGroupDisplay = ({ group, selectAndScrollTo }) => {
|
|
84
|
+
return (react_1.default.createElement("div", null,
|
|
85
|
+
react_1.default.createElement("h3", null, group.label),
|
|
86
|
+
react_1.default.createElement(ReferencesList, null, group.xrefs.map(([, pos], i) => {
|
|
87
|
+
return (react_1.default.createElement("li", { key: i },
|
|
88
|
+
react_1.default.createElement(style_guide_1.TextButton, { onClick: () => selectAndScrollTo(pos) }, `${(0, lodash_1.startCase)(pos.parent.type.name)} - ${pos.parent.textContent}`)));
|
|
89
|
+
}))));
|
|
90
|
+
};
|
|
91
|
+
const Container = (0, styled_components_1.default)(style_guide_1.ModalContainer) `
|
|
92
|
+
position: absolute;
|
|
93
|
+
top: 1rem;
|
|
94
|
+
left: 50%;
|
|
95
|
+
right: 0;
|
|
96
|
+
max-height: calc(50vh - 2rem);
|
|
97
|
+
min-height: 280px;
|
|
98
|
+
transform: translate(-50%, 0);
|
|
99
|
+
max-width: 480px;
|
|
100
|
+
transition:
|
|
101
|
+
top 0.2s,
|
|
102
|
+
transform 0.2s;
|
|
103
|
+
`;
|
|
104
|
+
const Modal = (0, styled_components_1.default)(style_guide_1.StyledModal) `
|
|
105
|
+
position: fixed;
|
|
106
|
+
top: 0;
|
|
107
|
+
left: 0;
|
|
108
|
+
width: 100%;
|
|
109
|
+
height: 100%;
|
|
110
|
+
z-index: 1100;
|
|
111
|
+
color: #6e6e6e;
|
|
112
|
+
margin: auto;
|
|
113
|
+
|
|
114
|
+
&.modal-bottom ${Container} {
|
|
115
|
+
top: calc(100% - 2rem);
|
|
116
|
+
transform: translate(-50%, -100%);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
&:after {
|
|
120
|
+
content: '';
|
|
121
|
+
display: block;
|
|
122
|
+
position: fixed;
|
|
123
|
+
z-index: -1;
|
|
124
|
+
left: 0;
|
|
125
|
+
top: 0;
|
|
126
|
+
right: 0;
|
|
127
|
+
bottom: 0;
|
|
128
|
+
background: rgba(0, 0, 0, 0.2);
|
|
129
|
+
}
|
|
130
|
+
h3 {
|
|
131
|
+
font-size: 16px;
|
|
132
|
+
margin: 0.5em 0;
|
|
133
|
+
}
|
|
134
|
+
p {
|
|
135
|
+
margin: 0.5em 0;
|
|
136
|
+
}
|
|
137
|
+
`;
|
|
138
|
+
const Body = styled_components_1.default.div `
|
|
139
|
+
margin: 1.5rem;
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-flow: column;
|
|
142
|
+
`;
|
|
143
|
+
const Title = styled_components_1.default.h2 `
|
|
144
|
+
font-size: 18px;
|
|
145
|
+
font-weight: 700;
|
|
146
|
+
line-height: 1.5;
|
|
147
|
+
margin: 0;
|
|
148
|
+
color: #353535;
|
|
149
|
+
svg {
|
|
150
|
+
vertical-align: text-top;
|
|
151
|
+
}
|
|
152
|
+
`;
|
|
153
|
+
const ReferencesList = styled_components_1.default.ul `
|
|
154
|
+
padding: 8px;
|
|
155
|
+
margin-left: 0;
|
|
156
|
+
list-style: none;
|
|
157
|
+
background: #f2f2f2;
|
|
158
|
+
border: 1px solid #e2e2e2;
|
|
159
|
+
border-radius: 3px;
|
|
160
|
+
|
|
161
|
+
${style_guide_1.TextButton} {
|
|
162
|
+
margin-left: 0;
|
|
163
|
+
text-decoration: underline;
|
|
164
|
+
&:hover {
|
|
165
|
+
text-decoration: none;
|
|
166
|
+
}
|
|
167
|
+
display: block;
|
|
168
|
+
max-width: 100%;
|
|
169
|
+
overflow: hidden;
|
|
170
|
+
color: #353535;
|
|
171
|
+
text-overflow: ellipsis;
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
174
|
+
const Actions = styled_components_1.default.footer `
|
|
175
|
+
text-align: right;
|
|
176
|
+
padding-top: 1rem;
|
|
177
|
+
`;
|
|
178
|
+
const ScrolableItems = styled_components_1.default.div `
|
|
179
|
+
max-height: 16vh;
|
|
180
|
+
min-height: 100px;
|
|
181
|
+
overflow-y: auto;
|
|
182
|
+
`;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* © 2026 Atypon Systems LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.openCrossRefWarningModal = void 0;
|
|
22
|
+
const editor_props_1 = require("../../plugins/editor-props");
|
|
23
|
+
const ReactSubView_1 = __importDefault(require("../../views/ReactSubView"));
|
|
24
|
+
const CrossRefWarningModal_1 = require("./CrossRefWarningModal");
|
|
25
|
+
const openCrossRefWarningModal = (view, xrefGroups, onConfirm, onClose, selectAndScrollTo) => {
|
|
26
|
+
const { state } = view;
|
|
27
|
+
const props = (0, editor_props_1.getEditorProps)(state);
|
|
28
|
+
const componentProps = {
|
|
29
|
+
xrefs: xrefGroups,
|
|
30
|
+
onConfirm,
|
|
31
|
+
onClose,
|
|
32
|
+
selectAndScrollTo,
|
|
33
|
+
};
|
|
34
|
+
const dialog = (0, ReactSubView_1.default)(props, CrossRefWarningModal_1.CrossRefWarningModal, componentProps, state.doc, () => 0, view);
|
|
35
|
+
document.body.appendChild(dialog);
|
|
36
|
+
return dialog;
|
|
37
|
+
};
|
|
38
|
+
exports.openCrossRefWarningModal = openCrossRefWarningModal;
|
|
@@ -16,12 +16,61 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const transform_1 = require("@manuscripts/transform");
|
|
19
|
+
const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
|
|
19
20
|
const lodash_1 = require("lodash");
|
|
20
21
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
21
22
|
const prosemirror_view_1 = require("prosemirror-view");
|
|
23
|
+
const openModal_1 = require("../components/cross-ref-check-modal/openModal");
|
|
22
24
|
const objects_1 = require("./objects");
|
|
25
|
+
let modalActive = false;
|
|
26
|
+
let modalElement = null;
|
|
23
27
|
exports.default = () => {
|
|
28
|
+
let view = null;
|
|
24
29
|
return new prosemirror_state_1.Plugin({
|
|
30
|
+
view(editorView) {
|
|
31
|
+
view = editorView;
|
|
32
|
+
return {
|
|
33
|
+
update(v) {
|
|
34
|
+
view = v;
|
|
35
|
+
},
|
|
36
|
+
destroy() {
|
|
37
|
+
view = null;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
filterTransaction(tr, state) {
|
|
42
|
+
if (!view ||
|
|
43
|
+
!tr.docChanged ||
|
|
44
|
+
tr.getMeta(track_changes_plugin_1.trackChangesPluginKey) ||
|
|
45
|
+
tr.getMeta('addToHistory') === false) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (modalActive) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const targets = objects_1.objectsKey.getState(state);
|
|
52
|
+
const xrefGroups = createXrefGroups(targets, state.doc, tr.doc);
|
|
53
|
+
if (xrefGroups.length === 0) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
modalActive = true;
|
|
57
|
+
const cleanup = () => {
|
|
58
|
+
modalActive = false;
|
|
59
|
+
if (modalElement) {
|
|
60
|
+
modalElement.classList.remove('modal-bottom');
|
|
61
|
+
modalElement.remove();
|
|
62
|
+
modalElement = null;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const deletedIds = new Set(xrefGroups.map((g) => g.referenced.attrs.id));
|
|
66
|
+
const onClose = () => {
|
|
67
|
+
cleanup();
|
|
68
|
+
};
|
|
69
|
+
if (view) {
|
|
70
|
+
modalElement = (0, openModal_1.openCrossRefWarningModal)(view, xrefGroups, onConfirmCreator(view, cleanup, deletedIds, tr), onClose, selectAndScrollToCreator(view));
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
},
|
|
25
74
|
state: {
|
|
26
75
|
init() {
|
|
27
76
|
return prosemirror_view_1.DecorationSet.empty;
|
|
@@ -55,3 +104,114 @@ function createDecorations(doc) {
|
|
|
55
104
|
});
|
|
56
105
|
return decorations;
|
|
57
106
|
}
|
|
107
|
+
function createXrefGroups(targets, stateDoc, resultDoc) {
|
|
108
|
+
const newIds = new Set();
|
|
109
|
+
const xrefRids = new Set();
|
|
110
|
+
const xrefGroups = [];
|
|
111
|
+
resultDoc.descendants((node) => {
|
|
112
|
+
if (node.attrs.id) {
|
|
113
|
+
newIds.add(node.attrs.id);
|
|
114
|
+
}
|
|
115
|
+
if (node.type === transform_1.schema.nodes.cross_reference) {
|
|
116
|
+
for (const rid of node.attrs.rids) {
|
|
117
|
+
xrefRids.add(rid);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
const orphanedRids = new Set();
|
|
122
|
+
for (const rid of xrefRids) {
|
|
123
|
+
if (!newIds.has(rid)) {
|
|
124
|
+
orphanedRids.add(rid);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (orphanedRids.size === 0) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
const referencedNodes = new Map();
|
|
131
|
+
const xrefsByRid = new Map();
|
|
132
|
+
stateDoc.descendants((node, pos) => {
|
|
133
|
+
const id = node.attrs.id;
|
|
134
|
+
if (id && orphanedRids.has(id)) {
|
|
135
|
+
referencedNodes.set(id, node);
|
|
136
|
+
}
|
|
137
|
+
if (node.type === transform_1.schema.nodes.cross_reference) {
|
|
138
|
+
for (const rid of node.attrs.rids) {
|
|
139
|
+
if (orphanedRids.has(rid)) {
|
|
140
|
+
let entries = xrefsByRid.get(rid);
|
|
141
|
+
if (!entries) {
|
|
142
|
+
entries = [];
|
|
143
|
+
xrefsByRid.set(rid, entries);
|
|
144
|
+
}
|
|
145
|
+
entries.push([node, stateDoc.resolve(pos)]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
for (const [id, referenced] of referencedNodes) {
|
|
151
|
+
const xrefs = xrefsByRid.get(id);
|
|
152
|
+
if (xrefs?.length) {
|
|
153
|
+
const label = targets.get(referenced.attrs.id)?.label || '';
|
|
154
|
+
xrefGroups.push({ referenced, label, xrefs });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return xrefGroups;
|
|
158
|
+
}
|
|
159
|
+
const onConfirmCreator = (view, cleanup, deletedIds, tr) => () => {
|
|
160
|
+
cleanup();
|
|
161
|
+
if (!view) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const newTr = view.state.tr;
|
|
165
|
+
for (const step of tr.steps) {
|
|
166
|
+
const result = step.apply(newTr.doc);
|
|
167
|
+
if (result.failed) {
|
|
168
|
+
console.warn('Cross-ref deletion warning: could not replay step —', result.failed);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
newTr.step(step);
|
|
172
|
+
}
|
|
173
|
+
const xrefPositions = [];
|
|
174
|
+
newTr.doc.descendants((node, pos) => {
|
|
175
|
+
if (node.type === transform_1.schema.nodes.cross_reference) {
|
|
176
|
+
const rids = node.attrs.rids;
|
|
177
|
+
if (rids.some((rid) => deletedIds.has(rid))) {
|
|
178
|
+
xrefPositions.push({ from: pos, to: pos + node.nodeSize });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
for (let i = xrefPositions.length - 1; i >= 0; i--) {
|
|
183
|
+
const { from, to } = xrefPositions[i];
|
|
184
|
+
newTr.delete(from, to);
|
|
185
|
+
}
|
|
186
|
+
view.dispatch(newTr);
|
|
187
|
+
};
|
|
188
|
+
const selectAndScrollToCreator = (view) => ($pos) => {
|
|
189
|
+
if (!view) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const selTr = view.state.tr;
|
|
193
|
+
selTr.setSelection(prosemirror_state_1.NodeSelection.create(view.state.doc, $pos.pos));
|
|
194
|
+
view.focus();
|
|
195
|
+
view.dispatch(selTr);
|
|
196
|
+
let scrollable = view.dom.parentElement;
|
|
197
|
+
while (scrollable != null &&
|
|
198
|
+
scrollable.scrollHeight <= scrollable.clientHeight) {
|
|
199
|
+
scrollable = scrollable.parentElement;
|
|
200
|
+
}
|
|
201
|
+
if (!scrollable) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const coords = view.coordsAtPos($pos.pos);
|
|
205
|
+
const containerRect = scrollable.getBoundingClientRect();
|
|
206
|
+
const offsetInContainer = coords.top - containerRect.top + scrollable.scrollTop;
|
|
207
|
+
const containerHeight = scrollable.clientHeight;
|
|
208
|
+
const scrollTo = offsetInContainer - containerHeight * 0.75;
|
|
209
|
+
if (scrollTo < 0) {
|
|
210
|
+
modalElement?.classList.add('modal-bottom');
|
|
211
|
+
scrollable.scrollTo({ top: 0, behavior: 'smooth' });
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
modalElement?.classList.remove('modal-bottom');
|
|
215
|
+
scrollable.scrollTo({ top: scrollTo, behavior: 'smooth' });
|
|
216
|
+
}
|
|
217
|
+
};
|
package/dist/cjs/versions.js
CHANGED
|
@@ -74,4 +74,5 @@ export const openAuthorsAndAffiliationsModals = (pos, view, initialModal) => {
|
|
|
74
74
|
const dialog = ReactSubView(props, AuthorsAndAffiliationsModals, componentProps, state.doc, () => pos, view);
|
|
75
75
|
view.focus();
|
|
76
76
|
document.body.appendChild(dialog);
|
|
77
|
+
return dialog;
|
|
77
78
|
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import React, { useState } from 'react';
|
|
17
|
+
import { AttentionOrangeIcon, CloseButton, ModalContainer, ModalHeader, PrimaryButton, StyledModal, TertiaryButton, TextButton, } from '@manuscripts/style-guide';
|
|
18
|
+
import { startCase } from 'lodash';
|
|
19
|
+
import styled from 'styled-components';
|
|
20
|
+
export const CrossRefWarningModal = ({ onClose, xrefs, onConfirm, selectAndScrollTo }) => {
|
|
21
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
22
|
+
const handleClose = () => {
|
|
23
|
+
setIsOpen(false);
|
|
24
|
+
onClose();
|
|
25
|
+
};
|
|
26
|
+
return (React.createElement(Modal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: false, hideOverlay: true },
|
|
27
|
+
React.createElement(Container, { "data-cy": "cross-reference-warning-modal" },
|
|
28
|
+
React.createElement(ModalHeader, null,
|
|
29
|
+
React.createElement(CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
|
|
30
|
+
React.createElement(Body, null,
|
|
31
|
+
React.createElement(Title, null,
|
|
32
|
+
React.createElement(AttentionOrangeIcon, { width: 24, height: 22 }),
|
|
33
|
+
" Delete referenced content?"),
|
|
34
|
+
React.createElement("p", null, "You are deleting content referenced elsewhere in the document:"),
|
|
35
|
+
React.createElement(ScrolableItems, null, xrefs.map((group, i) => (React.createElement(XrefGroupDisplay, { key: i, group: group, selectAndScrollTo: selectAndScrollTo })))),
|
|
36
|
+
React.createElement(Actions, null,
|
|
37
|
+
React.createElement(TertiaryButton, { type: "button", onClick: () => handleClose() }, "Cancel"),
|
|
38
|
+
React.createElement(PrimaryButton, { "$danger": true, type: "button", onClick: () => {
|
|
39
|
+
onConfirm();
|
|
40
|
+
setIsOpen(false);
|
|
41
|
+
} }, "Delete & remove citation"))))));
|
|
42
|
+
};
|
|
43
|
+
const XrefGroupDisplay = ({ group, selectAndScrollTo }) => {
|
|
44
|
+
return (React.createElement("div", null,
|
|
45
|
+
React.createElement("h3", null, group.label),
|
|
46
|
+
React.createElement(ReferencesList, null, group.xrefs.map(([, pos], i) => {
|
|
47
|
+
return (React.createElement("li", { key: i },
|
|
48
|
+
React.createElement(TextButton, { onClick: () => selectAndScrollTo(pos) }, `${startCase(pos.parent.type.name)} - ${pos.parent.textContent}`)));
|
|
49
|
+
}))));
|
|
50
|
+
};
|
|
51
|
+
const Container = styled(ModalContainer) `
|
|
52
|
+
position: absolute;
|
|
53
|
+
top: 1rem;
|
|
54
|
+
left: 50%;
|
|
55
|
+
right: 0;
|
|
56
|
+
max-height: calc(50vh - 2rem);
|
|
57
|
+
min-height: 280px;
|
|
58
|
+
transform: translate(-50%, 0);
|
|
59
|
+
max-width: 480px;
|
|
60
|
+
transition:
|
|
61
|
+
top 0.2s,
|
|
62
|
+
transform 0.2s;
|
|
63
|
+
`;
|
|
64
|
+
const Modal = styled(StyledModal) `
|
|
65
|
+
position: fixed;
|
|
66
|
+
top: 0;
|
|
67
|
+
left: 0;
|
|
68
|
+
width: 100%;
|
|
69
|
+
height: 100%;
|
|
70
|
+
z-index: 1100;
|
|
71
|
+
color: #6e6e6e;
|
|
72
|
+
margin: auto;
|
|
73
|
+
|
|
74
|
+
&.modal-bottom ${Container} {
|
|
75
|
+
top: calc(100% - 2rem);
|
|
76
|
+
transform: translate(-50%, -100%);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&:after {
|
|
80
|
+
content: '';
|
|
81
|
+
display: block;
|
|
82
|
+
position: fixed;
|
|
83
|
+
z-index: -1;
|
|
84
|
+
left: 0;
|
|
85
|
+
top: 0;
|
|
86
|
+
right: 0;
|
|
87
|
+
bottom: 0;
|
|
88
|
+
background: rgba(0, 0, 0, 0.2);
|
|
89
|
+
}
|
|
90
|
+
h3 {
|
|
91
|
+
font-size: 16px;
|
|
92
|
+
margin: 0.5em 0;
|
|
93
|
+
}
|
|
94
|
+
p {
|
|
95
|
+
margin: 0.5em 0;
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
const Body = styled.div `
|
|
99
|
+
margin: 1.5rem;
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-flow: column;
|
|
102
|
+
`;
|
|
103
|
+
const Title = styled.h2 `
|
|
104
|
+
font-size: 18px;
|
|
105
|
+
font-weight: 700;
|
|
106
|
+
line-height: 1.5;
|
|
107
|
+
margin: 0;
|
|
108
|
+
color: #353535;
|
|
109
|
+
svg {
|
|
110
|
+
vertical-align: text-top;
|
|
111
|
+
}
|
|
112
|
+
`;
|
|
113
|
+
const ReferencesList = styled.ul `
|
|
114
|
+
padding: 8px;
|
|
115
|
+
margin-left: 0;
|
|
116
|
+
list-style: none;
|
|
117
|
+
background: #f2f2f2;
|
|
118
|
+
border: 1px solid #e2e2e2;
|
|
119
|
+
border-radius: 3px;
|
|
120
|
+
|
|
121
|
+
${TextButton} {
|
|
122
|
+
margin-left: 0;
|
|
123
|
+
text-decoration: underline;
|
|
124
|
+
&:hover {
|
|
125
|
+
text-decoration: none;
|
|
126
|
+
}
|
|
127
|
+
display: block;
|
|
128
|
+
max-width: 100%;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
color: #353535;
|
|
131
|
+
text-overflow: ellipsis;
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
const Actions = styled.footer `
|
|
135
|
+
text-align: right;
|
|
136
|
+
padding-top: 1rem;
|
|
137
|
+
`;
|
|
138
|
+
const ScrolableItems = styled.div `
|
|
139
|
+
max-height: 16vh;
|
|
140
|
+
min-height: 100px;
|
|
141
|
+
overflow-y: auto;
|
|
142
|
+
`;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { getEditorProps } from '../../plugins/editor-props';
|
|
17
|
+
import ReactSubView from '../../views/ReactSubView';
|
|
18
|
+
import { CrossRefWarningModal } from './CrossRefWarningModal';
|
|
19
|
+
export const openCrossRefWarningModal = (view, xrefGroups, onConfirm, onClose, selectAndScrollTo) => {
|
|
20
|
+
const { state } = view;
|
|
21
|
+
const props = getEditorProps(state);
|
|
22
|
+
const componentProps = {
|
|
23
|
+
xrefs: xrefGroups,
|
|
24
|
+
onConfirm,
|
|
25
|
+
onClose,
|
|
26
|
+
selectAndScrollTo,
|
|
27
|
+
};
|
|
28
|
+
const dialog = ReactSubView(props, CrossRefWarningModal, componentProps, state.doc, () => 0, view);
|
|
29
|
+
document.body.appendChild(dialog);
|
|
30
|
+
return dialog;
|
|
31
|
+
};
|