@lobehub/editor 4.25.1 → 4.26.1

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/es/headless.d.ts CHANGED
@@ -76,6 +76,7 @@ declare const _default: {
76
76
  };
77
77
  image: {
78
78
  broken: string;
79
+ preview: string;
79
80
  replace: string;
80
81
  };
81
82
  link: {
package/es/headless.js CHANGED
@@ -43,6 +43,7 @@ var locale_default = {
43
43
  },
44
44
  image: {
45
45
  broken: "Broken image",
46
+ preview: "Preview image",
46
47
  replace: "Replace"
47
48
  },
48
49
  link: {
@@ -23,6 +23,7 @@ declare const _default: {
23
23
  };
24
24
  image: {
25
25
  broken: string;
26
+ preview: string;
26
27
  replace: string;
27
28
  };
28
29
  link: {
@@ -26,6 +26,7 @@ var init_locale = __esmMin((() => {
26
26
  },
27
27
  image: {
28
28
  broken: "Broken image",
29
+ preview: "Preview image",
29
30
  replace: "Replace"
30
31
  },
31
32
  link: {
@@ -1,4 +1,5 @@
1
1
  import { useLexicalEditor } from "../../../../editor-kernel/react/useLexicalEditor.js";
2
+ import { useTranslation } from "../../../../editor-kernel/react/useTranslation.js";
2
3
  import { $isBlockImageNode } from "../../node/block-image-node.js";
3
4
  import { useLexicalNodeSelection } from "../../../../editor-kernel/react/useLexicalNodeSelection.js";
4
5
  import { styles } from "./style.js";
@@ -6,20 +7,22 @@ import BrokenImage from "./BrokenImage.js";
6
7
  import ImageEditPopover from "./ImageEditPopover.js";
7
8
  import LazyImage from "./LazyImage.js";
8
9
  import { ResizeHandle } from "./ResizeHandle.js";
9
- import { Icon } from "@lobehub/ui";
10
- import { LoaderCircleIcon } from "lucide-react";
10
+ import { ActionIcon, Icon } from "@lobehub/ui";
11
+ import { LoaderCircleIcon, ZoomInIcon } from "lucide-react";
11
12
  import { Suspense, memo, useCallback, useMemo, useRef, useState } from "react";
12
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
14
  import { cx } from "antd-style";
15
+ import { Image } from "antd";
14
16
  import { COMMAND_PRIORITY_LOW, SELECTION_CHANGE_COMMAND } from "lexical";
15
17
  //#region src/plugins/image/react/components/Image.tsx
16
18
  function getResizedImageWidth(startWidth, deltaX, maxWidth) {
17
19
  const adjustedDeltaX = deltaX * 2;
18
20
  return Math.max(50, Math.min(startWidth + adjustedDeltaX, maxWidth));
19
21
  }
20
- const Image = memo(({ node, className, showScaleInfo = false, handleUpload, onPickFile }) => {
22
+ const Image$1 = memo(({ node, className, showScaleInfo = false, handleUpload, onPickFile }) => {
21
23
  const [isSelected, setSelected] = useLexicalNodeSelection(node.getKey());
22
24
  const [isHovered, setIsHovered] = useState(false);
25
+ const [previewOpen, setPreviewOpen] = useState(false);
23
26
  const [scale, setScale] = useState(1);
24
27
  const [size, setSize] = useState({
25
28
  height: 0,
@@ -34,6 +37,7 @@ const Image = memo(({ node, className, showScaleInfo = false, handleUpload, onPi
34
37
  const editorRef = useRef(null);
35
38
  const startWidthRef = useRef(0);
36
39
  const lastLoadedSrcRef = useRef(null);
40
+ const t = useTranslation();
37
41
  const isBlock = useMemo(() => {
38
42
  return $isBlockImageNode(node);
39
43
  }, [node]);
@@ -92,6 +96,11 @@ const Image = memo(({ node, className, showScaleInfo = false, handleUpload, onPi
92
96
  const handleMouseLeave = useCallback(() => {
93
97
  setIsHovered(false);
94
98
  }, []);
99
+ const handlePreview = useCallback((e) => {
100
+ e.preventDefault();
101
+ e.stopPropagation();
102
+ setPreviewOpen(true);
103
+ }, []);
95
104
  const children = useMemo(() => {
96
105
  switch (node.status) {
97
106
  case "error": return /* @__PURE__ */ jsx(BrokenImage, {});
@@ -167,6 +176,23 @@ const Image = memo(({ node, className, showScaleInfo = false, handleUpload, onPi
167
176
  spin: true
168
177
  })
169
178
  }),
179
+ (isHovered || isSelected) && node.status === "uploaded" && /* @__PURE__ */ jsx(ActionIcon, {
180
+ "aria-label": t("image.preview"),
181
+ glass: true,
182
+ className: styles.previewAction,
183
+ icon: ZoomInIcon,
184
+ onClick: handlePreview,
185
+ size: "small",
186
+ title: t("image.preview"),
187
+ variant: "filled"
188
+ }),
189
+ /* @__PURE__ */ jsx(Image.PreviewGroup, {
190
+ items: [node.src],
191
+ preview: {
192
+ open: previewOpen,
193
+ onOpenChange: setPreviewOpen
194
+ }
195
+ }),
170
196
  showScaleInfo && isSelected && scale !== 1 && /* @__PURE__ */ jsxs("div", {
171
197
  className: styles.scaleInfo,
172
198
  children: [Math.round(scale * 100), "%"]
@@ -190,6 +216,6 @@ const Image = memo(({ node, className, showScaleInfo = false, handleUpload, onPi
190
216
  })
191
217
  });
192
218
  });
193
- Image.displayName = "Image";
219
+ Image$1.displayName = "Image";
194
220
  //#endregion
195
- export { Image as default };
221
+ export { Image$1 as default };
@@ -78,6 +78,32 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
78
78
  justify-content: center;
79
79
 
80
80
  color: ${cssVar.colorTextSecondary};
81
+ `,
82
+ previewAction: css`
83
+ position: absolute;
84
+ z-index: 10000;
85
+ inset-block-start: 8px;
86
+ inset-inline-end: 8px;
87
+
88
+ && {
89
+ border: 1px solid rgb(255 255 255 / 24%);
90
+
91
+ color: rgb(255 255 255 / 96%);
92
+
93
+ background: rgb(0 0 0 / 58%);
94
+ backdrop-filter: saturate(120%) blur(12px);
95
+ box-shadow: 0 2px 8px rgb(0 0 0 / 36%);
96
+ }
97
+
98
+ &&:hover {
99
+ color: rgb(255 255 255);
100
+ background: rgb(0 0 0 / 72%);
101
+ }
102
+
103
+ &&:active {
104
+ color: rgb(255 255 255);
105
+ background: rgb(0 0 0 / 80%);
106
+ }
81
107
  `,
82
108
  resizeHandle: css`
83
109
  pointer-events: auto;
@@ -44,7 +44,7 @@ function tryToPositionRange(leadOffset, range, editorWindow) {
44
44
  }
45
45
  return true;
46
46
  }
47
- const PUNCTUATION = "\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\!%'\"~=<>_:;";
47
+ const PUNCTUATION = "\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\[\\]\\\\!%'\"~=<>_:;";
48
48
  function getBasicTypeaheadTriggerMatch(trigger, { minLength = 0, maxLength = 75, punctuation = PUNCTUATION, allowWhitespace = false }) {
49
49
  return (text) => {
50
50
  const validCharsSuffix = allowWhitespace ? "" : "\\s";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "4.25.1",
3
+ "version": "4.26.1",
4
4
  "description": "A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.",
5
5
  "keywords": [
6
6
  "lobehub",