@manuscripts/body-editor 3.5.12 → 3.5.13
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 +2 -1
- package/dist/cjs/lib/media.js +21 -8
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/embed.js +3 -3
- package/dist/cjs/views/figure_editable.js +1 -1
- package/dist/cjs/views/image_element.js +106 -56
- package/dist/es/icons.js +2 -1
- package/dist/es/lib/media.js +20 -7
- package/dist/es/versions.js +1 -1
- package/dist/es/views/embed.js +4 -4
- package/dist/es/views/figure_editable.js +2 -2
- package/dist/es/views/image_element.js +106 -23
- package/dist/types/icons.d.ts +1 -0
- package/dist/types/lib/media.d.ts +6 -1
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/image_element.d.ts +8 -0
- package/package.json +1 -1
- package/styles/AdvancedEditor.css +118 -1
- package/dist/cjs/components/DragAndDropUploader.js +0 -148
- package/dist/cjs/components/views/ExtLinkEditor.js +0 -137
- package/dist/cjs/views/figure_uploader.js +0 -17
- package/dist/es/components/DragAndDropUploader.js +0 -108
- package/dist/es/components/views/ExtLinkEditor.js +0 -97
- package/dist/es/views/figure_uploader.js +0 -13
- package/dist/types/components/DragAndDropUploader.d.ts +0 -9
- package/dist/types/components/views/ExtLinkEditor.d.ts +0 -13
- package/dist/types/views/figure_uploader.d.ts +0 -2
|
@@ -29,6 +29,8 @@ export declare class ImageElementView extends BlockView<Trackable<ImageElementNo
|
|
|
29
29
|
private figurePosition;
|
|
30
30
|
private isEditingExtLink;
|
|
31
31
|
ignoreMutation: () => boolean;
|
|
32
|
+
upload: (file: File) => Promise<void>;
|
|
33
|
+
initialise(): void;
|
|
32
34
|
createDOM(): void;
|
|
33
35
|
createElement(): void;
|
|
34
36
|
updateContents(): void;
|
|
@@ -38,6 +40,12 @@ export declare class ImageElementView extends BlockView<Trackable<ImageElementNo
|
|
|
38
40
|
private getAllFigures;
|
|
39
41
|
private showPositionMenu;
|
|
40
42
|
private updateAllFiguresPosition;
|
|
43
|
+
private removeExtLink;
|
|
44
|
+
private setExtLink;
|
|
45
|
+
private setIsEditingExtLink;
|
|
46
|
+
private createDnDPlaceholder;
|
|
47
|
+
private createAddLinkButton;
|
|
48
|
+
private createLinkedFile;
|
|
41
49
|
private addExternalLinkedFileEditor;
|
|
42
50
|
}
|
|
43
51
|
declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch) => import("../types").NodeViewCreator<ImageElementView>;
|
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.5.
|
|
4
|
+
"version": "3.5.13",
|
|
5
5
|
"repository": "github:Atypon-OpenSource/manuscripts-body-editor",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "dist/cjs",
|
|
@@ -254,6 +254,11 @@
|
|
|
254
254
|
white-space: normal;
|
|
255
255
|
font-size: 14px;
|
|
256
256
|
}
|
|
257
|
+
|
|
258
|
+
.ProseMirror .figure.placeholder p {
|
|
259
|
+
margin: 0;
|
|
260
|
+
}
|
|
261
|
+
|
|
257
262
|
.ProseMirror .block-embed .media-preview .placeholder {
|
|
258
263
|
padding: 16px 32px;
|
|
259
264
|
}
|
|
@@ -1553,6 +1558,56 @@ th:hover > .table-context-menu-button,
|
|
|
1553
1558
|
|
|
1554
1559
|
.ProseMirror .ext-link-editor-container {
|
|
1555
1560
|
position: static;
|
|
1561
|
+
width: 100%;
|
|
1562
|
+
}
|
|
1563
|
+
.ProseMirror .ext-link-editor-placeholder-container {
|
|
1564
|
+
font-size: 0;
|
|
1565
|
+
}
|
|
1566
|
+
.ProseMirror .ext-link-editor-placeholder-container {
|
|
1567
|
+
position: relative;
|
|
1568
|
+
font-size: initial;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
.ProseMirror .ext-link-editor-placeholder-container .placeholder {
|
|
1572
|
+
position: relative;
|
|
1573
|
+
box-sizing: content-box;
|
|
1574
|
+
max-width: 100%;
|
|
1575
|
+
min-height: 0;
|
|
1576
|
+
padding: 16px 0;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
.ProseMirror .ext-link-editor-container .close-button {
|
|
1580
|
+
border: 1px solid #f2f2f2;
|
|
1581
|
+
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.12);
|
|
1582
|
+
background-color: #ffffff;
|
|
1583
|
+
|
|
1584
|
+
position: absolute;
|
|
1585
|
+
top: -8px;
|
|
1586
|
+
right: -8px;
|
|
1587
|
+
}
|
|
1588
|
+
.ProseMirror .ext-link-editor-container .linked-file-info {
|
|
1589
|
+
display: flex;
|
|
1590
|
+
flex-direction: row;
|
|
1591
|
+
align-items: center;
|
|
1592
|
+
justify-content: space-between;
|
|
1593
|
+
padding: 4px 8px;
|
|
1594
|
+
background-color: #f2f2f2;
|
|
1595
|
+
color: #353535;
|
|
1596
|
+
border: 1px solid #e2e2e2;
|
|
1597
|
+
border-radius: 8px;
|
|
1598
|
+
}
|
|
1599
|
+
.ProseMirror .ext-link-editor-container .linked-file-info p {
|
|
1600
|
+
display: flex;
|
|
1601
|
+
align-items: center;
|
|
1602
|
+
justify-content: flex-start;
|
|
1603
|
+
gap: 8px;
|
|
1604
|
+
|
|
1605
|
+
font-family: Lato, sans-serif;
|
|
1606
|
+
font-weight: 400;
|
|
1607
|
+
font-size: 16px;
|
|
1608
|
+
}
|
|
1609
|
+
.ProseMirror .ext-link-editor-container .linked-file-info .icon-button {
|
|
1610
|
+
margin-right: 8px;
|
|
1556
1611
|
}
|
|
1557
1612
|
|
|
1558
1613
|
.ProseMirror .accessibility_element_label {
|
|
@@ -1801,6 +1856,68 @@ th:hover > .table-context-menu-button,
|
|
|
1801
1856
|
display: none;
|
|
1802
1857
|
}
|
|
1803
1858
|
|
|
1859
|
+
.ProseMirror .icon-button {
|
|
1860
|
+
display: flex;
|
|
1861
|
+
align-items: center;
|
|
1862
|
+
gap: 8px;
|
|
1863
|
+
cursor: pointer;
|
|
1864
|
+
border-radius: 4px;
|
|
1865
|
+
color: #353535;
|
|
1866
|
+
font-size: 16px;
|
|
1867
|
+
line-height: 24px;
|
|
1868
|
+
padding: 0;
|
|
1869
|
+
|
|
1870
|
+
background: transparent;
|
|
1871
|
+
border: 1px solid transparent;
|
|
1872
|
+
border-radius: 4px;
|
|
1873
|
+
cursor: pointer;
|
|
1874
|
+
display: inline-flex;
|
|
1875
|
+
flex-shrink: 0;
|
|
1876
|
+
justify-content: center;
|
|
1877
|
+
outline: none;
|
|
1878
|
+
transition: border 0.1s, color 0.1s, background-color 0.1s, color 0.1s,
|
|
1879
|
+
filter 0.1s;
|
|
1880
|
+
vertical-align: middle;
|
|
1881
|
+
white-space: nowrap;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
.ProseMirror .icon-button path,
|
|
1885
|
+
.ProseMirror .icon-button rect {
|
|
1886
|
+
fill: #353535 !important;
|
|
1887
|
+
}
|
|
1888
|
+
.ProseMirror .icon-button:hover path,
|
|
1889
|
+
.ProseMirror .icon-button:hover rect {
|
|
1890
|
+
fill: #1a9bc7 !important;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
.ProseMirror .close-button {
|
|
1894
|
+
cursor: pointer;
|
|
1895
|
+
box-shadow: none;
|
|
1896
|
+
text-indent: -99999px;
|
|
1897
|
+
z-index: 2;
|
|
1898
|
+
|
|
1899
|
+
width: 26px;
|
|
1900
|
+
height: 26px;
|
|
1901
|
+
border-radius: 50%;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
.ProseMirror .close-button::before,
|
|
1905
|
+
.ProseMirror .close-button::after {
|
|
1906
|
+
background-color: #6e6e6e;
|
|
1907
|
+
border-radius: 2px;
|
|
1908
|
+
content: ' ';
|
|
1909
|
+
display: block;
|
|
1910
|
+
height: 14px;
|
|
1911
|
+
transform: rotate(-45deg);
|
|
1912
|
+
width: 2px;
|
|
1913
|
+
position: absolute;
|
|
1914
|
+
top: calc(50% - 7px);
|
|
1915
|
+
left: calc(50% - 1px);
|
|
1916
|
+
}
|
|
1917
|
+
.ProseMirror .close-button::after {
|
|
1918
|
+
transform: rotate(45deg);
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1804
1921
|
/* Attachment styles */
|
|
1805
1922
|
.attachments-container .attachment-item {
|
|
1806
1923
|
border: 1px solid #ddd;
|
|
@@ -1866,4 +1983,4 @@ th:hover > .table-context-menu-button,
|
|
|
1866
1983
|
|
|
1867
1984
|
.ProseMirror a.link:empty::before {
|
|
1868
1985
|
content: "\00a0";
|
|
1869
|
-
}
|
|
1986
|
+
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.DragAndDropUploader = void 0;
|
|
40
|
-
const react_1 = __importStar(require("react"));
|
|
41
|
-
const styled_components_1 = __importDefault(require("styled-components"));
|
|
42
|
-
const DragAndDropUploader = ({ upload, onUploadError, allowedFileTypes, maxFileSizeMB, }) => {
|
|
43
|
-
const [isUploading, setIsUploading] = (0, react_1.useState)(false);
|
|
44
|
-
const fileInputRef = (0, react_1.useRef)(null);
|
|
45
|
-
const validateFile = (file) => {
|
|
46
|
-
if (!file) {
|
|
47
|
-
onUploadError('No file selected.');
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
if (allowedFileTypes && allowedFileTypes.length > 0) {
|
|
51
|
-
if (!allowedFileTypes.includes(file.type)) {
|
|
52
|
-
onUploadError(`Invalid file type. Allowed types: ${allowedFileTypes.join(', ')}`);
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (maxFileSizeMB && file.size > maxFileSizeMB * 1024 * 1024) {
|
|
57
|
-
onUploadError(`File size exceeds limit of ${maxFileSizeMB} MB.`);
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
return true;
|
|
61
|
-
};
|
|
62
|
-
const processFiles = async (files) => {
|
|
63
|
-
if (files && files.length > 0) {
|
|
64
|
-
const file = files[0];
|
|
65
|
-
if (validateFile(file)) {
|
|
66
|
-
try {
|
|
67
|
-
setIsUploading(true);
|
|
68
|
-
await upload(file);
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
onUploadError('Upload failed. Please try again.');
|
|
72
|
-
console.error('Upload error:', error);
|
|
73
|
-
}
|
|
74
|
-
finally {
|
|
75
|
-
setIsUploading(false);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
onUploadError('No file selected or dropped.');
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
const handleDragOver = (e) => {
|
|
84
|
-
if (e.dataTransfer && e.dataTransfer.items) {
|
|
85
|
-
for (const item of e.dataTransfer.items) {
|
|
86
|
-
if (item.kind === 'file' && item.type.startsWith('image/')) {
|
|
87
|
-
e.preventDefault();
|
|
88
|
-
e.dataTransfer.dropEffect = 'copy';
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
const handleDrop = async (e) => {
|
|
94
|
-
e.preventDefault();
|
|
95
|
-
await processFiles(e.dataTransfer.files);
|
|
96
|
-
};
|
|
97
|
-
const handleFileChange = async (e) => {
|
|
98
|
-
await processFiles(e.target.files);
|
|
99
|
-
};
|
|
100
|
-
const handleAreaClick = (event) => {
|
|
101
|
-
const target = event.target;
|
|
102
|
-
if (target.dataset && target.dataset.action) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
fileInputRef.current?.click();
|
|
106
|
-
};
|
|
107
|
-
return (react_1.default.createElement(DragAndDropContainer, { onDragOver: handleDragOver, onDrop: !isUploading ? handleDrop : undefined, onClick: !isUploading ? handleAreaClick : undefined, tabIndex: isUploading ? -1 : 0, "aria-label": "Drag and drop area for file upload, or click to open file dialog.", role: "button", onKeyDown: (e) => {
|
|
108
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
109
|
-
e.preventDefault();
|
|
110
|
-
fileInputRef.current?.click();
|
|
111
|
-
}
|
|
112
|
-
} },
|
|
113
|
-
react_1.default.createElement("input", { type: "file", ref: fileInputRef, onChange: handleFileChange, "aria-hidden": "true" }),
|
|
114
|
-
react_1.default.createElement("p", null,
|
|
115
|
-
"Drag or click here to upload a file to link",
|
|
116
|
-
react_1.default.createElement("br", null),
|
|
117
|
-
"or drag items here from the file",
|
|
118
|
-
' ',
|
|
119
|
-
react_1.default.createElement("span", { "data-action": "open-other-files" }, "'Other files'"),
|
|
120
|
-
" in the inspector.")));
|
|
121
|
-
};
|
|
122
|
-
exports.DragAndDropUploader = DragAndDropUploader;
|
|
123
|
-
const DragAndDropContainer = styled_components_1.default.div `
|
|
124
|
-
display: flex;
|
|
125
|
-
flex-direction: column;
|
|
126
|
-
align-items: center;
|
|
127
|
-
justify-content: center;
|
|
128
|
-
padding: 16px;
|
|
129
|
-
border: 1px dashed ${(props) => props.theme.colors.border.secondary};
|
|
130
|
-
border-radius: 8px;
|
|
131
|
-
background-color: ${(props) => props.theme.colors.background.secondary};
|
|
132
|
-
color: ${(props) => props.theme.colors.text.primary};
|
|
133
|
-
font-size: ${(props) => props.theme.font.size.normal};
|
|
134
|
-
|
|
135
|
-
input[type='file'] {
|
|
136
|
-
display: none;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
p {
|
|
140
|
-
margin: 0;
|
|
141
|
-
font-size: 14px;
|
|
142
|
-
text-align: center;
|
|
143
|
-
}
|
|
144
|
-
span {
|
|
145
|
-
text-decoration: underline;
|
|
146
|
-
cursor: pointer;
|
|
147
|
-
}
|
|
148
|
-
`;
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.ExtLinkEditor = void 0;
|
|
40
|
-
const style_guide_1 = require("@manuscripts/style-guide");
|
|
41
|
-
const react_1 = __importStar(require("react"));
|
|
42
|
-
const styled_components_1 = __importDefault(require("styled-components"));
|
|
43
|
-
const DragAndDropUploader_1 = require("../DragAndDropUploader");
|
|
44
|
-
const ExtLinkEditor = ({ node, nodePos, view, editorProps, isEditing, setIsEditing, }) => {
|
|
45
|
-
const [uploadError, setUploadError] = (0, react_1.useState)(null);
|
|
46
|
-
const fileManagement = editorProps.fileManagement;
|
|
47
|
-
const extLink = node.attrs.extLink;
|
|
48
|
-
const files = editorProps.getFiles();
|
|
49
|
-
const file = extLink ? files.find((f) => f.id === extLink) : undefined;
|
|
50
|
-
const onUpdate = (newAttrs) => {
|
|
51
|
-
const tr = view.state.tr.setNodeMarkup(nodePos, undefined, {
|
|
52
|
-
...node.attrs,
|
|
53
|
-
...newAttrs,
|
|
54
|
-
});
|
|
55
|
-
view.dispatch(tr);
|
|
56
|
-
};
|
|
57
|
-
const handleFileUpload = async (file) => {
|
|
58
|
-
setUploadError(null);
|
|
59
|
-
const result = await fileManagement.upload(file);
|
|
60
|
-
if (!result) {
|
|
61
|
-
handleUploadError('File upload failed');
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
setIsEditing(false);
|
|
65
|
-
onUpdate({ extLink: result.id });
|
|
66
|
-
};
|
|
67
|
-
const handleUploadError = (message) => {
|
|
68
|
-
setUploadError(message);
|
|
69
|
-
};
|
|
70
|
-
const handleRemove = () => {
|
|
71
|
-
setUploadError(null);
|
|
72
|
-
onUpdate({ extLink: '' });
|
|
73
|
-
setIsEditing(false);
|
|
74
|
-
};
|
|
75
|
-
return (react_1.default.createElement("div", null,
|
|
76
|
-
!isEditing && !extLink && (react_1.default.createElement(style_guide_1.IconTextButton, { onClick: () => setIsEditing(true), "aria-label": "Add linked file" },
|
|
77
|
-
react_1.default.createElement(style_guide_1.LinkIcon, null),
|
|
78
|
-
"Add link")),
|
|
79
|
-
isEditing && !extLink && (react_1.default.createElement("div", null,
|
|
80
|
-
react_1.default.createElement(ExtLinkEditorLabel, null, "Link"),
|
|
81
|
-
react_1.default.createElement(ExtLinkEditorContainer, null,
|
|
82
|
-
react_1.default.createElement(DragAndDropUploader_1.DragAndDropUploader, { upload: handleFileUpload, onUploadError: handleUploadError }),
|
|
83
|
-
react_1.default.createElement(CloseUploaderButton, { onClick: () => setIsEditing(false) })))),
|
|
84
|
-
extLink && (react_1.default.createElement(LinkedFileInfoBox, null,
|
|
85
|
-
react_1.default.createElement("p", null,
|
|
86
|
-
react_1.default.createElement(style_guide_1.LinkIcon, null),
|
|
87
|
-
file ? file.name : 'File does not exist.'),
|
|
88
|
-
react_1.default.createElement(style_guide_1.IconButton, { onClick: handleRemove, "aria-label": "Remove linked file" },
|
|
89
|
-
react_1.default.createElement(style_guide_1.DeleteIcon, null)))),
|
|
90
|
-
uploadError && (react_1.default.createElement("div", null,
|
|
91
|
-
react_1.default.createElement("p", { className: "font-semibold" }, "Error:"),
|
|
92
|
-
react_1.default.createElement("p", null, uploadError)))));
|
|
93
|
-
};
|
|
94
|
-
exports.ExtLinkEditor = ExtLinkEditor;
|
|
95
|
-
const ExtLinkEditorLabel = styled_components_1.default.div `
|
|
96
|
-
color: var(--label-color);
|
|
97
|
-
font-size: 18px;
|
|
98
|
-
font-style: normal;
|
|
99
|
-
font-weight: 400;
|
|
100
|
-
line-height: 24px;
|
|
101
|
-
letter-spacing: -0.369px;
|
|
102
|
-
margin-top: 12px;
|
|
103
|
-
cursor: pointer;
|
|
104
|
-
`;
|
|
105
|
-
const ExtLinkEditorContainer = styled_components_1.default.div `
|
|
106
|
-
position: relative;
|
|
107
|
-
`;
|
|
108
|
-
const LinkedFileInfoBox = styled_components_1.default.div `
|
|
109
|
-
display: flex;
|
|
110
|
-
flex-direction: row;
|
|
111
|
-
align-items: center;
|
|
112
|
-
justify-content: space-between;
|
|
113
|
-
padding: 4px 8px;
|
|
114
|
-
background-color: ${(props) => props.theme.colors.background.secondary};
|
|
115
|
-
color: ${(props) => props.theme.colors.text.primary};
|
|
116
|
-
border: 1px solid ${(props) => props.theme.colors.border.secondary};
|
|
117
|
-
border-radius: 8px;
|
|
118
|
-
|
|
119
|
-
p {
|
|
120
|
-
display: flex;
|
|
121
|
-
align-items: center;
|
|
122
|
-
justify-content: flex-start;
|
|
123
|
-
gap: 8px;
|
|
124
|
-
|
|
125
|
-
font-family: ${(props) => props.theme.font.family.sans};
|
|
126
|
-
font-weight: ${(props) => props.theme.font.weight.normal};
|
|
127
|
-
font-size: ${(props) => props.theme.font.size.medium};
|
|
128
|
-
}
|
|
129
|
-
`;
|
|
130
|
-
const CloseUploaderButton = (0, styled_components_1.default)(style_guide_1.CloseButton) `
|
|
131
|
-
border: 1px solid ${(props) => props.theme.colors.border.tertiary};
|
|
132
|
-
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.12);
|
|
133
|
-
|
|
134
|
-
position: absolute;
|
|
135
|
-
top: -8px;
|
|
136
|
-
right: -8px;
|
|
137
|
-
`;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.figureUploader = void 0;
|
|
4
|
-
const figureUploader = (handler) => {
|
|
5
|
-
const handleFileChange = async (e) => {
|
|
6
|
-
const target = e.target;
|
|
7
|
-
if (target && target.files && target.files.length) {
|
|
8
|
-
await handler(target.files[0]);
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
const input = document.createElement('input');
|
|
12
|
-
input.accept = 'image/*';
|
|
13
|
-
input.type = 'file';
|
|
14
|
-
input.addEventListener('change', handleFileChange);
|
|
15
|
-
return () => input.click();
|
|
16
|
-
};
|
|
17
|
-
exports.figureUploader = figureUploader;
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import React, { useRef, useState, } from 'react';
|
|
2
|
-
import styled from 'styled-components';
|
|
3
|
-
export const DragAndDropUploader = ({ upload, onUploadError, allowedFileTypes, maxFileSizeMB, }) => {
|
|
4
|
-
const [isUploading, setIsUploading] = useState(false);
|
|
5
|
-
const fileInputRef = useRef(null);
|
|
6
|
-
const validateFile = (file) => {
|
|
7
|
-
if (!file) {
|
|
8
|
-
onUploadError('No file selected.');
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
if (allowedFileTypes && allowedFileTypes.length > 0) {
|
|
12
|
-
if (!allowedFileTypes.includes(file.type)) {
|
|
13
|
-
onUploadError(`Invalid file type. Allowed types: ${allowedFileTypes.join(', ')}`);
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
if (maxFileSizeMB && file.size > maxFileSizeMB * 1024 * 1024) {
|
|
18
|
-
onUploadError(`File size exceeds limit of ${maxFileSizeMB} MB.`);
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
return true;
|
|
22
|
-
};
|
|
23
|
-
const processFiles = async (files) => {
|
|
24
|
-
if (files && files.length > 0) {
|
|
25
|
-
const file = files[0];
|
|
26
|
-
if (validateFile(file)) {
|
|
27
|
-
try {
|
|
28
|
-
setIsUploading(true);
|
|
29
|
-
await upload(file);
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
onUploadError('Upload failed. Please try again.');
|
|
33
|
-
console.error('Upload error:', error);
|
|
34
|
-
}
|
|
35
|
-
finally {
|
|
36
|
-
setIsUploading(false);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
onUploadError('No file selected or dropped.');
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
const handleDragOver = (e) => {
|
|
45
|
-
if (e.dataTransfer && e.dataTransfer.items) {
|
|
46
|
-
for (const item of e.dataTransfer.items) {
|
|
47
|
-
if (item.kind === 'file' && item.type.startsWith('image/')) {
|
|
48
|
-
e.preventDefault();
|
|
49
|
-
e.dataTransfer.dropEffect = 'copy';
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
const handleDrop = async (e) => {
|
|
55
|
-
e.preventDefault();
|
|
56
|
-
await processFiles(e.dataTransfer.files);
|
|
57
|
-
};
|
|
58
|
-
const handleFileChange = async (e) => {
|
|
59
|
-
await processFiles(e.target.files);
|
|
60
|
-
};
|
|
61
|
-
const handleAreaClick = (event) => {
|
|
62
|
-
const target = event.target;
|
|
63
|
-
if (target.dataset && target.dataset.action) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
fileInputRef.current?.click();
|
|
67
|
-
};
|
|
68
|
-
return (React.createElement(DragAndDropContainer, { onDragOver: handleDragOver, onDrop: !isUploading ? handleDrop : undefined, onClick: !isUploading ? handleAreaClick : undefined, tabIndex: isUploading ? -1 : 0, "aria-label": "Drag and drop area for file upload, or click to open file dialog.", role: "button", onKeyDown: (e) => {
|
|
69
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
70
|
-
e.preventDefault();
|
|
71
|
-
fileInputRef.current?.click();
|
|
72
|
-
}
|
|
73
|
-
} },
|
|
74
|
-
React.createElement("input", { type: "file", ref: fileInputRef, onChange: handleFileChange, "aria-hidden": "true" }),
|
|
75
|
-
React.createElement("p", null,
|
|
76
|
-
"Drag or click here to upload a file to link",
|
|
77
|
-
React.createElement("br", null),
|
|
78
|
-
"or drag items here from the file",
|
|
79
|
-
' ',
|
|
80
|
-
React.createElement("span", { "data-action": "open-other-files" }, "'Other files'"),
|
|
81
|
-
" in the inspector.")));
|
|
82
|
-
};
|
|
83
|
-
const DragAndDropContainer = styled.div `
|
|
84
|
-
display: flex;
|
|
85
|
-
flex-direction: column;
|
|
86
|
-
align-items: center;
|
|
87
|
-
justify-content: center;
|
|
88
|
-
padding: 16px;
|
|
89
|
-
border: 1px dashed ${(props) => props.theme.colors.border.secondary};
|
|
90
|
-
border-radius: 8px;
|
|
91
|
-
background-color: ${(props) => props.theme.colors.background.secondary};
|
|
92
|
-
color: ${(props) => props.theme.colors.text.primary};
|
|
93
|
-
font-size: ${(props) => props.theme.font.size.normal};
|
|
94
|
-
|
|
95
|
-
input[type='file'] {
|
|
96
|
-
display: none;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
p {
|
|
100
|
-
margin: 0;
|
|
101
|
-
font-size: 14px;
|
|
102
|
-
text-align: center;
|
|
103
|
-
}
|
|
104
|
-
span {
|
|
105
|
-
text-decoration: underline;
|
|
106
|
-
cursor: pointer;
|
|
107
|
-
}
|
|
108
|
-
`;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { CloseButton, DeleteIcon, IconButton, IconTextButton, LinkIcon, } from '@manuscripts/style-guide';
|
|
2
|
-
import React, { useState } from 'react';
|
|
3
|
-
import styled from 'styled-components';
|
|
4
|
-
import { DragAndDropUploader } from '../DragAndDropUploader';
|
|
5
|
-
export const ExtLinkEditor = ({ node, nodePos, view, editorProps, isEditing, setIsEditing, }) => {
|
|
6
|
-
const [uploadError, setUploadError] = useState(null);
|
|
7
|
-
const fileManagement = editorProps.fileManagement;
|
|
8
|
-
const extLink = node.attrs.extLink;
|
|
9
|
-
const files = editorProps.getFiles();
|
|
10
|
-
const file = extLink ? files.find((f) => f.id === extLink) : undefined;
|
|
11
|
-
const onUpdate = (newAttrs) => {
|
|
12
|
-
const tr = view.state.tr.setNodeMarkup(nodePos, undefined, {
|
|
13
|
-
...node.attrs,
|
|
14
|
-
...newAttrs,
|
|
15
|
-
});
|
|
16
|
-
view.dispatch(tr);
|
|
17
|
-
};
|
|
18
|
-
const handleFileUpload = async (file) => {
|
|
19
|
-
setUploadError(null);
|
|
20
|
-
const result = await fileManagement.upload(file);
|
|
21
|
-
if (!result) {
|
|
22
|
-
handleUploadError('File upload failed');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
setIsEditing(false);
|
|
26
|
-
onUpdate({ extLink: result.id });
|
|
27
|
-
};
|
|
28
|
-
const handleUploadError = (message) => {
|
|
29
|
-
setUploadError(message);
|
|
30
|
-
};
|
|
31
|
-
const handleRemove = () => {
|
|
32
|
-
setUploadError(null);
|
|
33
|
-
onUpdate({ extLink: '' });
|
|
34
|
-
setIsEditing(false);
|
|
35
|
-
};
|
|
36
|
-
return (React.createElement("div", null,
|
|
37
|
-
!isEditing && !extLink && (React.createElement(IconTextButton, { onClick: () => setIsEditing(true), "aria-label": "Add linked file" },
|
|
38
|
-
React.createElement(LinkIcon, null),
|
|
39
|
-
"Add link")),
|
|
40
|
-
isEditing && !extLink && (React.createElement("div", null,
|
|
41
|
-
React.createElement(ExtLinkEditorLabel, null, "Link"),
|
|
42
|
-
React.createElement(ExtLinkEditorContainer, null,
|
|
43
|
-
React.createElement(DragAndDropUploader, { upload: handleFileUpload, onUploadError: handleUploadError }),
|
|
44
|
-
React.createElement(CloseUploaderButton, { onClick: () => setIsEditing(false) })))),
|
|
45
|
-
extLink && (React.createElement(LinkedFileInfoBox, null,
|
|
46
|
-
React.createElement("p", null,
|
|
47
|
-
React.createElement(LinkIcon, null),
|
|
48
|
-
file ? file.name : 'File does not exist.'),
|
|
49
|
-
React.createElement(IconButton, { onClick: handleRemove, "aria-label": "Remove linked file" },
|
|
50
|
-
React.createElement(DeleteIcon, null)))),
|
|
51
|
-
uploadError && (React.createElement("div", null,
|
|
52
|
-
React.createElement("p", { className: "font-semibold" }, "Error:"),
|
|
53
|
-
React.createElement("p", null, uploadError)))));
|
|
54
|
-
};
|
|
55
|
-
const ExtLinkEditorLabel = styled.div `
|
|
56
|
-
color: var(--label-color);
|
|
57
|
-
font-size: 18px;
|
|
58
|
-
font-style: normal;
|
|
59
|
-
font-weight: 400;
|
|
60
|
-
line-height: 24px;
|
|
61
|
-
letter-spacing: -0.369px;
|
|
62
|
-
margin-top: 12px;
|
|
63
|
-
cursor: pointer;
|
|
64
|
-
`;
|
|
65
|
-
const ExtLinkEditorContainer = styled.div `
|
|
66
|
-
position: relative;
|
|
67
|
-
`;
|
|
68
|
-
const LinkedFileInfoBox = styled.div `
|
|
69
|
-
display: flex;
|
|
70
|
-
flex-direction: row;
|
|
71
|
-
align-items: center;
|
|
72
|
-
justify-content: space-between;
|
|
73
|
-
padding: 4px 8px;
|
|
74
|
-
background-color: ${(props) => props.theme.colors.background.secondary};
|
|
75
|
-
color: ${(props) => props.theme.colors.text.primary};
|
|
76
|
-
border: 1px solid ${(props) => props.theme.colors.border.secondary};
|
|
77
|
-
border-radius: 8px;
|
|
78
|
-
|
|
79
|
-
p {
|
|
80
|
-
display: flex;
|
|
81
|
-
align-items: center;
|
|
82
|
-
justify-content: flex-start;
|
|
83
|
-
gap: 8px;
|
|
84
|
-
|
|
85
|
-
font-family: ${(props) => props.theme.font.family.sans};
|
|
86
|
-
font-weight: ${(props) => props.theme.font.weight.normal};
|
|
87
|
-
font-size: ${(props) => props.theme.font.size.medium};
|
|
88
|
-
}
|
|
89
|
-
`;
|
|
90
|
-
const CloseUploaderButton = styled(CloseButton) `
|
|
91
|
-
border: 1px solid ${(props) => props.theme.colors.border.tertiary};
|
|
92
|
-
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.12);
|
|
93
|
-
|
|
94
|
-
position: absolute;
|
|
95
|
-
top: -8px;
|
|
96
|
-
right: -8px;
|
|
97
|
-
`;
|