@thangph2146/lexical-editor 0.0.11 → 0.0.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/README.md +2 -1
- package/dist/editor-x/editor.cjs +280 -20
- package/dist/editor-x/editor.cjs.map +1 -1
- package/dist/editor-x/editor.css +27 -4
- package/dist/editor-x/editor.css.map +1 -1
- package/dist/editor-x/editor.js +281 -21
- package/dist/editor-x/editor.js.map +1 -1
- package/dist/index.cjs +292 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +27 -4
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +293 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/lexical-editor.tsx +19 -6
- package/src/context/uploads-context.tsx +1 -0
- package/src/editor-ui/content-editable.tsx +18 -2
- package/src/editor-x/nodes.ts +2 -0
- package/src/nodes/download-link-node.tsx +118 -0
- package/src/plugins/floating-link-editor-plugin.tsx +338 -91
- package/src/themes/core/_tables.scss +0 -1
- package/src/themes/plugins/_floating-link-editor.scss +28 -2
- package/src/themes/ui-components/_button.scss +1 -1
- package/src/themes/ui-components/_flex.scss +1 -0
- package/src/ui/button-group.tsx +10 -10
- package/src/ui/button.tsx +38 -38
- package/src/ui/collapsible.tsx +67 -67
- package/src/ui/command.tsx +48 -48
- package/src/ui/dialog.tsx +146 -146
- package/src/ui/flex.tsx +45 -45
- package/src/ui/input.tsx +20 -20
- package/src/ui/label.tsx +20 -20
- package/src/ui/number-input.tsx +104 -104
- package/src/ui/popover.tsx +128 -128
- package/src/ui/scroll-area.tsx +17 -17
- package/src/ui/select.tsx +171 -171
- package/src/ui/separator.tsx +20 -20
- package/src/ui/slider.tsx +14 -14
- package/src/ui/slot.tsx +3 -3
- package/src/ui/tabs.tsx +87 -87
- package/src/ui/toggle-group.tsx +109 -109
- package/src/ui/toggle.tsx +28 -28
- package/src/ui/tooltip.tsx +28 -28
- package/src/ui/typography.tsx +44 -44
package/dist/index.cjs
CHANGED
|
@@ -20,9 +20,9 @@ var LexicalHistoryPlugin = require('@lexical/react/LexicalHistoryPlugin');
|
|
|
20
20
|
var LexicalRichTextPlugin = require('@lexical/react/LexicalRichTextPlugin');
|
|
21
21
|
var LexicalErrorBoundary = require('@lexical/react/LexicalErrorBoundary');
|
|
22
22
|
var list = require('@lexical/list');
|
|
23
|
+
var link = require('@lexical/link');
|
|
23
24
|
var code = require('@lexical/code');
|
|
24
25
|
var hashtag = require('@lexical/hashtag');
|
|
25
|
-
var link = require('@lexical/link');
|
|
26
26
|
var overflow = require('@lexical/overflow');
|
|
27
27
|
var LexicalHorizontalRuleNode = require('@lexical/react/LexicalHorizontalRuleNode');
|
|
28
28
|
var richText = require('@lexical/rich-text');
|
|
@@ -4218,6 +4218,12 @@ var init_tabs = __esm({
|
|
|
4218
4218
|
TabsContext = React21__namespace.createContext(null);
|
|
4219
4219
|
}
|
|
4220
4220
|
});
|
|
4221
|
+
function EditorUploadsProvider({
|
|
4222
|
+
children,
|
|
4223
|
+
value
|
|
4224
|
+
}) {
|
|
4225
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EditorUploadsContext.Provider, { value, children });
|
|
4226
|
+
}
|
|
4221
4227
|
function useEditorUploads() {
|
|
4222
4228
|
const context = React21.useContext(EditorUploadsContext);
|
|
4223
4229
|
if (context === void 0) {
|
|
@@ -5095,12 +5101,14 @@ var init_image_placeholder = __esm({
|
|
|
5095
5101
|
}
|
|
5096
5102
|
});
|
|
5097
5103
|
function ContentEditable({
|
|
5098
|
-
placeholder,
|
|
5104
|
+
placeholder = "",
|
|
5099
5105
|
className,
|
|
5100
5106
|
placeholderClassName,
|
|
5101
5107
|
placeholderDefaults = true
|
|
5102
5108
|
}) {
|
|
5103
5109
|
const isReadOnlyOrReview = className?.includes("--readonly") || className?.includes("--review");
|
|
5110
|
+
const text = placeholder.trim();
|
|
5111
|
+
const showLexicalPlaceholder = text.length > 0;
|
|
5104
5112
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5105
5113
|
LexicalContentEditable.ContentEditable,
|
|
5106
5114
|
{
|
|
@@ -5109,7 +5117,17 @@ function ContentEditable({
|
|
|
5109
5117
|
!isReadOnlyOrReview && "min-h-72 px-8 py-4",
|
|
5110
5118
|
className
|
|
5111
5119
|
),
|
|
5112
|
-
"aria-label": "Editor n\u1ED9i dung"
|
|
5120
|
+
"aria-label": "Editor n\u1ED9i dung",
|
|
5121
|
+
...showLexicalPlaceholder ? {
|
|
5122
|
+
"aria-placeholder": text,
|
|
5123
|
+
placeholder: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5124
|
+
"div",
|
|
5125
|
+
{
|
|
5126
|
+
className: cn(placeholderDefaults && "editor-placeholder", placeholderClassName),
|
|
5127
|
+
children: text
|
|
5128
|
+
}
|
|
5129
|
+
)
|
|
5130
|
+
} : { placeholder: null }
|
|
5113
5131
|
}
|
|
5114
5132
|
);
|
|
5115
5133
|
}
|
|
@@ -6245,6 +6263,86 @@ var init_list_with_color_node = __esm({
|
|
|
6245
6263
|
};
|
|
6246
6264
|
}
|
|
6247
6265
|
});
|
|
6266
|
+
function $createDownloadLinkNode(url, download = null, attributes) {
|
|
6267
|
+
return new DownloadLinkNode(url, download, attributes);
|
|
6268
|
+
}
|
|
6269
|
+
function $isDownloadLinkNode(node) {
|
|
6270
|
+
return node instanceof DownloadLinkNode;
|
|
6271
|
+
}
|
|
6272
|
+
var DownloadLinkNode;
|
|
6273
|
+
var init_download_link_node = __esm({
|
|
6274
|
+
"src/nodes/download-link-node.tsx"() {
|
|
6275
|
+
DownloadLinkNode = class _DownloadLinkNode extends link.LinkNode {
|
|
6276
|
+
__download;
|
|
6277
|
+
static getType() {
|
|
6278
|
+
return "download-link";
|
|
6279
|
+
}
|
|
6280
|
+
static clone(node) {
|
|
6281
|
+
return new _DownloadLinkNode(
|
|
6282
|
+
node.getURL(),
|
|
6283
|
+
node.__download,
|
|
6284
|
+
{
|
|
6285
|
+
rel: node.getRel(),
|
|
6286
|
+
target: node.getTarget(),
|
|
6287
|
+
title: node.getTitle()
|
|
6288
|
+
},
|
|
6289
|
+
node.__key
|
|
6290
|
+
);
|
|
6291
|
+
}
|
|
6292
|
+
constructor(url, download = null, attributes, key) {
|
|
6293
|
+
super(url, attributes, key);
|
|
6294
|
+
this.__download = download;
|
|
6295
|
+
}
|
|
6296
|
+
getDownload() {
|
|
6297
|
+
return this.__download;
|
|
6298
|
+
}
|
|
6299
|
+
setDownload(download) {
|
|
6300
|
+
const writable = this.getWritable();
|
|
6301
|
+
writable.__download = download;
|
|
6302
|
+
return this;
|
|
6303
|
+
}
|
|
6304
|
+
createDOM(config) {
|
|
6305
|
+
const dom = super.createDOM(config);
|
|
6306
|
+
this.applyDownloadDOM(dom);
|
|
6307
|
+
return dom;
|
|
6308
|
+
}
|
|
6309
|
+
updateLinkDOM(prevNode, anchorElem, config) {
|
|
6310
|
+
super.updateLinkDOM(prevNode, anchorElem, config);
|
|
6311
|
+
this.applyDownloadDOM(anchorElem);
|
|
6312
|
+
}
|
|
6313
|
+
exportJSON() {
|
|
6314
|
+
return {
|
|
6315
|
+
...super.exportJSON(),
|
|
6316
|
+
type: _DownloadLinkNode.getType(),
|
|
6317
|
+
version: 1,
|
|
6318
|
+
download: this.__download
|
|
6319
|
+
};
|
|
6320
|
+
}
|
|
6321
|
+
static importJSON(serializedNode) {
|
|
6322
|
+
const node = new _DownloadLinkNode(
|
|
6323
|
+
serializedNode.url,
|
|
6324
|
+
serializedNode.download,
|
|
6325
|
+
{
|
|
6326
|
+
rel: serializedNode.rel ?? null,
|
|
6327
|
+
target: serializedNode.target ?? null,
|
|
6328
|
+
title: serializedNode.title ?? null
|
|
6329
|
+
},
|
|
6330
|
+
serializedNode.key
|
|
6331
|
+
);
|
|
6332
|
+
return node;
|
|
6333
|
+
}
|
|
6334
|
+
applyDownloadDOM(dom) {
|
|
6335
|
+
if (dom instanceof HTMLAnchorElement) {
|
|
6336
|
+
if (this.__download === null) {
|
|
6337
|
+
dom.removeAttribute("download");
|
|
6338
|
+
} else {
|
|
6339
|
+
dom.setAttribute("download", this.__download);
|
|
6340
|
+
}
|
|
6341
|
+
}
|
|
6342
|
+
}
|
|
6343
|
+
};
|
|
6344
|
+
}
|
|
6345
|
+
});
|
|
6248
6346
|
function $convertMentionElement(domNode) {
|
|
6249
6347
|
const textContent = domNode.textContent;
|
|
6250
6348
|
if (textContent !== null) {
|
|
@@ -6357,6 +6455,7 @@ var init_nodes = __esm({
|
|
|
6357
6455
|
init_layout_container_node();
|
|
6358
6456
|
init_layout_item_node();
|
|
6359
6457
|
init_list_with_color_node();
|
|
6458
|
+
init_download_link_node();
|
|
6360
6459
|
init_mention_node();
|
|
6361
6460
|
nodes = [
|
|
6362
6461
|
richText.HeadingNode,
|
|
@@ -6372,6 +6471,7 @@ var init_nodes = __esm({
|
|
|
6372
6471
|
ListWithColorNode,
|
|
6373
6472
|
list.ListItemNode,
|
|
6374
6473
|
link.LinkNode,
|
|
6474
|
+
DownloadLinkNode,
|
|
6375
6475
|
overflow.OverflowNode,
|
|
6376
6476
|
hashtag.HashtagNode,
|
|
6377
6477
|
table.TableNode,
|
|
@@ -28024,6 +28124,44 @@ var init_url = __esm({
|
|
|
28024
28124
|
);
|
|
28025
28125
|
}
|
|
28026
28126
|
});
|
|
28127
|
+
function shouldTreatUrlAsDownload(url) {
|
|
28128
|
+
if (typeof url !== "string") return false;
|
|
28129
|
+
const u = url.toLowerCase();
|
|
28130
|
+
if (u.includes("/api/uploads/") || u.includes("/uploads/") || u.includes("/api/admin/uploads/") || u.includes("/admin/uploads/"))
|
|
28131
|
+
return true;
|
|
28132
|
+
return /\.(pdf|doc|docx|xls|xlsx|csv|zip|rar|7z|txt|rtf|png|jpg|jpeg|gif|webp|mp3|wav|mp4|mov|avi)(\?.*)?$/.test(
|
|
28133
|
+
u
|
|
28134
|
+
);
|
|
28135
|
+
}
|
|
28136
|
+
function inferDownloadFileName(url) {
|
|
28137
|
+
try {
|
|
28138
|
+
const path = url.split("?")[0] ?? "";
|
|
28139
|
+
const last = path.split("/").filter(Boolean).pop();
|
|
28140
|
+
return last ? decodeURIComponent(last) : "download";
|
|
28141
|
+
} catch {
|
|
28142
|
+
return "download";
|
|
28143
|
+
}
|
|
28144
|
+
}
|
|
28145
|
+
function getCookieValue(name) {
|
|
28146
|
+
if (typeof document === "undefined") return null;
|
|
28147
|
+
const row = document.cookie.split("; ").find((item) => item.startsWith(`${name}=`));
|
|
28148
|
+
if (!row) return null;
|
|
28149
|
+
return row.split("=").slice(1).join("=") || null;
|
|
28150
|
+
}
|
|
28151
|
+
function buildHrefFromJsDownloadArg(jsArg) {
|
|
28152
|
+
const firstSegment = typeof window !== "undefined" ? window.location.pathname.split("/").filter(Boolean)[0] ?? "" : "";
|
|
28153
|
+
const serveBase = firstSegment === "admin" ? "/api/admin/uploads/serve" : "/api/uploads/serve";
|
|
28154
|
+
const arg = jsArg.trim();
|
|
28155
|
+
if (!arg) return "about:blank";
|
|
28156
|
+
if (/^https?:\/\//i.test(arg)) return arg;
|
|
28157
|
+
if (arg.startsWith("/api/")) return arg;
|
|
28158
|
+
if (arg.startsWith("images/") || arg.startsWith("files/")) {
|
|
28159
|
+
return `${serveBase}/${arg}`;
|
|
28160
|
+
}
|
|
28161
|
+
const m = arg.match(/(images|files)\/.+/i);
|
|
28162
|
+
if (m?.[0]) return `${serveBase}/${m[0]}`;
|
|
28163
|
+
return "about:blank";
|
|
28164
|
+
}
|
|
28027
28165
|
function FloatingLinkEditor({
|
|
28028
28166
|
editor,
|
|
28029
28167
|
isLink,
|
|
@@ -28037,6 +28175,9 @@ function FloatingLinkEditor({
|
|
|
28037
28175
|
const [linkUrl, setLinkUrl] = React21.useState("");
|
|
28038
28176
|
const [editedLinkUrl, setEditedLinkUrl] = React21.useState("https://");
|
|
28039
28177
|
const [lastSelection, setLastSelection] = React21.useState(null);
|
|
28178
|
+
const [isUploadingFile, setIsUploadingFile] = React21.useState(false);
|
|
28179
|
+
const fileInputRef = React21.useRef(null);
|
|
28180
|
+
const { onUploadFile } = useEditorUploads();
|
|
28040
28181
|
const $updateLinkEditor = React21.useCallback(() => {
|
|
28041
28182
|
const selection = lexical.$getSelection();
|
|
28042
28183
|
let linkNode = null;
|
|
@@ -28230,9 +28371,11 @@ function FloatingLinkEditor({
|
|
|
28230
28371
|
setIsLinkEditMode(false);
|
|
28231
28372
|
}
|
|
28232
28373
|
};
|
|
28233
|
-
const handleLinkSubmission = () => {
|
|
28234
|
-
const
|
|
28235
|
-
|
|
28374
|
+
const handleLinkSubmission = (submittedUrl, originalFileName) => {
|
|
28375
|
+
const rawUrl = typeof submittedUrl === "string" ? submittedUrl : editedLinkUrl;
|
|
28376
|
+
const url = sanitizeUrl(rawUrl);
|
|
28377
|
+
const downloadFileName = originalFileName || (shouldTreatUrlAsDownload(url) ? inferDownloadFileName(url) : null);
|
|
28378
|
+
if (url && url !== "about:blank" && url !== "https://" && url !== "http://") {
|
|
28236
28379
|
editor.update(() => {
|
|
28237
28380
|
let selection = lexical.$getSelection();
|
|
28238
28381
|
if (!selection && lastSelection !== null) {
|
|
@@ -28257,8 +28400,11 @@ function FloatingLinkEditor({
|
|
|
28257
28400
|
const existingLinkNode = utils.$findMatchingParent(node, link.$isLinkNode) || (link.$isLinkNode(node.getParent()) ? node.getParent() : null);
|
|
28258
28401
|
if (existingLinkNode) {
|
|
28259
28402
|
existingLinkNode.setURL(url);
|
|
28403
|
+
if (downloadFileName && $isDownloadLinkNode(existingLinkNode)) {
|
|
28404
|
+
existingLinkNode.setDownload(downloadFileName);
|
|
28405
|
+
}
|
|
28260
28406
|
} else {
|
|
28261
|
-
const linkNode = link.$createLinkNode(url);
|
|
28407
|
+
const linkNode = downloadFileName ? $createDownloadLinkNode(url, downloadFileName) : link.$createLinkNode(url);
|
|
28262
28408
|
utils.$wrapNodeInElement(node, () => linkNode);
|
|
28263
28409
|
}
|
|
28264
28410
|
}
|
|
@@ -28267,25 +28413,114 @@ function FloatingLinkEditor({
|
|
|
28267
28413
|
editor.dispatchCommand(link.TOGGLE_LINK_COMMAND, url);
|
|
28268
28414
|
const parent = getSelectedNode(selection).getParent();
|
|
28269
28415
|
if (link.$isAutoLinkNode(parent)) {
|
|
28270
|
-
const linkNode =
|
|
28416
|
+
const linkNode = downloadFileName ? $createDownloadLinkNode(parent.getURL(), downloadFileName, {
|
|
28417
|
+
rel: parent.__rel,
|
|
28418
|
+
target: parent.__target,
|
|
28419
|
+
title: parent.__title
|
|
28420
|
+
}) : link.$createLinkNode(parent.getURL(), {
|
|
28271
28421
|
rel: parent.__rel,
|
|
28272
28422
|
target: parent.__target,
|
|
28273
28423
|
title: parent.__title
|
|
28274
28424
|
});
|
|
28275
28425
|
parent.replace(linkNode, true);
|
|
28276
28426
|
}
|
|
28427
|
+
if (downloadFileName) {
|
|
28428
|
+
const selectedNode = getSelectedNode(selection);
|
|
28429
|
+
const linkNode = utils.$findMatchingParent(selectedNode, link.$isLinkNode) || (link.$isLinkNode(selectedNode) ? selectedNode : null);
|
|
28430
|
+
if (linkNode) {
|
|
28431
|
+
const currentText = linkNode.getTextContent();
|
|
28432
|
+
const targetText = originalFileName || downloadFileName;
|
|
28433
|
+
const downloadLinkNode = $createDownloadLinkNode(url, downloadFileName, {
|
|
28434
|
+
rel: linkNode.getRel(),
|
|
28435
|
+
target: linkNode.getTarget(),
|
|
28436
|
+
title: linkNode.getTitle()
|
|
28437
|
+
});
|
|
28438
|
+
if (currentText === url && targetText) {
|
|
28439
|
+
downloadLinkNode.append(lexical.$createTextNode(targetText));
|
|
28440
|
+
} else {
|
|
28441
|
+
const children = linkNode.getChildren();
|
|
28442
|
+
if (children.length > 0) {
|
|
28443
|
+
downloadLinkNode.append(...children);
|
|
28444
|
+
}
|
|
28445
|
+
}
|
|
28446
|
+
linkNode.replace(downloadLinkNode);
|
|
28447
|
+
}
|
|
28448
|
+
}
|
|
28277
28449
|
}
|
|
28278
28450
|
});
|
|
28279
28451
|
setEditedLinkUrl("https://");
|
|
28280
28452
|
setIsLinkEditMode(false);
|
|
28281
28453
|
}
|
|
28282
28454
|
};
|
|
28455
|
+
const handlePickLocalFile = () => {
|
|
28456
|
+
if (isUploadingFile) return;
|
|
28457
|
+
fileInputRef.current?.click();
|
|
28458
|
+
};
|
|
28459
|
+
const handleUploadLocalFile = async (event) => {
|
|
28460
|
+
const file = event.target.files?.[0];
|
|
28461
|
+
if (!file) return;
|
|
28462
|
+
try {
|
|
28463
|
+
setIsUploadingFile(true);
|
|
28464
|
+
let uploadedUrl = void 0;
|
|
28465
|
+
if (onUploadFile) {
|
|
28466
|
+
const result = await onUploadFile(file);
|
|
28467
|
+
if (result.error) throw new Error(result.error);
|
|
28468
|
+
uploadedUrl = result.url;
|
|
28469
|
+
} else {
|
|
28470
|
+
const formData = new FormData();
|
|
28471
|
+
formData.append("file", file);
|
|
28472
|
+
const firstSegment = typeof window !== "undefined" ? window.location.pathname.split("/").filter(Boolean)[0] ?? "" : "";
|
|
28473
|
+
const pathPart = firstSegment === "admin" ? "/admin/uploads" : "/uploads";
|
|
28474
|
+
const endpoint = firstSegment === "admin" ? `/admin/api${pathPart}` : `/api${pathPart}`;
|
|
28475
|
+
const userId = getCookieValue("app_user_id");
|
|
28476
|
+
const authToken = getCookieValue("auth-token");
|
|
28477
|
+
const headers = {};
|
|
28478
|
+
if (userId) headers["X-User-Id"] = userId;
|
|
28479
|
+
if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
|
|
28480
|
+
const res = await fetch(endpoint, {
|
|
28481
|
+
method: "POST",
|
|
28482
|
+
credentials: "include",
|
|
28483
|
+
headers: Object.keys(headers).length > 0 ? headers : void 0,
|
|
28484
|
+
body: formData
|
|
28485
|
+
});
|
|
28486
|
+
if (!res.ok) {
|
|
28487
|
+
throw new Error(`Upload failed: HTTP ${res.status}`);
|
|
28488
|
+
}
|
|
28489
|
+
const payload = await res.json();
|
|
28490
|
+
uploadedUrl = payload?.data?.url;
|
|
28491
|
+
if (!payload?.success || !uploadedUrl) {
|
|
28492
|
+
throw new Error(payload?.message || payload?.error || "Upload failed");
|
|
28493
|
+
}
|
|
28494
|
+
}
|
|
28495
|
+
if (uploadedUrl) {
|
|
28496
|
+
setEditedLinkUrl(uploadedUrl);
|
|
28497
|
+
handleLinkSubmission(uploadedUrl, file.name);
|
|
28498
|
+
}
|
|
28499
|
+
} catch (error) {
|
|
28500
|
+
console.error("[FloatingLinkEditor] Upload local file failed:", error);
|
|
28501
|
+
} finally {
|
|
28502
|
+
setIsUploadingFile(false);
|
|
28503
|
+
if (fileInputRef.current) {
|
|
28504
|
+
fileInputRef.current.value = "";
|
|
28505
|
+
}
|
|
28506
|
+
}
|
|
28507
|
+
};
|
|
28283
28508
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28284
28509
|
"div",
|
|
28285
28510
|
{
|
|
28286
28511
|
ref: editorRef,
|
|
28287
28512
|
className: "editor-floating-link-editor",
|
|
28288
|
-
children: isLinkEditMode || isLink ? isLinkEditMode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "editor-floating-link-editor__input-container", children: [
|
|
28513
|
+
children: isLinkEditMode || isLink ? isLinkEditMode ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "editor-floating-link-editor__input-container", children: [
|
|
28514
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28515
|
+
"input",
|
|
28516
|
+
{
|
|
28517
|
+
ref: fileInputRef,
|
|
28518
|
+
type: "file",
|
|
28519
|
+
className: "hidden",
|
|
28520
|
+
onChange: handleUploadLocalFile,
|
|
28521
|
+
accept: ".pdf,.doc,.docx,.xls,.xlsx,.csv,.rtf,.txt,.zip,.rar,.7z,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.webp,.svg,.mp3,.wav,.mp4,.mov,.avi,.webm"
|
|
28522
|
+
}
|
|
28523
|
+
),
|
|
28289
28524
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28290
28525
|
Input,
|
|
28291
28526
|
{
|
|
@@ -28296,6 +28531,18 @@ function FloatingLinkEditor({
|
|
|
28296
28531
|
className: "editor-flex-grow"
|
|
28297
28532
|
}
|
|
28298
28533
|
),
|
|
28534
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28535
|
+
Button,
|
|
28536
|
+
{
|
|
28537
|
+
size: "icon",
|
|
28538
|
+
variant: "ghost",
|
|
28539
|
+
onClick: handlePickLocalFile,
|
|
28540
|
+
className: "editor-shrink-0",
|
|
28541
|
+
disabled: isUploadingFile,
|
|
28542
|
+
title: isUploadingFile ? "Uploading..." : "Upload file t\u1EEB thi\u1EBFt b\u1ECB",
|
|
28543
|
+
children: isUploadingFile ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "editor-icon-sm animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "editor-icon-sm" })
|
|
28544
|
+
}
|
|
28545
|
+
),
|
|
28299
28546
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28300
28547
|
Button,
|
|
28301
28548
|
{
|
|
@@ -28313,22 +28560,39 @@ function FloatingLinkEditor({
|
|
|
28313
28560
|
Button,
|
|
28314
28561
|
{
|
|
28315
28562
|
size: "icon",
|
|
28316
|
-
onClick: handleLinkSubmission,
|
|
28563
|
+
onClick: () => handleLinkSubmission(),
|
|
28317
28564
|
className: "editor-shrink-0",
|
|
28318
28565
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "editor-icon-sm" })
|
|
28319
28566
|
}
|
|
28320
28567
|
)
|
|
28321
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "editor-floating-link-editor__view-container", children: [
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
|
|
28325
|
-
|
|
28326
|
-
|
|
28327
|
-
|
|
28328
|
-
|
|
28329
|
-
|
|
28568
|
+
] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "editor-floating-link-editor__view-container", children: [
|
|
28569
|
+
(() => {
|
|
28570
|
+
let href = sanitizeUrl(linkUrl);
|
|
28571
|
+
const jsDownloadMatch = typeof linkUrl === "string" ? linkUrl.match(/^javascript:download\(\s*(['"])(.*?)\1\s*\)\s*$/i) : null;
|
|
28572
|
+
let downloadAttr;
|
|
28573
|
+
if (jsDownloadMatch) {
|
|
28574
|
+
const jsArg = jsDownloadMatch[2] ?? "";
|
|
28575
|
+
href = buildHrefFromJsDownloadArg(jsArg);
|
|
28576
|
+
if (href !== "about:blank") {
|
|
28577
|
+
downloadAttr = inferDownloadFileName(href);
|
|
28578
|
+
}
|
|
28579
|
+
} else if (shouldTreatUrlAsDownload(href)) {
|
|
28580
|
+
downloadAttr = inferDownloadFileName(href);
|
|
28330
28581
|
}
|
|
28331
|
-
|
|
28582
|
+
const isDownload = typeof downloadAttr === "string" && downloadAttr.length > 0;
|
|
28583
|
+
const text = jsDownloadMatch ? "Download" : shouldTreatUrlAsDownload(href) ? inferDownloadFileName(href) : href === "about:blank" ? "Invalid URL" : linkUrl;
|
|
28584
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28585
|
+
"a",
|
|
28586
|
+
{
|
|
28587
|
+
href,
|
|
28588
|
+
download: downloadAttr,
|
|
28589
|
+
target: isDownload ? "_self" : "_blank",
|
|
28590
|
+
rel: isDownload ? void 0 : "noopener noreferrer",
|
|
28591
|
+
className: "editor-floating-link-editor__link",
|
|
28592
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TypographyPSmall, { className: "editor-truncate", children: text })
|
|
28593
|
+
}
|
|
28594
|
+
);
|
|
28595
|
+
})(),
|
|
28332
28596
|
/* @__PURE__ */ jsxRuntime.jsxs(Flex, { gap: 0, className: "editor-shrink-0", children: [
|
|
28333
28597
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28334
28598
|
Button,
|
|
@@ -28642,6 +28906,8 @@ var init_floating_link_editor_plugin = __esm({
|
|
|
28642
28906
|
init_flex();
|
|
28643
28907
|
init_typography();
|
|
28644
28908
|
init_image_node();
|
|
28909
|
+
init_download_link_node();
|
|
28910
|
+
init_uploads_context();
|
|
28645
28911
|
}
|
|
28646
28912
|
});
|
|
28647
28913
|
|
|
@@ -33529,6 +33795,7 @@ function Editor({
|
|
|
33529
33795
|
);
|
|
33530
33796
|
}
|
|
33531
33797
|
init_logger();
|
|
33798
|
+
init_uploads_context();
|
|
33532
33799
|
function isValidSerializedEditorState(value) {
|
|
33533
33800
|
return value !== null && typeof value === "object" && "root" in value && value.root !== null && typeof value.root === "object" && "type" in value.root && value.root.type === "root";
|
|
33534
33801
|
}
|
|
@@ -33537,7 +33804,8 @@ function LexicalEditor11({
|
|
|
33537
33804
|
onChange,
|
|
33538
33805
|
readOnly = false,
|
|
33539
33806
|
className,
|
|
33540
|
-
placeholder = ""
|
|
33807
|
+
placeholder = "",
|
|
33808
|
+
uploadsContext
|
|
33541
33809
|
}) {
|
|
33542
33810
|
const [editorState, setEditorState] = React21.useState(() => {
|
|
33543
33811
|
if (value && typeof value === "object" && value !== null) {
|
|
@@ -33607,7 +33875,7 @@ function LexicalEditor11({
|
|
|
33607
33875
|
onChange(newState);
|
|
33608
33876
|
}
|
|
33609
33877
|
};
|
|
33610
|
-
|
|
33878
|
+
const editorContent = /* @__PURE__ */ jsxRuntime.jsx(
|
|
33611
33879
|
Editor,
|
|
33612
33880
|
{
|
|
33613
33881
|
editorSerializedState: editorState,
|
|
@@ -33615,7 +33883,8 @@ function LexicalEditor11({
|
|
|
33615
33883
|
readOnly,
|
|
33616
33884
|
placeholder
|
|
33617
33885
|
}
|
|
33618
|
-
)
|
|
33886
|
+
);
|
|
33887
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: uploadsContext ? /* @__PURE__ */ jsxRuntime.jsx(EditorUploadsProvider, { value: uploadsContext, children: editorContent }) : editorContent });
|
|
33619
33888
|
}
|
|
33620
33889
|
|
|
33621
33890
|
exports.Editor = Editor;
|