@underverse-ui/underverse 1.0.63 → 1.0.64
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/api-reference.json +1 -1
- package/dist/index.cjs +324 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +330 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -708,7 +708,15 @@ var en_default = {
|
|
|
708
708
|
heading1: "Heading 1",
|
|
709
709
|
heading2: "Heading 2",
|
|
710
710
|
heading3: "Heading 3",
|
|
711
|
-
emoji: "Insert Emoji"
|
|
711
|
+
emoji: "Insert Emoji",
|
|
712
|
+
imageLayoutBlock: "Image Block",
|
|
713
|
+
imageLayoutLeft: "Wrap Text Right",
|
|
714
|
+
imageLayoutRight: "Wrap Text Left",
|
|
715
|
+
imageWidthSm: "Image Width Small",
|
|
716
|
+
imageWidthMd: "Image Width Medium",
|
|
717
|
+
imageWidthLg: "Image Width Large",
|
|
718
|
+
imageResetSize: "Reset Image Size",
|
|
719
|
+
imageDelete: "Delete Image"
|
|
712
720
|
},
|
|
713
721
|
slashCommand: {
|
|
714
722
|
basicBlocks: "Basic Blocks",
|
|
@@ -932,7 +940,15 @@ var vi_default = {
|
|
|
932
940
|
heading1: "Ti\xEAu \u0111\u1EC1 1",
|
|
933
941
|
heading2: "Ti\xEAu \u0111\u1EC1 2",
|
|
934
942
|
heading3: "Ti\xEAu \u0111\u1EC1 3",
|
|
935
|
-
emoji: "Ch\xE8n Emoji"
|
|
943
|
+
emoji: "Ch\xE8n Emoji",
|
|
944
|
+
imageLayoutBlock: "\u1EA2nh D\u1EA1ng Kh\u1ED1i",
|
|
945
|
+
imageLayoutLeft: "\u1EA2nh Tr\xE1i, Ch\u1EEF Ph\u1EA3i",
|
|
946
|
+
imageLayoutRight: "\u1EA2nh Ph\u1EA3i, Ch\u1EEF Tr\xE1i",
|
|
947
|
+
imageWidthSm: "\u1EA2nh Nh\u1ECF",
|
|
948
|
+
imageWidthMd: "\u1EA2nh V\u1EEBa",
|
|
949
|
+
imageWidthLg: "\u1EA2nh L\u1EDBn",
|
|
950
|
+
imageResetSize: "\u0110\u1EB7t L\u1EA1i K\xEDch Th\u01B0\u1EDBc \u1EA2nh",
|
|
951
|
+
imageDelete: "X\xF3a \u1EA2nh"
|
|
936
952
|
},
|
|
937
953
|
slashCommand: {
|
|
938
954
|
basicBlocks: "Kh\u1ED1i c\u01A1 b\u1EA3n",
|
|
@@ -1156,7 +1172,15 @@ var ko_default = {
|
|
|
1156
1172
|
heading1: "\uC81C\uBAA9 1",
|
|
1157
1173
|
heading2: "\uC81C\uBAA9 2",
|
|
1158
1174
|
heading3: "\uC81C\uBAA9 3",
|
|
1159
|
-
emoji: "\uC774\uBAA8\uC9C0 \uC0BD\uC785"
|
|
1175
|
+
emoji: "\uC774\uBAA8\uC9C0 \uC0BD\uC785",
|
|
1176
|
+
imageLayoutBlock: "\uC774\uBBF8\uC9C0 \uBE14\uB85D",
|
|
1177
|
+
imageLayoutLeft: "\uC67C\uCABD \uC774\uBBF8\uC9C0, \uC624\uB978\uCABD \uD14D\uC2A4\uD2B8",
|
|
1178
|
+
imageLayoutRight: "\uC624\uB978\uCABD \uC774\uBBF8\uC9C0, \uC67C\uCABD \uD14D\uC2A4\uD2B8",
|
|
1179
|
+
imageWidthSm: "\uC791\uC740 \uC774\uBBF8\uC9C0",
|
|
1180
|
+
imageWidthMd: "\uC911\uAC04 \uC774\uBBF8\uC9C0",
|
|
1181
|
+
imageWidthLg: "\uD070 \uC774\uBBF8\uC9C0",
|
|
1182
|
+
imageResetSize: "\uC774\uBBF8\uC9C0 \uD06C\uAE30 \uCD08\uAE30\uD654",
|
|
1183
|
+
imageDelete: "\uC774\uBBF8\uC9C0 \uC0AD\uC81C"
|
|
1160
1184
|
},
|
|
1161
1185
|
slashCommand: {
|
|
1162
1186
|
basicBlocks: "\uAE30\uBCF8 \uBE14\uB85D",
|
|
@@ -1379,7 +1403,15 @@ var ja_default = {
|
|
|
1379
1403
|
heading1: "\u898B\u51FA\u3057 1",
|
|
1380
1404
|
heading2: "\u898B\u51FA\u3057 2",
|
|
1381
1405
|
heading3: "\u898B\u51FA\u3057 3",
|
|
1382
|
-
emoji: "\u7D75\u6587\u5B57\u3092\u633F\u5165"
|
|
1406
|
+
emoji: "\u7D75\u6587\u5B57\u3092\u633F\u5165",
|
|
1407
|
+
imageLayoutBlock: "\u753B\u50CF\u30D6\u30ED\u30C3\u30AF",
|
|
1408
|
+
imageLayoutLeft: "\u753B\u50CF\u3092\u5DE6\u3001\u6587\u5B57\u3092\u53F3\u306B\u56DE\u308A\u8FBC\u307F",
|
|
1409
|
+
imageLayoutRight: "\u753B\u50CF\u3092\u53F3\u3001\u6587\u5B57\u3092\u5DE6\u306B\u56DE\u308A\u8FBC\u307F",
|
|
1410
|
+
imageWidthSm: "\u753B\u50CF \u5C0F",
|
|
1411
|
+
imageWidthMd: "\u753B\u50CF \u4E2D",
|
|
1412
|
+
imageWidthLg: "\u753B\u50CF \u5927",
|
|
1413
|
+
imageResetSize: "\u753B\u50CF\u30B5\u30A4\u30BA\u3092\u30EA\u30BB\u30C3\u30C8",
|
|
1414
|
+
imageDelete: "\u753B\u50CF\u3092\u524A\u9664"
|
|
1383
1415
|
},
|
|
1384
1416
|
slashCommand: {
|
|
1385
1417
|
basicBlocks: "\u57FA\u672C\u30D6\u30ED\u30C3\u30AF",
|
|
@@ -22381,6 +22413,8 @@ import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
|
|
|
22381
22413
|
import { jsx as jsx73, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
22382
22414
|
var MIN_IMAGE_SIZE_PX = 40;
|
|
22383
22415
|
var AXIS_LOCK_THRESHOLD_PX = 4;
|
|
22416
|
+
var IMAGE_LAYOUTS = /* @__PURE__ */ new Set(["block", "left", "right"]);
|
|
22417
|
+
var IMAGE_WIDTH_PRESETS = /* @__PURE__ */ new Set(["sm", "md", "lg"]);
|
|
22384
22418
|
function toNullableNumber(value) {
|
|
22385
22419
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
22386
22420
|
if (typeof value === "string") {
|
|
@@ -22392,6 +22426,33 @@ function toNullableNumber(value) {
|
|
|
22392
22426
|
function clamp8(value, min, max) {
|
|
22393
22427
|
return Math.min(max, Math.max(min, value));
|
|
22394
22428
|
}
|
|
22429
|
+
function parseImageLayout(value) {
|
|
22430
|
+
if (typeof value === "string" && IMAGE_LAYOUTS.has(value)) {
|
|
22431
|
+
return value;
|
|
22432
|
+
}
|
|
22433
|
+
return "block";
|
|
22434
|
+
}
|
|
22435
|
+
function parseImageWidthPreset(value) {
|
|
22436
|
+
if (typeof value === "string" && IMAGE_WIDTH_PRESETS.has(value)) {
|
|
22437
|
+
return value;
|
|
22438
|
+
}
|
|
22439
|
+
return null;
|
|
22440
|
+
}
|
|
22441
|
+
function getImageLayoutStyles(layout) {
|
|
22442
|
+
if (layout === "left") {
|
|
22443
|
+
return {
|
|
22444
|
+
"data-image-layout": "left",
|
|
22445
|
+
style: "float:left;display:block;margin:0.25rem 1rem 0.75rem 0;"
|
|
22446
|
+
};
|
|
22447
|
+
}
|
|
22448
|
+
if (layout === "right") {
|
|
22449
|
+
return {
|
|
22450
|
+
"data-image-layout": "right",
|
|
22451
|
+
style: "float:right;display:block;margin:0.25rem 0 0.75rem 1rem;"
|
|
22452
|
+
};
|
|
22453
|
+
}
|
|
22454
|
+
return {};
|
|
22455
|
+
}
|
|
22395
22456
|
function ResizableImageNodeView(props) {
|
|
22396
22457
|
const { node, selected, updateAttributes, editor, getPos } = props;
|
|
22397
22458
|
const wrapperRef = useRef25(null);
|
|
@@ -22401,6 +22462,8 @@ function ResizableImageNodeView(props) {
|
|
|
22401
22462
|
const widthAttr = toNullableNumber(node.attrs["width"]);
|
|
22402
22463
|
const heightAttr = toNullableNumber(node.attrs["height"]);
|
|
22403
22464
|
const textAlign = String(node.attrs["textAlign"] ?? "");
|
|
22465
|
+
const imageLayout = parseImageLayout(node.attrs["imageLayout"]);
|
|
22466
|
+
const preserveAspectByDefault = imageLayout === "left" || imageLayout === "right";
|
|
22404
22467
|
const dragStateRef = useRef25(null);
|
|
22405
22468
|
useEffect30(() => {
|
|
22406
22469
|
const img = imgRef.current;
|
|
@@ -22449,7 +22512,8 @@ function ResizableImageNodeView(props) {
|
|
|
22449
22512
|
const dy = event.clientY - drag.startY;
|
|
22450
22513
|
let nextW = drag.startW;
|
|
22451
22514
|
let nextH = drag.startH;
|
|
22452
|
-
|
|
22515
|
+
const shouldPreserveAspect = preserveAspectByDefault ? !event.ctrlKey : event.ctrlKey;
|
|
22516
|
+
if (shouldPreserveAspect) {
|
|
22453
22517
|
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
22454
22518
|
nextW = clamp8(drag.startW + dx, MIN_IMAGE_SIZE_PX, drag.maxW);
|
|
22455
22519
|
nextH = clamp8(nextW / drag.aspect, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
|
|
@@ -22476,7 +22540,8 @@ function ResizableImageNodeView(props) {
|
|
|
22476
22540
|
if (!drag) return;
|
|
22477
22541
|
updateAttributes({
|
|
22478
22542
|
width: Math.round(drag.lastW),
|
|
22479
|
-
height: Math.round(drag.lastH)
|
|
22543
|
+
height: Math.round(drag.lastH),
|
|
22544
|
+
imageWidthPreset: null
|
|
22480
22545
|
});
|
|
22481
22546
|
};
|
|
22482
22547
|
const onResizePointerUp = (event) => {
|
|
@@ -22494,14 +22559,15 @@ function ResizableImageNodeView(props) {
|
|
|
22494
22559
|
finishResize();
|
|
22495
22560
|
};
|
|
22496
22561
|
const showHandle = selected || isHovered || isResizing;
|
|
22497
|
-
const wrapperAlignClass = textAlign === "center" ? "mx-auto" : textAlign === "right" ? "ml-auto" : textAlign === "justify" ? "mx-auto" : "";
|
|
22498
|
-
const
|
|
22562
|
+
const wrapperAlignClass = imageLayout === "block" ? textAlign === "center" ? "mx-auto" : textAlign === "right" ? "ml-auto" : textAlign === "justify" ? "mx-auto" : "" : "";
|
|
22563
|
+
const wrapperLayoutClass = imageLayout === "left" ? "float-left mr-4 mb-3 mt-1 clear-none max-w-[min(45%,20rem)]" : imageLayout === "right" ? "float-right ml-4 mb-3 mt-1 clear-none max-w-[min(45%,20rem)]" : "w-fit";
|
|
22499
22564
|
return /* @__PURE__ */ jsxs63(
|
|
22500
22565
|
NodeViewWrapper,
|
|
22501
22566
|
{
|
|
22502
22567
|
as: "div",
|
|
22503
22568
|
ref: wrapperRef,
|
|
22504
|
-
|
|
22569
|
+
"data-image-layout": imageLayout,
|
|
22570
|
+
className: ["relative block align-middle max-w-full my-4", wrapperLayoutClass, wrapperAlignClass].filter(Boolean).join(" "),
|
|
22505
22571
|
onMouseEnter: () => setIsHovered(true),
|
|
22506
22572
|
onMouseLeave: () => setIsHovered(false),
|
|
22507
22573
|
onClick: (e) => {
|
|
@@ -22571,6 +22637,25 @@ var ResizableImage = Image3.extend({
|
|
|
22571
22637
|
return Number.isFinite(parsed) ? parsed : null;
|
|
22572
22638
|
},
|
|
22573
22639
|
renderHTML: (attrs) => typeof attrs.height === "number" ? { height: attrs.height } : {}
|
|
22640
|
+
},
|
|
22641
|
+
imageLayout: {
|
|
22642
|
+
default: "block",
|
|
22643
|
+
parseHTML: (element) => {
|
|
22644
|
+
const explicit = element.getAttribute("data-image-layout");
|
|
22645
|
+
if (explicit) return parseImageLayout(explicit);
|
|
22646
|
+
const floatValue = element.style.float;
|
|
22647
|
+
if (floatValue === "left" || floatValue === "right") return floatValue;
|
|
22648
|
+
return "block";
|
|
22649
|
+
},
|
|
22650
|
+
renderHTML: (attrs) => getImageLayoutStyles(parseImageLayout(attrs.imageLayout))
|
|
22651
|
+
},
|
|
22652
|
+
imageWidthPreset: {
|
|
22653
|
+
default: null,
|
|
22654
|
+
parseHTML: (element) => parseImageWidthPreset(element.getAttribute("data-image-size")),
|
|
22655
|
+
renderHTML: (attrs) => {
|
|
22656
|
+
const preset = parseImageWidthPreset(attrs.imageWidthPreset);
|
|
22657
|
+
return preset ? { "data-image-size": preset } : {};
|
|
22658
|
+
}
|
|
22574
22659
|
}
|
|
22575
22660
|
};
|
|
22576
22661
|
},
|
|
@@ -22758,6 +22843,7 @@ import {
|
|
|
22758
22843
|
Palette as Palette2,
|
|
22759
22844
|
Quote as QuoteIcon,
|
|
22760
22845
|
Redo as RedoIcon,
|
|
22846
|
+
RotateCcw as RotateCcw2,
|
|
22761
22847
|
Smile as Smile3,
|
|
22762
22848
|
Strikethrough as StrikethroughIcon,
|
|
22763
22849
|
Subscript as SubscriptIcon,
|
|
@@ -22833,6 +22919,96 @@ var EditorColorPalette = ({
|
|
|
22833
22919
|
)) })
|
|
22834
22920
|
] });
|
|
22835
22921
|
|
|
22922
|
+
// src/components/UEditor/image-commands.ts
|
|
22923
|
+
import { NodeSelection, TextSelection } from "@tiptap/pm/state";
|
|
22924
|
+
var IMAGE_WIDTHS_BY_LAYOUT = {
|
|
22925
|
+
block: {
|
|
22926
|
+
sm: 180,
|
|
22927
|
+
md: 280,
|
|
22928
|
+
lg: 380
|
|
22929
|
+
},
|
|
22930
|
+
wrap: {
|
|
22931
|
+
sm: 140,
|
|
22932
|
+
md: 200,
|
|
22933
|
+
lg: 260
|
|
22934
|
+
}
|
|
22935
|
+
};
|
|
22936
|
+
function isSelectedImage(editor) {
|
|
22937
|
+
const { selection } = editor.state;
|
|
22938
|
+
return selection instanceof NodeSelection && selection.node.type.name === "image";
|
|
22939
|
+
}
|
|
22940
|
+
function applyImageLayout(editor, layout) {
|
|
22941
|
+
const { state, view } = editor;
|
|
22942
|
+
const { selection, schema } = state;
|
|
22943
|
+
if (!(selection instanceof NodeSelection) || selection.node.type.name !== "image") {
|
|
22944
|
+
editor.chain().focus().updateAttributes("image", { imageLayout: layout }).run();
|
|
22945
|
+
return;
|
|
22946
|
+
}
|
|
22947
|
+
let transaction = state.tr.setNodeMarkup(selection.from, void 0, {
|
|
22948
|
+
...selection.node.attrs,
|
|
22949
|
+
imageLayout: layout
|
|
22950
|
+
});
|
|
22951
|
+
if (layout !== "block") {
|
|
22952
|
+
const nextPos = transaction.mapping.map(selection.to);
|
|
22953
|
+
const nextNode = transaction.doc.nodeAt(nextPos);
|
|
22954
|
+
if (!nextNode || nextNode.type.name !== "paragraph") {
|
|
22955
|
+
const paragraph = schema.nodes.paragraph?.create();
|
|
22956
|
+
if (paragraph) {
|
|
22957
|
+
transaction = transaction.insert(nextPos, paragraph);
|
|
22958
|
+
}
|
|
22959
|
+
}
|
|
22960
|
+
const resolvedPos = transaction.doc.resolve(Math.min(nextPos + 1, transaction.doc.content.size));
|
|
22961
|
+
transaction = transaction.setSelection(TextSelection.near(resolvedPos));
|
|
22962
|
+
} else {
|
|
22963
|
+
const resolvedPos = transaction.doc.resolve(selection.from);
|
|
22964
|
+
transaction = transaction.setSelection(NodeSelection.create(transaction.doc, resolvedPos.pos));
|
|
22965
|
+
}
|
|
22966
|
+
view.dispatch(transaction.scrollIntoView());
|
|
22967
|
+
view.focus();
|
|
22968
|
+
}
|
|
22969
|
+
function applyImageWidthPreset(editor, preset) {
|
|
22970
|
+
const attrs = editor.getAttributes("image");
|
|
22971
|
+
const mode = attrs.imageLayout === "left" || attrs.imageLayout === "right" ? "wrap" : "block";
|
|
22972
|
+
const width = IMAGE_WIDTHS_BY_LAYOUT[mode][preset];
|
|
22973
|
+
if (!isSelectedImage(editor)) {
|
|
22974
|
+
editor.chain().focus().updateAttributes("image", { width, imageWidthPreset: preset }).run();
|
|
22975
|
+
return;
|
|
22976
|
+
}
|
|
22977
|
+
const { state, view } = editor;
|
|
22978
|
+
const selection = state.selection;
|
|
22979
|
+
const transaction = state.tr.setNodeMarkup(selection.from, void 0, {
|
|
22980
|
+
...selection.node.attrs,
|
|
22981
|
+
width,
|
|
22982
|
+
imageWidthPreset: preset
|
|
22983
|
+
});
|
|
22984
|
+
view.dispatch(transaction.scrollIntoView());
|
|
22985
|
+
view.focus();
|
|
22986
|
+
}
|
|
22987
|
+
function resetImageSize(editor) {
|
|
22988
|
+
if (!isSelectedImage(editor)) {
|
|
22989
|
+
editor.chain().focus().updateAttributes("image", {
|
|
22990
|
+
width: null,
|
|
22991
|
+
height: null,
|
|
22992
|
+
imageWidthPreset: null
|
|
22993
|
+
}).run();
|
|
22994
|
+
return;
|
|
22995
|
+
}
|
|
22996
|
+
const { state, view } = editor;
|
|
22997
|
+
const selection = state.selection;
|
|
22998
|
+
const transaction = state.tr.setNodeMarkup(selection.from, void 0, {
|
|
22999
|
+
...selection.node.attrs,
|
|
23000
|
+
width: null,
|
|
23001
|
+
height: null,
|
|
23002
|
+
imageWidthPreset: null
|
|
23003
|
+
});
|
|
23004
|
+
view.dispatch(transaction.scrollIntoView());
|
|
23005
|
+
view.focus();
|
|
23006
|
+
}
|
|
23007
|
+
function deleteSelectedImage(editor) {
|
|
23008
|
+
if (!isSelectedImage(editor)) return;
|
|
23009
|
+
editor.chain().focus().deleteSelection().run();
|
|
23010
|
+
}
|
|
23011
|
+
|
|
22836
23012
|
// src/components/UEditor/inputs.tsx
|
|
22837
23013
|
import { useEffect as useEffect31, useRef as useRef26, useState as useState42 } from "react";
|
|
22838
23014
|
import { Check as Check10, X as X18 } from "lucide-react";
|
|
@@ -23169,6 +23345,10 @@ var EditorToolbar = ({
|
|
|
23169
23345
|
const fileInputRef = useRef28(null);
|
|
23170
23346
|
const [isUploadingImage, setIsUploadingImage] = useState44(false);
|
|
23171
23347
|
const [imageUploadError, setImageUploadError] = useState44(null);
|
|
23348
|
+
const isImageSelected = editor.isActive("image");
|
|
23349
|
+
const imageAttrs = editor.getAttributes("image");
|
|
23350
|
+
const imageLayout = imageAttrs.imageLayout === "left" || imageAttrs.imageLayout === "right" ? imageAttrs.imageLayout : "block";
|
|
23351
|
+
const imageWidthPreset = imageAttrs.imageWidthPreset === "sm" || imageAttrs.imageWidthPreset === "md" || imageAttrs.imageWidthPreset === "lg" ? imageAttrs.imageWidthPreset : null;
|
|
23172
23352
|
const insertImageFiles = async (files) => {
|
|
23173
23353
|
if (files.length === 0) return;
|
|
23174
23354
|
setIsUploadingImage(true);
|
|
@@ -23501,6 +23681,85 @@ var EditorToolbar = ({
|
|
|
23501
23681
|
void insertImageFiles(files);
|
|
23502
23682
|
}
|
|
23503
23683
|
}
|
|
23684
|
+
),
|
|
23685
|
+
/* @__PURE__ */ jsx77("div", { className: "my-1 border-t" }),
|
|
23686
|
+
/* @__PURE__ */ jsx77(
|
|
23687
|
+
DropdownMenuItem,
|
|
23688
|
+
{
|
|
23689
|
+
icon: AlignCenter,
|
|
23690
|
+
label: t("toolbar.imageLayoutBlock"),
|
|
23691
|
+
onClick: () => applyImageLayout(editor, "block"),
|
|
23692
|
+
active: isImageSelected && imageLayout === "block",
|
|
23693
|
+
disabled: !isImageSelected
|
|
23694
|
+
}
|
|
23695
|
+
),
|
|
23696
|
+
/* @__PURE__ */ jsx77(
|
|
23697
|
+
DropdownMenuItem,
|
|
23698
|
+
{
|
|
23699
|
+
icon: AlignLeft,
|
|
23700
|
+
label: t("toolbar.imageLayoutLeft"),
|
|
23701
|
+
onClick: () => applyImageLayout(editor, "left"),
|
|
23702
|
+
active: isImageSelected && imageLayout === "left",
|
|
23703
|
+
disabled: !isImageSelected
|
|
23704
|
+
}
|
|
23705
|
+
),
|
|
23706
|
+
/* @__PURE__ */ jsx77(
|
|
23707
|
+
DropdownMenuItem,
|
|
23708
|
+
{
|
|
23709
|
+
icon: AlignRight,
|
|
23710
|
+
label: t("toolbar.imageLayoutRight"),
|
|
23711
|
+
onClick: () => applyImageLayout(editor, "right"),
|
|
23712
|
+
active: isImageSelected && imageLayout === "right",
|
|
23713
|
+
disabled: !isImageSelected
|
|
23714
|
+
}
|
|
23715
|
+
),
|
|
23716
|
+
/* @__PURE__ */ jsx77("div", { className: "my-1 border-t" }),
|
|
23717
|
+
/* @__PURE__ */ jsx77(
|
|
23718
|
+
DropdownMenuItem,
|
|
23719
|
+
{
|
|
23720
|
+
label: t("toolbar.imageWidthSm"),
|
|
23721
|
+
onClick: () => applyImageWidthPreset(editor, "sm"),
|
|
23722
|
+
active: isImageSelected && imageWidthPreset === "sm",
|
|
23723
|
+
disabled: !isImageSelected
|
|
23724
|
+
}
|
|
23725
|
+
),
|
|
23726
|
+
/* @__PURE__ */ jsx77(
|
|
23727
|
+
DropdownMenuItem,
|
|
23728
|
+
{
|
|
23729
|
+
label: t("toolbar.imageWidthMd"),
|
|
23730
|
+
onClick: () => applyImageWidthPreset(editor, "md"),
|
|
23731
|
+
active: isImageSelected && imageWidthPreset === "md",
|
|
23732
|
+
disabled: !isImageSelected
|
|
23733
|
+
}
|
|
23734
|
+
),
|
|
23735
|
+
/* @__PURE__ */ jsx77(
|
|
23736
|
+
DropdownMenuItem,
|
|
23737
|
+
{
|
|
23738
|
+
label: t("toolbar.imageWidthLg"),
|
|
23739
|
+
onClick: () => applyImageWidthPreset(editor, "lg"),
|
|
23740
|
+
active: isImageSelected && imageWidthPreset === "lg",
|
|
23741
|
+
disabled: !isImageSelected
|
|
23742
|
+
}
|
|
23743
|
+
),
|
|
23744
|
+
/* @__PURE__ */ jsx77("div", { className: "my-1 border-t" }),
|
|
23745
|
+
/* @__PURE__ */ jsx77(
|
|
23746
|
+
DropdownMenuItem,
|
|
23747
|
+
{
|
|
23748
|
+
icon: RotateCcw2,
|
|
23749
|
+
label: t("toolbar.imageResetSize"),
|
|
23750
|
+
onClick: () => resetImageSize(editor),
|
|
23751
|
+
disabled: !isImageSelected
|
|
23752
|
+
}
|
|
23753
|
+
),
|
|
23754
|
+
/* @__PURE__ */ jsx77(
|
|
23755
|
+
DropdownMenuItem,
|
|
23756
|
+
{
|
|
23757
|
+
icon: Trash22,
|
|
23758
|
+
label: t("toolbar.imageDelete"),
|
|
23759
|
+
onClick: () => deleteSelectedImage(editor),
|
|
23760
|
+
disabled: !isImageSelected,
|
|
23761
|
+
destructive: true
|
|
23762
|
+
}
|
|
23504
23763
|
)
|
|
23505
23764
|
] })
|
|
23506
23765
|
}
|
|
@@ -23619,6 +23878,9 @@ var EditorToolbar = ({
|
|
|
23619
23878
|
import React70, { useCallback as useCallback17, useEffect as useEffect33, useMemo as useMemo22, useRef as useRef29, useState as useState45 } from "react";
|
|
23620
23879
|
import { createPortal as createPortal8 } from "react-dom";
|
|
23621
23880
|
import {
|
|
23881
|
+
AlignCenter as AlignCenter2,
|
|
23882
|
+
AlignLeft as AlignLeft2,
|
|
23883
|
+
AlignRight as AlignRight2,
|
|
23622
23884
|
Bold as BoldIcon2,
|
|
23623
23885
|
Code as CodeIcon2,
|
|
23624
23886
|
FileCode as FileCode4,
|
|
@@ -23634,9 +23896,11 @@ import {
|
|
|
23634
23896
|
Palette as Palette3,
|
|
23635
23897
|
Plus as Plus3,
|
|
23636
23898
|
Quote as QuoteIcon2,
|
|
23899
|
+
RotateCcw as RotateCcw3,
|
|
23637
23900
|
Subscript as SubscriptIcon2,
|
|
23638
23901
|
Superscript as SuperscriptIcon2,
|
|
23639
23902
|
Table as TableIcon2,
|
|
23903
|
+
Trash2 as Trash23,
|
|
23640
23904
|
Type as Type3,
|
|
23641
23905
|
Underline as UnderlineIcon2,
|
|
23642
23906
|
Strikethrough as StrikethroughIcon2
|
|
@@ -23835,6 +24099,10 @@ var BubbleMenuContent = ({
|
|
|
23835
24099
|
const { textColors, highlightColors } = useEditorColors();
|
|
23836
24100
|
const [showLinkInput, setShowLinkInput] = useState45(false);
|
|
23837
24101
|
const [showEditorColorPalette, setShowEditorColorPalette] = useState45(false);
|
|
24102
|
+
const isImageSelected = editor.isActive("image");
|
|
24103
|
+
const imageAttrs = editor.getAttributes("image");
|
|
24104
|
+
const imageLayout = imageAttrs.imageLayout === "left" || imageAttrs.imageLayout === "right" ? imageAttrs.imageLayout : "block";
|
|
24105
|
+
const imageWidthPreset = imageAttrs.imageWidthPreset === "sm" || imageAttrs.imageWidthPreset === "md" || imageAttrs.imageWidthPreset === "lg" ? imageAttrs.imageWidthPreset : null;
|
|
23838
24106
|
useEffect33(() => {
|
|
23839
24107
|
onKeepOpenChange?.(showLinkInput);
|
|
23840
24108
|
}, [onKeepOpenChange, showLinkInput]);
|
|
@@ -23909,6 +24177,20 @@ var BubbleMenuContent = ({
|
|
|
23909
24177
|
) })
|
|
23910
24178
|
] });
|
|
23911
24179
|
}
|
|
24180
|
+
if (isImageSelected) {
|
|
24181
|
+
return /* @__PURE__ */ jsxs68("div", { className: "flex items-center gap-0.5 p-1", children: [
|
|
24182
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => applyImageLayout(editor, "block"), active: imageLayout === "block", title: t("toolbar.imageLayoutBlock"), children: /* @__PURE__ */ jsx78(AlignCenter2, { className: "w-4 h-4" }) }),
|
|
24183
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => applyImageLayout(editor, "left"), active: imageLayout === "left", title: t("toolbar.imageLayoutLeft"), children: /* @__PURE__ */ jsx78(AlignLeft2, { className: "w-4 h-4" }) }),
|
|
24184
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => applyImageLayout(editor, "right"), active: imageLayout === "right", title: t("toolbar.imageLayoutRight"), children: /* @__PURE__ */ jsx78(AlignRight2, { className: "w-4 h-4" }) }),
|
|
24185
|
+
/* @__PURE__ */ jsx78("div", { className: "w-px h-6 bg-border/50 mx-1" }),
|
|
24186
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => applyImageWidthPreset(editor, "sm"), active: imageWidthPreset === "sm", title: t("toolbar.imageWidthSm"), children: /* @__PURE__ */ jsx78("span", { className: "text-[10px] font-semibold", children: "S" }) }),
|
|
24187
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => applyImageWidthPreset(editor, "md"), active: imageWidthPreset === "md", title: t("toolbar.imageWidthMd"), children: /* @__PURE__ */ jsx78("span", { className: "text-[10px] font-semibold", children: "M" }) }),
|
|
24188
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => applyImageWidthPreset(editor, "lg"), active: imageWidthPreset === "lg", title: t("toolbar.imageWidthLg"), children: /* @__PURE__ */ jsx78("span", { className: "text-[10px] font-semibold", children: "L" }) }),
|
|
24189
|
+
/* @__PURE__ */ jsx78("div", { className: "w-px h-6 bg-border/50 mx-1" }),
|
|
24190
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => resetImageSize(editor), title: t("toolbar.imageResetSize"), children: /* @__PURE__ */ jsx78(RotateCcw3, { className: "w-4 h-4" }) }),
|
|
24191
|
+
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => deleteSelectedImage(editor), title: t("toolbar.imageDelete"), className: "text-destructive hover:text-destructive", children: /* @__PURE__ */ jsx78(Trash23, { className: "w-4 h-4" }) })
|
|
24192
|
+
] });
|
|
24193
|
+
}
|
|
23912
24194
|
return /* @__PURE__ */ jsxs68("div", { className: "flex items-center gap-0.5 p-1", children: [
|
|
23913
24195
|
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => editor.chain().focus().toggleBold().run(), active: editor.isActive("bold"), title: t("toolbar.bold"), children: /* @__PURE__ */ jsx78(BoldIcon2, { className: "w-4 h-4" }) }),
|
|
23914
24196
|
/* @__PURE__ */ jsx78(ToolbarButton, { onClick: () => editor.chain().focus().toggleItalic().run(), active: editor.isActive("italic"), title: t("toolbar.italic"), children: /* @__PURE__ */ jsx78(ItalicIcon2, { className: "w-4 h-4" }) }),
|
|
@@ -23961,19 +24243,28 @@ var BubbleMenuContent = ({
|
|
|
23961
24243
|
] });
|
|
23962
24244
|
};
|
|
23963
24245
|
var CustomBubbleMenu = ({ editor }) => {
|
|
24246
|
+
const SHOW_DELAY_MS = 180;
|
|
23964
24247
|
const [isVisible, setIsVisible] = useState45(false);
|
|
23965
24248
|
const [position, setPosition] = useState45({ top: 0, left: 0 });
|
|
23966
24249
|
const menuRef = useRef29(null);
|
|
23967
24250
|
const keepOpenRef = useRef29(false);
|
|
24251
|
+
const showTimeoutRef = useRef29(null);
|
|
23968
24252
|
const setKeepOpen = useCallback17((next) => {
|
|
23969
24253
|
keepOpenRef.current = next;
|
|
23970
24254
|
if (next) setIsVisible(true);
|
|
23971
24255
|
}, []);
|
|
23972
24256
|
useEffect33(() => {
|
|
24257
|
+
const clearShowTimeout = () => {
|
|
24258
|
+
if (showTimeoutRef.current) {
|
|
24259
|
+
clearTimeout(showTimeoutRef.current);
|
|
24260
|
+
showTimeoutRef.current = null;
|
|
24261
|
+
}
|
|
24262
|
+
};
|
|
23973
24263
|
const updatePosition = () => {
|
|
23974
24264
|
const { state, view } = editor;
|
|
23975
24265
|
const { from, to, empty } = state.selection;
|
|
23976
24266
|
if (!keepOpenRef.current && (empty || !view.hasFocus())) {
|
|
24267
|
+
clearShowTimeout();
|
|
23977
24268
|
setIsVisible(false);
|
|
23978
24269
|
return;
|
|
23979
24270
|
}
|
|
@@ -23982,15 +24273,28 @@ var CustomBubbleMenu = ({ editor }) => {
|
|
|
23982
24273
|
const left = (start.left + end.left) / 2;
|
|
23983
24274
|
const top = start.top - 10;
|
|
23984
24275
|
setPosition({ top, left });
|
|
23985
|
-
|
|
24276
|
+
if (keepOpenRef.current) {
|
|
24277
|
+
clearShowTimeout();
|
|
24278
|
+
setIsVisible(true);
|
|
24279
|
+
return;
|
|
24280
|
+
}
|
|
24281
|
+
clearShowTimeout();
|
|
24282
|
+
showTimeoutRef.current = setTimeout(() => {
|
|
24283
|
+
setIsVisible(true);
|
|
24284
|
+
showTimeoutRef.current = null;
|
|
24285
|
+
}, SHOW_DELAY_MS);
|
|
23986
24286
|
};
|
|
23987
24287
|
const handleBlur = () => {
|
|
23988
|
-
if (!keepOpenRef.current)
|
|
24288
|
+
if (!keepOpenRef.current) {
|
|
24289
|
+
clearShowTimeout();
|
|
24290
|
+
setIsVisible(false);
|
|
24291
|
+
}
|
|
23989
24292
|
};
|
|
23990
24293
|
editor.on("selectionUpdate", updatePosition);
|
|
23991
24294
|
editor.on("focus", updatePosition);
|
|
23992
24295
|
editor.on("blur", handleBlur);
|
|
23993
24296
|
return () => {
|
|
24297
|
+
clearShowTimeout();
|
|
23994
24298
|
editor.off("selectionUpdate", updatePosition);
|
|
23995
24299
|
editor.off("focus", updatePosition);
|
|
23996
24300
|
editor.off("blur", handleBlur);
|
|
@@ -24474,7 +24778,21 @@ var UEditor = React71.forwardRef(({
|
|
|
24474
24778
|
"[&_blockquote]:rounded-r-lg",
|
|
24475
24779
|
"[&_blockquote]:italic",
|
|
24476
24780
|
"[&_blockquote]:text-muted-foreground",
|
|
24477
|
-
"[&_blockquote_p]:my-0"
|
|
24781
|
+
"[&_blockquote_p]:my-0",
|
|
24782
|
+
"[&_[data-image-layout='left']+p]:mt-1",
|
|
24783
|
+
"[&_[data-image-layout='left']+p]:min-h-[5rem]",
|
|
24784
|
+
"[&_[data-image-layout='right']+p]:mt-1",
|
|
24785
|
+
"[&_[data-image-layout='right']+p]:min-h-[5rem]",
|
|
24786
|
+
"max-md:[&_[data-image-layout='left']]:float-none",
|
|
24787
|
+
"max-md:[&_[data-image-layout='left']]:mr-0",
|
|
24788
|
+
"max-md:[&_[data-image-layout='left']]:ml-0",
|
|
24789
|
+
"max-md:[&_[data-image-layout='left']]:max-w-full",
|
|
24790
|
+
"max-md:[&_[data-image-layout='right']]:float-none",
|
|
24791
|
+
"max-md:[&_[data-image-layout='right']]:mr-0",
|
|
24792
|
+
"max-md:[&_[data-image-layout='right']]:ml-0",
|
|
24793
|
+
"max-md:[&_[data-image-layout='right']]:max-w-full",
|
|
24794
|
+
"max-md:[&_[data-image-layout='left']+p]:min-h-0",
|
|
24795
|
+
"max-md:[&_[data-image-layout='right']+p]:min-h-0"
|
|
24478
24796
|
)
|
|
24479
24797
|
}
|
|
24480
24798
|
},
|