@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/api-reference.json
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -890,7 +890,15 @@ var en_default = {
|
|
|
890
890
|
heading1: "Heading 1",
|
|
891
891
|
heading2: "Heading 2",
|
|
892
892
|
heading3: "Heading 3",
|
|
893
|
-
emoji: "Insert Emoji"
|
|
893
|
+
emoji: "Insert Emoji",
|
|
894
|
+
imageLayoutBlock: "Image Block",
|
|
895
|
+
imageLayoutLeft: "Wrap Text Right",
|
|
896
|
+
imageLayoutRight: "Wrap Text Left",
|
|
897
|
+
imageWidthSm: "Image Width Small",
|
|
898
|
+
imageWidthMd: "Image Width Medium",
|
|
899
|
+
imageWidthLg: "Image Width Large",
|
|
900
|
+
imageResetSize: "Reset Image Size",
|
|
901
|
+
imageDelete: "Delete Image"
|
|
894
902
|
},
|
|
895
903
|
slashCommand: {
|
|
896
904
|
basicBlocks: "Basic Blocks",
|
|
@@ -1114,7 +1122,15 @@ var vi_default = {
|
|
|
1114
1122
|
heading1: "Ti\xEAu \u0111\u1EC1 1",
|
|
1115
1123
|
heading2: "Ti\xEAu \u0111\u1EC1 2",
|
|
1116
1124
|
heading3: "Ti\xEAu \u0111\u1EC1 3",
|
|
1117
|
-
emoji: "Ch\xE8n Emoji"
|
|
1125
|
+
emoji: "Ch\xE8n Emoji",
|
|
1126
|
+
imageLayoutBlock: "\u1EA2nh D\u1EA1ng Kh\u1ED1i",
|
|
1127
|
+
imageLayoutLeft: "\u1EA2nh Tr\xE1i, Ch\u1EEF Ph\u1EA3i",
|
|
1128
|
+
imageLayoutRight: "\u1EA2nh Ph\u1EA3i, Ch\u1EEF Tr\xE1i",
|
|
1129
|
+
imageWidthSm: "\u1EA2nh Nh\u1ECF",
|
|
1130
|
+
imageWidthMd: "\u1EA2nh V\u1EEBa",
|
|
1131
|
+
imageWidthLg: "\u1EA2nh L\u1EDBn",
|
|
1132
|
+
imageResetSize: "\u0110\u1EB7t L\u1EA1i K\xEDch Th\u01B0\u1EDBc \u1EA2nh",
|
|
1133
|
+
imageDelete: "X\xF3a \u1EA2nh"
|
|
1118
1134
|
},
|
|
1119
1135
|
slashCommand: {
|
|
1120
1136
|
basicBlocks: "Kh\u1ED1i c\u01A1 b\u1EA3n",
|
|
@@ -1338,7 +1354,15 @@ var ko_default = {
|
|
|
1338
1354
|
heading1: "\uC81C\uBAA9 1",
|
|
1339
1355
|
heading2: "\uC81C\uBAA9 2",
|
|
1340
1356
|
heading3: "\uC81C\uBAA9 3",
|
|
1341
|
-
emoji: "\uC774\uBAA8\uC9C0 \uC0BD\uC785"
|
|
1357
|
+
emoji: "\uC774\uBAA8\uC9C0 \uC0BD\uC785",
|
|
1358
|
+
imageLayoutBlock: "\uC774\uBBF8\uC9C0 \uBE14\uB85D",
|
|
1359
|
+
imageLayoutLeft: "\uC67C\uCABD \uC774\uBBF8\uC9C0, \uC624\uB978\uCABD \uD14D\uC2A4\uD2B8",
|
|
1360
|
+
imageLayoutRight: "\uC624\uB978\uCABD \uC774\uBBF8\uC9C0, \uC67C\uCABD \uD14D\uC2A4\uD2B8",
|
|
1361
|
+
imageWidthSm: "\uC791\uC740 \uC774\uBBF8\uC9C0",
|
|
1362
|
+
imageWidthMd: "\uC911\uAC04 \uC774\uBBF8\uC9C0",
|
|
1363
|
+
imageWidthLg: "\uD070 \uC774\uBBF8\uC9C0",
|
|
1364
|
+
imageResetSize: "\uC774\uBBF8\uC9C0 \uD06C\uAE30 \uCD08\uAE30\uD654",
|
|
1365
|
+
imageDelete: "\uC774\uBBF8\uC9C0 \uC0AD\uC81C"
|
|
1342
1366
|
},
|
|
1343
1367
|
slashCommand: {
|
|
1344
1368
|
basicBlocks: "\uAE30\uBCF8 \uBE14\uB85D",
|
|
@@ -1561,7 +1585,15 @@ var ja_default = {
|
|
|
1561
1585
|
heading1: "\u898B\u51FA\u3057 1",
|
|
1562
1586
|
heading2: "\u898B\u51FA\u3057 2",
|
|
1563
1587
|
heading3: "\u898B\u51FA\u3057 3",
|
|
1564
|
-
emoji: "\u7D75\u6587\u5B57\u3092\u633F\u5165"
|
|
1588
|
+
emoji: "\u7D75\u6587\u5B57\u3092\u633F\u5165",
|
|
1589
|
+
imageLayoutBlock: "\u753B\u50CF\u30D6\u30ED\u30C3\u30AF",
|
|
1590
|
+
imageLayoutLeft: "\u753B\u50CF\u3092\u5DE6\u3001\u6587\u5B57\u3092\u53F3\u306B\u56DE\u308A\u8FBC\u307F",
|
|
1591
|
+
imageLayoutRight: "\u753B\u50CF\u3092\u53F3\u3001\u6587\u5B57\u3092\u5DE6\u306B\u56DE\u308A\u8FBC\u307F",
|
|
1592
|
+
imageWidthSm: "\u753B\u50CF \u5C0F",
|
|
1593
|
+
imageWidthMd: "\u753B\u50CF \u4E2D",
|
|
1594
|
+
imageWidthLg: "\u753B\u50CF \u5927",
|
|
1595
|
+
imageResetSize: "\u753B\u50CF\u30B5\u30A4\u30BA\u3092\u30EA\u30BB\u30C3\u30C8",
|
|
1596
|
+
imageDelete: "\u753B\u50CF\u3092\u524A\u9664"
|
|
1565
1597
|
},
|
|
1566
1598
|
slashCommand: {
|
|
1567
1599
|
basicBlocks: "\u57FA\u672C\u30D6\u30ED\u30C3\u30AF",
|
|
@@ -22535,6 +22567,8 @@ var import_react44 = require("@tiptap/react");
|
|
|
22535
22567
|
var import_jsx_runtime73 = require("react/jsx-runtime");
|
|
22536
22568
|
var MIN_IMAGE_SIZE_PX = 40;
|
|
22537
22569
|
var AXIS_LOCK_THRESHOLD_PX = 4;
|
|
22570
|
+
var IMAGE_LAYOUTS = /* @__PURE__ */ new Set(["block", "left", "right"]);
|
|
22571
|
+
var IMAGE_WIDTH_PRESETS = /* @__PURE__ */ new Set(["sm", "md", "lg"]);
|
|
22538
22572
|
function toNullableNumber(value) {
|
|
22539
22573
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
22540
22574
|
if (typeof value === "string") {
|
|
@@ -22546,6 +22580,33 @@ function toNullableNumber(value) {
|
|
|
22546
22580
|
function clamp8(value, min, max) {
|
|
22547
22581
|
return Math.min(max, Math.max(min, value));
|
|
22548
22582
|
}
|
|
22583
|
+
function parseImageLayout(value) {
|
|
22584
|
+
if (typeof value === "string" && IMAGE_LAYOUTS.has(value)) {
|
|
22585
|
+
return value;
|
|
22586
|
+
}
|
|
22587
|
+
return "block";
|
|
22588
|
+
}
|
|
22589
|
+
function parseImageWidthPreset(value) {
|
|
22590
|
+
if (typeof value === "string" && IMAGE_WIDTH_PRESETS.has(value)) {
|
|
22591
|
+
return value;
|
|
22592
|
+
}
|
|
22593
|
+
return null;
|
|
22594
|
+
}
|
|
22595
|
+
function getImageLayoutStyles(layout) {
|
|
22596
|
+
if (layout === "left") {
|
|
22597
|
+
return {
|
|
22598
|
+
"data-image-layout": "left",
|
|
22599
|
+
style: "float:left;display:block;margin:0.25rem 1rem 0.75rem 0;"
|
|
22600
|
+
};
|
|
22601
|
+
}
|
|
22602
|
+
if (layout === "right") {
|
|
22603
|
+
return {
|
|
22604
|
+
"data-image-layout": "right",
|
|
22605
|
+
style: "float:right;display:block;margin:0.25rem 0 0.75rem 1rem;"
|
|
22606
|
+
};
|
|
22607
|
+
}
|
|
22608
|
+
return {};
|
|
22609
|
+
}
|
|
22549
22610
|
function ResizableImageNodeView(props) {
|
|
22550
22611
|
const { node, selected, updateAttributes, editor, getPos } = props;
|
|
22551
22612
|
const wrapperRef = (0, import_react43.useRef)(null);
|
|
@@ -22555,6 +22616,8 @@ function ResizableImageNodeView(props) {
|
|
|
22555
22616
|
const widthAttr = toNullableNumber(node.attrs["width"]);
|
|
22556
22617
|
const heightAttr = toNullableNumber(node.attrs["height"]);
|
|
22557
22618
|
const textAlign = String(node.attrs["textAlign"] ?? "");
|
|
22619
|
+
const imageLayout = parseImageLayout(node.attrs["imageLayout"]);
|
|
22620
|
+
const preserveAspectByDefault = imageLayout === "left" || imageLayout === "right";
|
|
22558
22621
|
const dragStateRef = (0, import_react43.useRef)(null);
|
|
22559
22622
|
(0, import_react43.useEffect)(() => {
|
|
22560
22623
|
const img = imgRef.current;
|
|
@@ -22603,7 +22666,8 @@ function ResizableImageNodeView(props) {
|
|
|
22603
22666
|
const dy = event.clientY - drag.startY;
|
|
22604
22667
|
let nextW = drag.startW;
|
|
22605
22668
|
let nextH = drag.startH;
|
|
22606
|
-
|
|
22669
|
+
const shouldPreserveAspect = preserveAspectByDefault ? !event.ctrlKey : event.ctrlKey;
|
|
22670
|
+
if (shouldPreserveAspect) {
|
|
22607
22671
|
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
22608
22672
|
nextW = clamp8(drag.startW + dx, MIN_IMAGE_SIZE_PX, drag.maxW);
|
|
22609
22673
|
nextH = clamp8(nextW / drag.aspect, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
|
|
@@ -22630,7 +22694,8 @@ function ResizableImageNodeView(props) {
|
|
|
22630
22694
|
if (!drag) return;
|
|
22631
22695
|
updateAttributes({
|
|
22632
22696
|
width: Math.round(drag.lastW),
|
|
22633
|
-
height: Math.round(drag.lastH)
|
|
22697
|
+
height: Math.round(drag.lastH),
|
|
22698
|
+
imageWidthPreset: null
|
|
22634
22699
|
});
|
|
22635
22700
|
};
|
|
22636
22701
|
const onResizePointerUp = (event) => {
|
|
@@ -22648,14 +22713,15 @@ function ResizableImageNodeView(props) {
|
|
|
22648
22713
|
finishResize();
|
|
22649
22714
|
};
|
|
22650
22715
|
const showHandle = selected || isHovered || isResizing;
|
|
22651
|
-
const wrapperAlignClass = textAlign === "center" ? "mx-auto" : textAlign === "right" ? "ml-auto" : textAlign === "justify" ? "mx-auto" : "";
|
|
22652
|
-
const
|
|
22716
|
+
const wrapperAlignClass = imageLayout === "block" ? textAlign === "center" ? "mx-auto" : textAlign === "right" ? "ml-auto" : textAlign === "justify" ? "mx-auto" : "" : "";
|
|
22717
|
+
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";
|
|
22653
22718
|
return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(
|
|
22654
22719
|
import_react44.NodeViewWrapper,
|
|
22655
22720
|
{
|
|
22656
22721
|
as: "div",
|
|
22657
22722
|
ref: wrapperRef,
|
|
22658
|
-
|
|
22723
|
+
"data-image-layout": imageLayout,
|
|
22724
|
+
className: ["relative block align-middle max-w-full my-4", wrapperLayoutClass, wrapperAlignClass].filter(Boolean).join(" "),
|
|
22659
22725
|
onMouseEnter: () => setIsHovered(true),
|
|
22660
22726
|
onMouseLeave: () => setIsHovered(false),
|
|
22661
22727
|
onClick: (e) => {
|
|
@@ -22725,6 +22791,25 @@ var ResizableImage = import_extension_image.default.extend({
|
|
|
22725
22791
|
return Number.isFinite(parsed) ? parsed : null;
|
|
22726
22792
|
},
|
|
22727
22793
|
renderHTML: (attrs) => typeof attrs.height === "number" ? { height: attrs.height } : {}
|
|
22794
|
+
},
|
|
22795
|
+
imageLayout: {
|
|
22796
|
+
default: "block",
|
|
22797
|
+
parseHTML: (element) => {
|
|
22798
|
+
const explicit = element.getAttribute("data-image-layout");
|
|
22799
|
+
if (explicit) return parseImageLayout(explicit);
|
|
22800
|
+
const floatValue = element.style.float;
|
|
22801
|
+
if (floatValue === "left" || floatValue === "right") return floatValue;
|
|
22802
|
+
return "block";
|
|
22803
|
+
},
|
|
22804
|
+
renderHTML: (attrs) => getImageLayoutStyles(parseImageLayout(attrs.imageLayout))
|
|
22805
|
+
},
|
|
22806
|
+
imageWidthPreset: {
|
|
22807
|
+
default: null,
|
|
22808
|
+
parseHTML: (element) => parseImageWidthPreset(element.getAttribute("data-image-size")),
|
|
22809
|
+
renderHTML: (attrs) => {
|
|
22810
|
+
const preset = parseImageWidthPreset(attrs.imageWidthPreset);
|
|
22811
|
+
return preset ? { "data-image-size": preset } : {};
|
|
22812
|
+
}
|
|
22728
22813
|
}
|
|
22729
22814
|
};
|
|
22730
22815
|
},
|
|
@@ -22953,6 +23038,96 @@ var EditorColorPalette = ({
|
|
|
22953
23038
|
)) })
|
|
22954
23039
|
] });
|
|
22955
23040
|
|
|
23041
|
+
// src/components/UEditor/image-commands.ts
|
|
23042
|
+
var import_state4 = require("@tiptap/pm/state");
|
|
23043
|
+
var IMAGE_WIDTHS_BY_LAYOUT = {
|
|
23044
|
+
block: {
|
|
23045
|
+
sm: 180,
|
|
23046
|
+
md: 280,
|
|
23047
|
+
lg: 380
|
|
23048
|
+
},
|
|
23049
|
+
wrap: {
|
|
23050
|
+
sm: 140,
|
|
23051
|
+
md: 200,
|
|
23052
|
+
lg: 260
|
|
23053
|
+
}
|
|
23054
|
+
};
|
|
23055
|
+
function isSelectedImage(editor) {
|
|
23056
|
+
const { selection } = editor.state;
|
|
23057
|
+
return selection instanceof import_state4.NodeSelection && selection.node.type.name === "image";
|
|
23058
|
+
}
|
|
23059
|
+
function applyImageLayout(editor, layout) {
|
|
23060
|
+
const { state, view } = editor;
|
|
23061
|
+
const { selection, schema } = state;
|
|
23062
|
+
if (!(selection instanceof import_state4.NodeSelection) || selection.node.type.name !== "image") {
|
|
23063
|
+
editor.chain().focus().updateAttributes("image", { imageLayout: layout }).run();
|
|
23064
|
+
return;
|
|
23065
|
+
}
|
|
23066
|
+
let transaction = state.tr.setNodeMarkup(selection.from, void 0, {
|
|
23067
|
+
...selection.node.attrs,
|
|
23068
|
+
imageLayout: layout
|
|
23069
|
+
});
|
|
23070
|
+
if (layout !== "block") {
|
|
23071
|
+
const nextPos = transaction.mapping.map(selection.to);
|
|
23072
|
+
const nextNode = transaction.doc.nodeAt(nextPos);
|
|
23073
|
+
if (!nextNode || nextNode.type.name !== "paragraph") {
|
|
23074
|
+
const paragraph = schema.nodes.paragraph?.create();
|
|
23075
|
+
if (paragraph) {
|
|
23076
|
+
transaction = transaction.insert(nextPos, paragraph);
|
|
23077
|
+
}
|
|
23078
|
+
}
|
|
23079
|
+
const resolvedPos = transaction.doc.resolve(Math.min(nextPos + 1, transaction.doc.content.size));
|
|
23080
|
+
transaction = transaction.setSelection(import_state4.TextSelection.near(resolvedPos));
|
|
23081
|
+
} else {
|
|
23082
|
+
const resolvedPos = transaction.doc.resolve(selection.from);
|
|
23083
|
+
transaction = transaction.setSelection(import_state4.NodeSelection.create(transaction.doc, resolvedPos.pos));
|
|
23084
|
+
}
|
|
23085
|
+
view.dispatch(transaction.scrollIntoView());
|
|
23086
|
+
view.focus();
|
|
23087
|
+
}
|
|
23088
|
+
function applyImageWidthPreset(editor, preset) {
|
|
23089
|
+
const attrs = editor.getAttributes("image");
|
|
23090
|
+
const mode = attrs.imageLayout === "left" || attrs.imageLayout === "right" ? "wrap" : "block";
|
|
23091
|
+
const width = IMAGE_WIDTHS_BY_LAYOUT[mode][preset];
|
|
23092
|
+
if (!isSelectedImage(editor)) {
|
|
23093
|
+
editor.chain().focus().updateAttributes("image", { width, imageWidthPreset: preset }).run();
|
|
23094
|
+
return;
|
|
23095
|
+
}
|
|
23096
|
+
const { state, view } = editor;
|
|
23097
|
+
const selection = state.selection;
|
|
23098
|
+
const transaction = state.tr.setNodeMarkup(selection.from, void 0, {
|
|
23099
|
+
...selection.node.attrs,
|
|
23100
|
+
width,
|
|
23101
|
+
imageWidthPreset: preset
|
|
23102
|
+
});
|
|
23103
|
+
view.dispatch(transaction.scrollIntoView());
|
|
23104
|
+
view.focus();
|
|
23105
|
+
}
|
|
23106
|
+
function resetImageSize(editor) {
|
|
23107
|
+
if (!isSelectedImage(editor)) {
|
|
23108
|
+
editor.chain().focus().updateAttributes("image", {
|
|
23109
|
+
width: null,
|
|
23110
|
+
height: null,
|
|
23111
|
+
imageWidthPreset: null
|
|
23112
|
+
}).run();
|
|
23113
|
+
return;
|
|
23114
|
+
}
|
|
23115
|
+
const { state, view } = editor;
|
|
23116
|
+
const selection = state.selection;
|
|
23117
|
+
const transaction = state.tr.setNodeMarkup(selection.from, void 0, {
|
|
23118
|
+
...selection.node.attrs,
|
|
23119
|
+
width: null,
|
|
23120
|
+
height: null,
|
|
23121
|
+
imageWidthPreset: null
|
|
23122
|
+
});
|
|
23123
|
+
view.dispatch(transaction.scrollIntoView());
|
|
23124
|
+
view.focus();
|
|
23125
|
+
}
|
|
23126
|
+
function deleteSelectedImage(editor) {
|
|
23127
|
+
if (!isSelectedImage(editor)) return;
|
|
23128
|
+
editor.chain().focus().deleteSelection().run();
|
|
23129
|
+
}
|
|
23130
|
+
|
|
22956
23131
|
// src/components/UEditor/inputs.tsx
|
|
22957
23132
|
var import_react46 = require("react");
|
|
22958
23133
|
var import_lucide_react42 = require("lucide-react");
|
|
@@ -23289,6 +23464,10 @@ var EditorToolbar = ({
|
|
|
23289
23464
|
const fileInputRef = (0, import_react48.useRef)(null);
|
|
23290
23465
|
const [isUploadingImage, setIsUploadingImage] = (0, import_react48.useState)(false);
|
|
23291
23466
|
const [imageUploadError, setImageUploadError] = (0, import_react48.useState)(null);
|
|
23467
|
+
const isImageSelected = editor.isActive("image");
|
|
23468
|
+
const imageAttrs = editor.getAttributes("image");
|
|
23469
|
+
const imageLayout = imageAttrs.imageLayout === "left" || imageAttrs.imageLayout === "right" ? imageAttrs.imageLayout : "block";
|
|
23470
|
+
const imageWidthPreset = imageAttrs.imageWidthPreset === "sm" || imageAttrs.imageWidthPreset === "md" || imageAttrs.imageWidthPreset === "lg" ? imageAttrs.imageWidthPreset : null;
|
|
23292
23471
|
const insertImageFiles = async (files) => {
|
|
23293
23472
|
if (files.length === 0) return;
|
|
23294
23473
|
setIsUploadingImage(true);
|
|
@@ -23621,6 +23800,85 @@ var EditorToolbar = ({
|
|
|
23621
23800
|
void insertImageFiles(files);
|
|
23622
23801
|
}
|
|
23623
23802
|
}
|
|
23803
|
+
),
|
|
23804
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { className: "my-1 border-t" }),
|
|
23805
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23806
|
+
DropdownMenuItem,
|
|
23807
|
+
{
|
|
23808
|
+
icon: import_lucide_react44.AlignCenter,
|
|
23809
|
+
label: t("toolbar.imageLayoutBlock"),
|
|
23810
|
+
onClick: () => applyImageLayout(editor, "block"),
|
|
23811
|
+
active: isImageSelected && imageLayout === "block",
|
|
23812
|
+
disabled: !isImageSelected
|
|
23813
|
+
}
|
|
23814
|
+
),
|
|
23815
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23816
|
+
DropdownMenuItem,
|
|
23817
|
+
{
|
|
23818
|
+
icon: import_lucide_react44.AlignLeft,
|
|
23819
|
+
label: t("toolbar.imageLayoutLeft"),
|
|
23820
|
+
onClick: () => applyImageLayout(editor, "left"),
|
|
23821
|
+
active: isImageSelected && imageLayout === "left",
|
|
23822
|
+
disabled: !isImageSelected
|
|
23823
|
+
}
|
|
23824
|
+
),
|
|
23825
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23826
|
+
DropdownMenuItem,
|
|
23827
|
+
{
|
|
23828
|
+
icon: import_lucide_react44.AlignRight,
|
|
23829
|
+
label: t("toolbar.imageLayoutRight"),
|
|
23830
|
+
onClick: () => applyImageLayout(editor, "right"),
|
|
23831
|
+
active: isImageSelected && imageLayout === "right",
|
|
23832
|
+
disabled: !isImageSelected
|
|
23833
|
+
}
|
|
23834
|
+
),
|
|
23835
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { className: "my-1 border-t" }),
|
|
23836
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23837
|
+
DropdownMenuItem,
|
|
23838
|
+
{
|
|
23839
|
+
label: t("toolbar.imageWidthSm"),
|
|
23840
|
+
onClick: () => applyImageWidthPreset(editor, "sm"),
|
|
23841
|
+
active: isImageSelected && imageWidthPreset === "sm",
|
|
23842
|
+
disabled: !isImageSelected
|
|
23843
|
+
}
|
|
23844
|
+
),
|
|
23845
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23846
|
+
DropdownMenuItem,
|
|
23847
|
+
{
|
|
23848
|
+
label: t("toolbar.imageWidthMd"),
|
|
23849
|
+
onClick: () => applyImageWidthPreset(editor, "md"),
|
|
23850
|
+
active: isImageSelected && imageWidthPreset === "md",
|
|
23851
|
+
disabled: !isImageSelected
|
|
23852
|
+
}
|
|
23853
|
+
),
|
|
23854
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23855
|
+
DropdownMenuItem,
|
|
23856
|
+
{
|
|
23857
|
+
label: t("toolbar.imageWidthLg"),
|
|
23858
|
+
onClick: () => applyImageWidthPreset(editor, "lg"),
|
|
23859
|
+
active: isImageSelected && imageWidthPreset === "lg",
|
|
23860
|
+
disabled: !isImageSelected
|
|
23861
|
+
}
|
|
23862
|
+
),
|
|
23863
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { className: "my-1 border-t" }),
|
|
23864
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23865
|
+
DropdownMenuItem,
|
|
23866
|
+
{
|
|
23867
|
+
icon: import_lucide_react44.RotateCcw,
|
|
23868
|
+
label: t("toolbar.imageResetSize"),
|
|
23869
|
+
onClick: () => resetImageSize(editor),
|
|
23870
|
+
disabled: !isImageSelected
|
|
23871
|
+
}
|
|
23872
|
+
),
|
|
23873
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
23874
|
+
DropdownMenuItem,
|
|
23875
|
+
{
|
|
23876
|
+
icon: import_lucide_react44.Trash2,
|
|
23877
|
+
label: t("toolbar.imageDelete"),
|
|
23878
|
+
onClick: () => deleteSelectedImage(editor),
|
|
23879
|
+
disabled: !isImageSelected,
|
|
23880
|
+
destructive: true
|
|
23881
|
+
}
|
|
23624
23882
|
)
|
|
23625
23883
|
] })
|
|
23626
23884
|
}
|
|
@@ -23933,6 +24191,10 @@ var BubbleMenuContent = ({
|
|
|
23933
24191
|
const { textColors, highlightColors } = useEditorColors();
|
|
23934
24192
|
const [showLinkInput, setShowLinkInput] = (0, import_react49.useState)(false);
|
|
23935
24193
|
const [showEditorColorPalette, setShowEditorColorPalette] = (0, import_react49.useState)(false);
|
|
24194
|
+
const isImageSelected = editor.isActive("image");
|
|
24195
|
+
const imageAttrs = editor.getAttributes("image");
|
|
24196
|
+
const imageLayout = imageAttrs.imageLayout === "left" || imageAttrs.imageLayout === "right" ? imageAttrs.imageLayout : "block";
|
|
24197
|
+
const imageWidthPreset = imageAttrs.imageWidthPreset === "sm" || imageAttrs.imageWidthPreset === "md" || imageAttrs.imageWidthPreset === "lg" ? imageAttrs.imageWidthPreset : null;
|
|
23936
24198
|
(0, import_react49.useEffect)(() => {
|
|
23937
24199
|
onKeepOpenChange?.(showLinkInput);
|
|
23938
24200
|
}, [onKeepOpenChange, showLinkInput]);
|
|
@@ -24007,6 +24269,20 @@ var BubbleMenuContent = ({
|
|
|
24007
24269
|
) })
|
|
24008
24270
|
] });
|
|
24009
24271
|
}
|
|
24272
|
+
if (isImageSelected) {
|
|
24273
|
+
return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "flex items-center gap-0.5 p-1", children: [
|
|
24274
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => applyImageLayout(editor, "block"), active: imageLayout === "block", title: t("toolbar.imageLayoutBlock"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react45.AlignCenter, { className: "w-4 h-4" }) }),
|
|
24275
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => applyImageLayout(editor, "left"), active: imageLayout === "left", title: t("toolbar.imageLayoutLeft"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react45.AlignLeft, { className: "w-4 h-4" }) }),
|
|
24276
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => applyImageLayout(editor, "right"), active: imageLayout === "right", title: t("toolbar.imageLayoutRight"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react45.AlignRight, { className: "w-4 h-4" }) }),
|
|
24277
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "w-px h-6 bg-border/50 mx-1" }),
|
|
24278
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => applyImageWidthPreset(editor, "sm"), active: imageWidthPreset === "sm", title: t("toolbar.imageWidthSm"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "text-[10px] font-semibold", children: "S" }) }),
|
|
24279
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => applyImageWidthPreset(editor, "md"), active: imageWidthPreset === "md", title: t("toolbar.imageWidthMd"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "text-[10px] font-semibold", children: "M" }) }),
|
|
24280
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => applyImageWidthPreset(editor, "lg"), active: imageWidthPreset === "lg", title: t("toolbar.imageWidthLg"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "text-[10px] font-semibold", children: "L" }) }),
|
|
24281
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "w-px h-6 bg-border/50 mx-1" }),
|
|
24282
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => resetImageSize(editor), title: t("toolbar.imageResetSize"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react45.RotateCcw, { className: "w-4 h-4" }) }),
|
|
24283
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => deleteSelectedImage(editor), title: t("toolbar.imageDelete"), className: "text-destructive hover:text-destructive", children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react45.Trash2, { className: "w-4 h-4" }) })
|
|
24284
|
+
] });
|
|
24285
|
+
}
|
|
24010
24286
|
return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "flex items-center gap-0.5 p-1", children: [
|
|
24011
24287
|
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => editor.chain().focus().toggleBold().run(), active: editor.isActive("bold"), title: t("toolbar.bold"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react45.Bold, { className: "w-4 h-4" }) }),
|
|
24012
24288
|
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)(ToolbarButton, { onClick: () => editor.chain().focus().toggleItalic().run(), active: editor.isActive("italic"), title: t("toolbar.italic"), children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react45.Italic, { className: "w-4 h-4" }) }),
|
|
@@ -24059,19 +24335,28 @@ var BubbleMenuContent = ({
|
|
|
24059
24335
|
] });
|
|
24060
24336
|
};
|
|
24061
24337
|
var CustomBubbleMenu = ({ editor }) => {
|
|
24338
|
+
const SHOW_DELAY_MS = 180;
|
|
24062
24339
|
const [isVisible, setIsVisible] = (0, import_react49.useState)(false);
|
|
24063
24340
|
const [position, setPosition] = (0, import_react49.useState)({ top: 0, left: 0 });
|
|
24064
24341
|
const menuRef = (0, import_react49.useRef)(null);
|
|
24065
24342
|
const keepOpenRef = (0, import_react49.useRef)(false);
|
|
24343
|
+
const showTimeoutRef = (0, import_react49.useRef)(null);
|
|
24066
24344
|
const setKeepOpen = (0, import_react49.useCallback)((next) => {
|
|
24067
24345
|
keepOpenRef.current = next;
|
|
24068
24346
|
if (next) setIsVisible(true);
|
|
24069
24347
|
}, []);
|
|
24070
24348
|
(0, import_react49.useEffect)(() => {
|
|
24349
|
+
const clearShowTimeout = () => {
|
|
24350
|
+
if (showTimeoutRef.current) {
|
|
24351
|
+
clearTimeout(showTimeoutRef.current);
|
|
24352
|
+
showTimeoutRef.current = null;
|
|
24353
|
+
}
|
|
24354
|
+
};
|
|
24071
24355
|
const updatePosition = () => {
|
|
24072
24356
|
const { state, view } = editor;
|
|
24073
24357
|
const { from, to, empty } = state.selection;
|
|
24074
24358
|
if (!keepOpenRef.current && (empty || !view.hasFocus())) {
|
|
24359
|
+
clearShowTimeout();
|
|
24075
24360
|
setIsVisible(false);
|
|
24076
24361
|
return;
|
|
24077
24362
|
}
|
|
@@ -24080,15 +24365,28 @@ var CustomBubbleMenu = ({ editor }) => {
|
|
|
24080
24365
|
const left = (start.left + end.left) / 2;
|
|
24081
24366
|
const top = start.top - 10;
|
|
24082
24367
|
setPosition({ top, left });
|
|
24083
|
-
|
|
24368
|
+
if (keepOpenRef.current) {
|
|
24369
|
+
clearShowTimeout();
|
|
24370
|
+
setIsVisible(true);
|
|
24371
|
+
return;
|
|
24372
|
+
}
|
|
24373
|
+
clearShowTimeout();
|
|
24374
|
+
showTimeoutRef.current = setTimeout(() => {
|
|
24375
|
+
setIsVisible(true);
|
|
24376
|
+
showTimeoutRef.current = null;
|
|
24377
|
+
}, SHOW_DELAY_MS);
|
|
24084
24378
|
};
|
|
24085
24379
|
const handleBlur = () => {
|
|
24086
|
-
if (!keepOpenRef.current)
|
|
24380
|
+
if (!keepOpenRef.current) {
|
|
24381
|
+
clearShowTimeout();
|
|
24382
|
+
setIsVisible(false);
|
|
24383
|
+
}
|
|
24087
24384
|
};
|
|
24088
24385
|
editor.on("selectionUpdate", updatePosition);
|
|
24089
24386
|
editor.on("focus", updatePosition);
|
|
24090
24387
|
editor.on("blur", handleBlur);
|
|
24091
24388
|
return () => {
|
|
24389
|
+
clearShowTimeout();
|
|
24092
24390
|
editor.off("selectionUpdate", updatePosition);
|
|
24093
24391
|
editor.off("focus", updatePosition);
|
|
24094
24392
|
editor.off("blur", handleBlur);
|
|
@@ -24572,7 +24870,21 @@ var UEditor = import_react50.default.forwardRef(({
|
|
|
24572
24870
|
"[&_blockquote]:rounded-r-lg",
|
|
24573
24871
|
"[&_blockquote]:italic",
|
|
24574
24872
|
"[&_blockquote]:text-muted-foreground",
|
|
24575
|
-
"[&_blockquote_p]:my-0"
|
|
24873
|
+
"[&_blockquote_p]:my-0",
|
|
24874
|
+
"[&_[data-image-layout='left']+p]:mt-1",
|
|
24875
|
+
"[&_[data-image-layout='left']+p]:min-h-[5rem]",
|
|
24876
|
+
"[&_[data-image-layout='right']+p]:mt-1",
|
|
24877
|
+
"[&_[data-image-layout='right']+p]:min-h-[5rem]",
|
|
24878
|
+
"max-md:[&_[data-image-layout='left']]:float-none",
|
|
24879
|
+
"max-md:[&_[data-image-layout='left']]:mr-0",
|
|
24880
|
+
"max-md:[&_[data-image-layout='left']]:ml-0",
|
|
24881
|
+
"max-md:[&_[data-image-layout='left']]:max-w-full",
|
|
24882
|
+
"max-md:[&_[data-image-layout='right']]:float-none",
|
|
24883
|
+
"max-md:[&_[data-image-layout='right']]:mr-0",
|
|
24884
|
+
"max-md:[&_[data-image-layout='right']]:ml-0",
|
|
24885
|
+
"max-md:[&_[data-image-layout='right']]:max-w-full",
|
|
24886
|
+
"max-md:[&_[data-image-layout='left']+p]:min-h-0",
|
|
24887
|
+
"max-md:[&_[data-image-layout='right']+p]:min-h-0"
|
|
24576
24888
|
)
|
|
24577
24889
|
}
|
|
24578
24890
|
},
|