@haklex/rich-renderer-image 0.22.1 → 0.24.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ImageEditContext.d.ts","sourceRoot":"","sources":["../src/ImageEditContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAoBvC,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAsDA"}
1
+ {"version":3,"file":"ImageEditContext.d.ts","sourceRoot":"","sources":["../src/ImageEditContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAsBvC,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,SAAS,CAAC;CACrB,2CA4DA"}
@@ -1 +1 @@
1
- {"version":3,"file":"ImageEditRenderer.d.ts","sourceRoot":"","sources":["../src/ImageEditRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAgCxE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,2CAQ1D"}
1
+ {"version":3,"file":"ImageEditRenderer.d.ts","sourceRoot":"","sources":["../src/ImageEditRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAoCxE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,2CAQ1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"ImageEditToolbar.d.ts","sourceRoot":"","sources":["../src/ImageEditToolbar.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,gBAAgB,4CA0J/B"}
1
+ {"version":3,"file":"ImageEditToolbar.d.ts","sourceRoot":"","sources":["../src/ImageEditToolbar.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,gBAAgB,4CA6J/B"}
@@ -0,0 +1,3 @@
1
+ export declare function ImageSizeControl(): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ImageLayoutControl(): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=ImageLayoutControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageLayoutControls.d.ts","sourceRoot":"","sources":["../src/ImageLayoutControls.tsx"],"names":[],"mappings":"AAyDA,wBAAgB,gBAAgB,4CA6F/B;AAED,wBAAgB,kBAAkB,4CAmCjC"}
@@ -25,7 +25,8 @@ var semanticClassNames = {
25
25
  editInput: "rr-image-edit-input",
26
26
  replaceUploadArea: "rr-image-replace-upload-area",
27
27
  replacePreview: "rr-image-replace-preview",
28
- panelHint: "rr-image-panel-hint"
28
+ panelHint: "rr-image-panel-hint",
29
+ resizeHandle: "rr-image-resize-handle"
29
30
  };
30
31
  var root = "_1n94osf0";
31
32
  var image = "_1n94osf2";
@@ -54,6 +55,17 @@ var editInput = "_1n94osfu";
54
55
  var replaceUploadArea = "_1n94osfv";
55
56
  var replacePreview = "_1n94osfw";
56
57
  var panelHint = "_1n94osfx";
58
+ var resizeHandle = "_1n94osfy";
59
+ var resizeHandleLeft = "_1n94osfz";
60
+ var resizeHandleRight = "_1n94osf10";
61
+ var resizeHandleVisible = "_1n94osf11";
62
+ var controlPanel = "_1n94osf12";
63
+ var sizeSliderWrap = "_1n94osf13";
64
+ var sizeSlider = "_1n94osf14";
65
+ var sizeSliderTick = "_1n94osf15";
66
+ var sizeValue = "_1n94osf16";
67
+ var sizeOption = "_1n94osf17";
68
+ var editToolbarButtonActive = "_1n94osf18";
57
69
  //#endregion
58
70
  //#region src/ImageRenderer.tsx
59
71
  var frameStateSemanticClass = {
@@ -66,7 +78,7 @@ function getCaptionText(altText, caption) {
66
78
  if (!altText) return void 0;
67
79
  if (altText.startsWith("!") || altText.startsWith("¡")) return altText.slice(1);
68
80
  }
69
- function ImageRenderer({ src, altText, width, height, caption: caption$1, thumbhash, accent, onActivate, ref }) {
81
+ function ImageRenderer({ src, altText, width, height, caption: caption$1, thumbhash, accent, displayWidth, layout, onActivate, ref }) {
70
82
  const [state, setState] = useState("loading");
71
83
  const imgRef = useRef(null);
72
84
  const captionText = useMemo(() => getCaptionText(altText, caption$1), [altText, caption$1]);
@@ -89,9 +101,12 @@ function ImageRenderer({ src, altText, width, height, caption: caption$1, thumbh
89
101
  e.preventDefault();
90
102
  activate();
91
103
  };
104
+ const figureStyle = displayWidth ? { "--rich-image-display-width": `${displayWidth}%` } : void 0;
92
105
  return /* @__PURE__ */ jsxs("figure", {
93
106
  className: `${root} ${semanticClassNames.root}`,
107
+ "data-layout": layout,
94
108
  ref,
109
+ style: figureStyle,
95
110
  children: [/* @__PURE__ */ jsxs("div", {
96
111
  "aria-label": interactive ? `Open image: ${altText || "image"}` : void 0,
97
112
  className: `${frame} ${interactive ? "" : frameStatic} ${semanticClassNames.frame} ${imageState[state]} ${frameStateSemanticClass[state]}`.trim(),
@@ -130,4 +145,4 @@ function ImageRenderer({ src, altText, width, height, caption: caption$1, thumbh
130
145
  });
131
146
  }
132
147
  //#endregion
133
- export { root as C, replaceUploadArea as S, imageState as _, editInput as a, panelHint as b, editToolbar as c, editToolbarVisible as d, editTrigger as f, image as g, frameEditMode as h, editFieldIcon as i, editToolbarButton as l, frame as m, caption as n, editPanel as o, errorBadge as p, editField as r, editPlaceholder as s, ImageRenderer as t, editToolbarButtonDanger as u, imageVisible as v, semanticClassNames as w, replacePreview as x, loader as y };
148
+ export { semanticClassNames as A, replacePreview as C, resizeHandleRight as D, resizeHandleLeft as E, sizeValue as F, sizeSlider as M, sizeSliderTick as N, resizeHandleVisible as O, sizeSliderWrap as P, panelHint as S, resizeHandle as T, frameEditMode as _, editFieldIcon as a, imageVisible as b, editPlaceholder as c, editToolbarButtonActive as d, editToolbarButtonDanger as f, frame as g, errorBadge as h, editField as i, sizeOption as j, root as k, editToolbar as l, editTrigger as m, caption as n, editInput as o, editToolbarVisible as p, controlPanel as r, editPanel as s, ImageRenderer as t, editToolbarButton as u, image as v, replaceUploadArea as w, loader as x, imageState as y };
@@ -4,5 +4,5 @@ export interface ImageRendererInteractiveProps extends ImageRendererProps {
4
4
  onActivate?: (target: HTMLElement) => void;
5
5
  ref?: Ref<HTMLElement>;
6
6
  }
7
- export declare function ImageRenderer({ src, altText, width, height, caption, thumbhash, accent, onActivate, ref, }: ImageRendererInteractiveProps): import("react/jsx-runtime").JSX.Element | null;
7
+ export declare function ImageRenderer({ src, altText, width, height, caption, thumbhash, accent, displayWidth, layout, onActivate, ref, }: ImageRendererInteractiveProps): import("react/jsx-runtime").JSX.Element | null;
8
8
  //# sourceMappingURL=ImageRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ImageRenderer.d.ts","sourceRoot":"","sources":["../src/ImageRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEzF,OAAO,KAAK,EAAgC,GAAG,EAAE,MAAM,OAAO,CAAC;AAsB/D,MAAM,WAAW,6BAA8B,SAAQ,kBAAkB;IACvE,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IAC3C,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,EAC5B,GAAG,EACH,OAAO,EACP,KAAK,EACL,MAAM,EACN,OAAO,EACP,SAAS,EACT,MAAM,EACN,UAAU,EACV,GAAG,GACJ,EAAE,6BAA6B,kDA8E/B"}
1
+ {"version":3,"file":"ImageRenderer.d.ts","sourceRoot":"","sources":["../src/ImageRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEzF,OAAO,KAAK,EAAgC,GAAG,EAAE,MAAM,OAAO,CAAC;AAsB/D,MAAM,WAAW,6BAA8B,SAAQ,kBAAkB;IACvE,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IAC3C,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,EAC5B,GAAG,EACH,OAAO,EACP,KAAK,EACL,MAAM,EACN,OAAO,EACP,SAAS,EACT,MAAM,EACN,YAAY,EACZ,MAAM,EACN,UAAU,EACV,GAAG,GACJ,EAAE,6BAA6B,kDAuF/B"}
@@ -0,0 +1,2 @@
1
+ export declare function ResizeHandles(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=ResizeHandles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResizeHandles.d.ts","sourceRoot":"","sources":["../src/ResizeHandles.tsx"],"names":[],"mappings":"AAMA,wBAAgB,aAAa,4CAiB5B"}
package/dist/atoms.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ImageLayout } from '@haklex/rich-editor/nodes';
1
2
  import { CSSProperties, RefObject } from 'react';
2
3
  export type ImageLoadState = 'loading' | 'loaded' | 'error';
3
4
  export type ReplaceMode = 'upload' | 'url';
@@ -22,6 +23,12 @@ export declare const thumbhashAtom: import('jotai').PrimitiveAtom<string | undef
22
23
  export declare const accentAtom: import('jotai').PrimitiveAtom<string | undefined> & {
23
24
  init: string | undefined;
24
25
  };
26
+ export declare const displayWidthAtom: import('jotai').PrimitiveAtom<number | undefined> & {
27
+ init: number | undefined;
28
+ };
29
+ export declare const layoutAtom: import('jotai').PrimitiveAtom<ImageLayout | undefined> & {
30
+ init: ImageLayout | undefined;
31
+ };
25
32
  export declare const loadStateAtom: import('jotai').PrimitiveAtom<ImageLoadState> & {
26
33
  init: ImageLoadState;
27
34
  };
@@ -34,6 +41,15 @@ export declare const metaOpenAtom: import('jotai').PrimitiveAtom<boolean> & {
34
41
  export declare const replaceOpenAtom: import('jotai').PrimitiveAtom<boolean> & {
35
42
  init: boolean;
36
43
  };
44
+ export declare const sizeOpenAtom: import('jotai').PrimitiveAtom<boolean> & {
45
+ init: boolean;
46
+ };
47
+ export declare const layoutOpenAtom: import('jotai').PrimitiveAtom<boolean> & {
48
+ init: boolean;
49
+ };
50
+ export declare const resizingAtom: import('jotai').PrimitiveAtom<boolean> & {
51
+ init: boolean;
52
+ };
37
53
  export declare const toolbarVisibleAtom: import('jotai').Atom<boolean>;
38
54
  export declare const focusCaptionOnOpenAtom: import('jotai').PrimitiveAtom<boolean> & {
39
55
  init: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"atoms.d.ts","sourceRoot":"","sources":["../src/atoms.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC5D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,CAAC;AAY3C,eAAO,MAAM,OAAO;;CAAW,CAAC;AAChC,eAAO,MAAM,WAAW;;CAAW,CAAC;AACpC,eAAO,MAAM,SAAS;;CAA6B,CAAC;AACpD,eAAO,MAAM,UAAU;;CAA6B,CAAC;AACrD,eAAO,MAAM,WAAW;;CAA6B,CAAC;AACtD,eAAO,MAAM,aAAa;;CAA6B,CAAC;AACxD,eAAO,MAAM,UAAU;;CAA6B,CAAC;AAGrD,eAAO,MAAM,aAAa;;CAAkC,CAAC;AAC7D,eAAO,MAAM,YAAY;;CAAc,CAAC;AACxC,eAAO,MAAM,YAAY;;CAAc,CAAC;AACxC,eAAO,MAAM,eAAe;;CAAc,CAAC;AAC3C,eAAO,MAAM,kBAAkB,+BAE9B,CAAC;AAEF,eAAO,MAAM,sBAAsB;;CAAc,CAAC;AAGlD,eAAO,MAAM,WAAW;;CAAW,CAAC;AACpC,eAAO,MAAM,eAAe;;CAAW,CAAC;AACxC,eAAO,MAAM,eAAe;;CAAW,CAAC;AAGxC,eAAO,MAAM,eAAe;;CAA8B,CAAC;AAC3D,eAAO,MAAM,cAAc;;CAAW,CAAC;AACvC,eAAO,MAAM,kBAAkB;;CAA4B,CAAC;AAC5D,eAAO,MAAM,eAAe;WACnB,MAAM;YACL,MAAM;;;eADP,MAAM;gBACL,MAAM;;CACD,CAAC;AAChB,eAAO,MAAM,kBAAkB;;CAAc,CAAC;AAC9C,eAAO,MAAM,gBAAgB;;CAA4B,CAAC;AAG1D,eAAO,MAAM,cAAc;;CAEzB,CAAC;AACH,eAAO,MAAM,gBAAgB;;CAE3B,CAAC;AAGH,eAAO,MAAM,kBAAkB,0CAG7B,CAAC;AAEH,eAAO,MAAM,eAAe,0CAAoE,CAAC;AAEjG,eAAO,MAAM,cAAc,qCAgBzB,CAAC"}
1
+ {"version":3,"file":"atoms.d.ts","sourceRoot":"","sources":["../src/atoms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAG7D,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC5D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,CAAC;AAY3C,eAAO,MAAM,OAAO;;CAAW,CAAC;AAChC,eAAO,MAAM,WAAW;;CAAW,CAAC;AACpC,eAAO,MAAM,SAAS;;CAA6B,CAAC;AACpD,eAAO,MAAM,UAAU;;CAA6B,CAAC;AACrD,eAAO,MAAM,WAAW;;CAA6B,CAAC;AACtD,eAAO,MAAM,aAAa;;CAA6B,CAAC;AACxD,eAAO,MAAM,UAAU;;CAA6B,CAAC;AACrD,eAAO,MAAM,gBAAgB;;CAA6B,CAAC;AAC3D,eAAO,MAAM,UAAU;;CAAkC,CAAC;AAG1D,eAAO,MAAM,aAAa;;CAAkC,CAAC;AAC7D,eAAO,MAAM,YAAY;;CAAc,CAAC;AACxC,eAAO,MAAM,YAAY;;CAAc,CAAC;AACxC,eAAO,MAAM,eAAe;;CAAc,CAAC;AAC3C,eAAO,MAAM,YAAY;;CAAc,CAAC;AACxC,eAAO,MAAM,cAAc;;CAAc,CAAC;AAC1C,eAAO,MAAM,YAAY;;CAAc,CAAC;AACxC,eAAO,MAAM,kBAAkB,+BAQ9B,CAAC;AAEF,eAAO,MAAM,sBAAsB;;CAAc,CAAC;AAGlD,eAAO,MAAM,WAAW;;CAAW,CAAC;AACpC,eAAO,MAAM,eAAe;;CAAW,CAAC;AACxC,eAAO,MAAM,eAAe;;CAAW,CAAC;AAGxC,eAAO,MAAM,eAAe;;CAA8B,CAAC;AAC3D,eAAO,MAAM,cAAc;;CAAW,CAAC;AACvC,eAAO,MAAM,kBAAkB;;CAA4B,CAAC;AAC5D,eAAO,MAAM,eAAe;WACnB,MAAM;YACL,MAAM;;;eADP,MAAM;gBACL,MAAM;;CACD,CAAC;AAChB,eAAO,MAAM,kBAAkB;;CAAc,CAAC;AAC9C,eAAO,MAAM,gBAAgB;;CAA4B,CAAC;AAG1D,eAAO,MAAM,cAAc;;CAEzB,CAAC;AACH,eAAO,MAAM,gBAAgB;;CAE3B,CAAC;AAGH,eAAO,MAAM,kBAAkB,0CAG7B,CAAC;AAEH,eAAO,MAAM,eAAe,0CAAoE,CAAC;AAEjG,eAAO,MAAM,cAAc,qCAgBzB,CAAC"}
package/dist/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
- import { C as root, S as replaceUploadArea, _ as imageState, a as editInput, c as editToolbar, d as editToolbarVisible, f as editTrigger, g as image, h as frameEditMode, i as editFieldIcon, l as editToolbarButton, m as frame, o as editPanel, r as editField, s as editPlaceholder, t as ImageRenderer, u as editToolbarButtonDanger, v as imageVisible, w as semanticClassNames } from "./ImageRenderer-BihkEC_w.js";
1
+ import { A as semanticClassNames, D as resizeHandleRight, E as resizeHandleLeft, F as sizeValue, M as sizeSlider, N as sizeSliderTick, O as resizeHandleVisible, P as sizeSliderWrap, T as resizeHandle, _ as frameEditMode, a as editFieldIcon, b as imageVisible, c as editPlaceholder, d as editToolbarButtonActive, f as editToolbarButtonDanger, g as frame, i as editField, j as sizeOption, k as root, l as editToolbar, m as editTrigger, o as editInput, p as editToolbarVisible, r as controlPanel, s as editPanel, t as ImageRenderer, u as editToolbarButton, v as image, w as replaceUploadArea, y as imageState } from "./ImageRenderer-ew0e3cUJ.js";
2
2
  import { useRendererMode } from "@haklex/rich-editor/static";
3
3
  import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
4
- import { Provider, atom, createStore, useAtomValue, useSetAtom, useStore } from "jotai";
4
+ import { Provider, atom, createStore, useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
5
5
  import { useCallback, useEffect, useRef, useState } from "react";
6
6
  import { computeImageMeta, decodeThumbHash } from "@haklex/rich-editor/renderers";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { ActionBar, ActionButton, Popover, PopoverPanel, PopoverTrigger, SegmentedControl } from "@haklex/rich-editor-ui";
9
9
  import { $getNearestNodeFromDOMNode, REDO_COMMAND, UNDO_COMMAND } from "lexical";
10
- import { Captions, Copy, Download, ExternalLink, ImageIcon, Loader2, Replace, Trash2, Type, Upload } from "lucide-react";
11
- import { $createImageNode, $isImageNode } from "@haklex/rich-editor/nodes";
10
+ import { AlignCenterVertical, AlignEndVertical, AlignStartVertical, ArrowLeftToLine, ArrowRightToLine, Captions, CopyPlus, Download, ExternalLink, ImageIcon, Loader2, Replace, Scaling, Trash2, Type, Upload } from "lucide-react";
11
+ import { $createImageNode, $isImageNode, sanitizeImageDisplayWidth } from "@haklex/rich-editor/nodes";
12
12
  import { useImageUpload } from "@haklex/rich-editor/plugins";
13
13
  //#region src/atoms.ts
14
14
  function getCaptionText(altText, caption) {
@@ -23,11 +23,16 @@ var heightAtom = atom();
23
23
  var captionAtom = atom();
24
24
  var thumbhashAtom = atom();
25
25
  var accentAtom = atom();
26
+ var displayWidthAtom = atom();
27
+ var layoutAtom = atom();
26
28
  var loadStateAtom = atom("loading");
27
29
  var hoveringAtom = atom(false);
28
30
  var metaOpenAtom = atom(false);
29
31
  var replaceOpenAtom = atom(false);
30
- var toolbarVisibleAtom = atom((get) => get(hoveringAtom) || get(metaOpenAtom) || get(replaceOpenAtom));
32
+ var sizeOpenAtom = atom(false);
33
+ var layoutOpenAtom = atom(false);
34
+ var resizingAtom = atom(false);
35
+ var toolbarVisibleAtom = atom((get) => get(hoveringAtom) || get(metaOpenAtom) || get(replaceOpenAtom) || get(sizeOpenAtom) || get(layoutOpenAtom) || get(resizingAtom));
31
36
  var focusCaptionOnOpenAtom = atom(false);
32
37
  var editSrcAtom = atom("");
33
38
  var editAltTextAtom = atom("");
@@ -74,6 +79,8 @@ function ImageEditProvider({ props, children }) {
74
79
  s.set(captionAtom, props.caption);
75
80
  s.set(thumbhashAtom, props.thumbhash);
76
81
  s.set(accentAtom, props.accent);
82
+ s.set(displayWidthAtom, props.displayWidth);
83
+ s.set(layoutAtom, props.layout);
77
84
  s.set(editSrcAtom, props.src);
78
85
  s.set(editAltTextAtom, props.altText);
79
86
  s.set(editCaptionAtom, props.caption || "");
@@ -91,6 +98,8 @@ function ImageEditProvider({ props, children }) {
91
98
  store.set(captionAtom, props.caption);
92
99
  store.set(thumbhashAtom, props.thumbhash);
93
100
  store.set(accentAtom, props.accent);
101
+ store.set(displayWidthAtom, props.displayWidth);
102
+ store.set(layoutAtom, props.layout);
94
103
  }, [
95
104
  store,
96
105
  props.src,
@@ -99,7 +108,9 @@ function ImageEditProvider({ props, children }) {
99
108
  props.height,
100
109
  props.caption,
101
110
  props.thumbhash,
102
- props.accent
111
+ props.accent,
112
+ props.displayWidth,
113
+ props.layout
103
114
  ]);
104
115
  useEffect(() => {
105
116
  store.set(editSrcAtom, props.src);
@@ -156,7 +167,7 @@ function useImageActions() {
156
167
  editor.update(() => {
157
168
  const node = $getNearestNodeFromDOMNode(wrapperRef.current);
158
169
  if ($isImageNode(node)) updater(node);
159
- });
170
+ }, { tag: "skip-scroll-into-view" });
160
171
  }, [editor, store]);
161
172
  const closeReplacePanel = useCallback(() => {
162
173
  store.set(replaceOpenAtom, false);
@@ -212,11 +223,23 @@ function useImageActions() {
212
223
  height: node.getHeight(),
213
224
  caption: node.getCaption(),
214
225
  thumbhash: node.getThumbhash(),
215
- accent: node.getAccent()
226
+ accent: node.getAccent(),
227
+ displayWidth: node.getDisplayWidth(),
228
+ layout: node.getLayout()
216
229
  });
217
230
  node.insertAfter(copy);
218
231
  });
219
232
  }, [withImageNode]);
233
+ const handleSetDisplayWidth = useCallback((width) => {
234
+ withImageNode((node) => {
235
+ node.setDisplayWidth(width);
236
+ });
237
+ }, [withImageNode]);
238
+ const handleSetLayout = useCallback((layout) => {
239
+ withImageNode((node) => {
240
+ node.setLayout(layout);
241
+ });
242
+ }, [withImageNode]);
220
243
  return {
221
244
  commitMeta,
222
245
  closeReplacePanel,
@@ -291,7 +314,9 @@ function useImageActions() {
291
314
  handleOpen,
292
315
  handleDuplicate,
293
316
  handleDownload,
294
- handleDelete
317
+ handleDelete,
318
+ handleSetDisplayWidth,
319
+ handleSetLayout
295
320
  };
296
321
  }
297
322
  //#endregion
@@ -378,6 +403,168 @@ function getEditorHistoryShortcut(event, options = {}) {
378
403
  return null;
379
404
  }
380
405
  //#endregion
406
+ //#region src/ImageLayoutControls.tsx
407
+ var SIZE_PRESETS = [
408
+ 25,
409
+ 50,
410
+ 75,
411
+ 100
412
+ ];
413
+ var SIZE_MIN = 10;
414
+ var SIZE_MAX = 100;
415
+ var SNAP_THRESHOLD = 3;
416
+ function snapToPreset(value) {
417
+ for (const preset of SIZE_PRESETS) if (Math.abs(value - preset) <= SNAP_THRESHOLD) return preset;
418
+ return value;
419
+ }
420
+ function tickLeft(preset) {
421
+ return `calc(6px + ${(preset - SIZE_MIN) / (SIZE_MAX - SIZE_MIN)} * (100% - 12px))`;
422
+ }
423
+ var LAYOUT_OPTIONS = [
424
+ {
425
+ value: void 0,
426
+ label: "Center",
427
+ Icon: AlignCenterVertical
428
+ },
429
+ {
430
+ value: "align-left",
431
+ label: "Align left",
432
+ Icon: AlignStartVertical
433
+ },
434
+ {
435
+ value: "align-right",
436
+ label: "Align right",
437
+ Icon: AlignEndVertical
438
+ },
439
+ {
440
+ value: "float-left",
441
+ label: "Float left, text wraps right",
442
+ Icon: ArrowLeftToLine
443
+ },
444
+ {
445
+ value: "float-right",
446
+ label: "Float right, text wraps left",
447
+ Icon: ArrowRightToLine
448
+ }
449
+ ];
450
+ var toolbarButtonClass = `${editToolbarButton} ${semanticClassNames.editToolbarButton}`;
451
+ var stopMouseDown = (e) => {
452
+ e.preventDefault();
453
+ e.stopPropagation();
454
+ };
455
+ function ImageSizeControl() {
456
+ const store = useStore();
457
+ const [sizeOpen, setSizeOpen] = useAtom(sizeOpenAtom);
458
+ const displayWidth = useAtomValue(displayWidthAtom);
459
+ const { handleSetDisplayWidth } = useImageActions();
460
+ const [dragValue, setDragValue] = useState(null);
461
+ useEffect(() => {
462
+ setDragValue(null);
463
+ }, [displayWidth]);
464
+ const value = dragValue ?? displayWidth ?? SIZE_MAX;
465
+ const applyPreview = (percent) => {
466
+ const trigger = store.get(wrapperRefAtom).current;
467
+ if (!trigger) return;
468
+ const layout = store.get(layoutAtom);
469
+ if (layout === "float-left" || layout === "float-right") {
470
+ const blockWrapper = trigger.closest(".rich-image-wrapper");
471
+ if (blockWrapper) blockWrapper.style.width = `${percent}%`;
472
+ } else trigger.querySelector("figure")?.style.setProperty("--rich-image-display-width", `${percent}%`);
473
+ };
474
+ const handleSliderChange = (event) => {
475
+ const next = snapToPreset(Number(event.target.value));
476
+ setDragValue(next);
477
+ applyPreview(next);
478
+ };
479
+ const commit = () => {
480
+ if (dragValue === null || dragValue === (displayWidth ?? SIZE_MAX)) return;
481
+ handleSetDisplayWidth(dragValue);
482
+ };
483
+ const fill = `${(value - SIZE_MIN) / (SIZE_MAX - SIZE_MIN) * 100}%`;
484
+ return /* @__PURE__ */ jsxs(Popover, {
485
+ open: sizeOpen,
486
+ onOpenChange: setSizeOpen,
487
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
488
+ className: toolbarButtonClass,
489
+ title: "Image size",
490
+ onMouseDown: stopMouseDown,
491
+ children: /* @__PURE__ */ jsx(Scaling, { size: 14 })
492
+ }), /* @__PURE__ */ jsxs(PopoverPanel, {
493
+ className: controlPanel,
494
+ side: "bottom",
495
+ sideOffset: 8,
496
+ children: [
497
+ /* @__PURE__ */ jsx("button", {
498
+ className: `${sizeOption} ${displayWidth === void 0 ? editToolbarButtonActive : ""}`.trim(),
499
+ title: "Natural size",
500
+ type: "button",
501
+ onMouseDown: stopMouseDown,
502
+ onClick: () => {
503
+ handleSetDisplayWidth(void 0);
504
+ setSizeOpen(false);
505
+ },
506
+ children: "Auto"
507
+ }),
508
+ /* @__PURE__ */ jsxs("span", {
509
+ className: sizeSliderWrap,
510
+ children: [/* @__PURE__ */ jsx("input", {
511
+ "aria-label": "Image width, percent of content width",
512
+ className: sizeSlider,
513
+ max: SIZE_MAX,
514
+ min: SIZE_MIN,
515
+ step: 1,
516
+ style: { "--fill": fill },
517
+ type: "range",
518
+ value,
519
+ onBlur: commit,
520
+ onChange: handleSliderChange,
521
+ onKeyUp: commit,
522
+ onMouseDown: (e) => e.stopPropagation(),
523
+ onPointerUp: commit
524
+ }), SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsx("span", {
525
+ className: sizeSliderTick,
526
+ style: { left: tickLeft(preset) }
527
+ }, preset))]
528
+ }),
529
+ /* @__PURE__ */ jsx("span", {
530
+ className: sizeValue,
531
+ children: displayWidth === void 0 && dragValue === null ? "Auto" : `${value}%`
532
+ })
533
+ ]
534
+ })]
535
+ });
536
+ }
537
+ function ImageLayoutControl() {
538
+ const [layoutOpen, setLayoutOpen] = useAtom(layoutOpenAtom);
539
+ const layout = useAtomValue(layoutAtom);
540
+ const { handleSetLayout } = useImageActions();
541
+ return /* @__PURE__ */ jsxs(Popover, {
542
+ open: layoutOpen,
543
+ onOpenChange: setLayoutOpen,
544
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
545
+ className: toolbarButtonClass,
546
+ title: "Image layout",
547
+ onMouseDown: stopMouseDown,
548
+ children: /* @__PURE__ */ jsx((LAYOUT_OPTIONS.find((option) => option.value === layout) ?? LAYOUT_OPTIONS[0]).Icon, { size: 14 })
549
+ }), /* @__PURE__ */ jsx(PopoverPanel, {
550
+ className: controlPanel,
551
+ side: "bottom",
552
+ sideOffset: 8,
553
+ children: LAYOUT_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx("button", {
554
+ className: `${toolbarButtonClass} ${layout === value ? editToolbarButtonActive : ""}`.trim(),
555
+ title: label,
556
+ type: "button",
557
+ onMouseDown: stopMouseDown,
558
+ onClick: () => {
559
+ handleSetLayout(value);
560
+ setLayoutOpen(false);
561
+ },
562
+ children: /* @__PURE__ */ jsx(Icon, { size: 14 })
563
+ }, value ?? "center"))
564
+ })]
565
+ });
566
+ }
567
+ //#endregion
381
568
  //#region src/ReplacePanel.tsx
382
569
  var replaceModeItems = [{
383
570
  value: "upload",
@@ -495,6 +682,8 @@ function ImageEditToolbar() {
495
682
  return /* @__PURE__ */ jsxs("div", {
496
683
  className: `${editToolbar} ${semanticClassNames.editToolbar} ${toolbarVisible ? `${editToolbarVisible} ${semanticClassNames.editToolbarVisible}` : ""}`,
497
684
  children: [
685
+ /* @__PURE__ */ jsx(ImageSizeControl, {}),
686
+ /* @__PURE__ */ jsx(ImageLayoutControl, {}),
498
687
  /* @__PURE__ */ jsxs(Popover, {
499
688
  open: metaOpen,
500
689
  onOpenChange: (nextOpen) => {
@@ -541,25 +730,25 @@ function ImageEditToolbar() {
541
730
  }),
542
731
  /* @__PURE__ */ jsx("button", {
543
732
  className: `${editToolbarButton} ${semanticClassNames.editToolbarButton}`,
544
- title: "Open source",
733
+ title: "Duplicate",
545
734
  type: "button",
546
- onClick: handleOpen,
735
+ onClick: handleDuplicate,
547
736
  onMouseDown: (e) => {
548
737
  e.preventDefault();
549
738
  e.stopPropagation();
550
739
  },
551
- children: /* @__PURE__ */ jsx(ExternalLink, { size: 14 })
740
+ children: /* @__PURE__ */ jsx(CopyPlus, { size: 14 })
552
741
  }),
553
742
  /* @__PURE__ */ jsx("button", {
554
743
  className: `${editToolbarButton} ${semanticClassNames.editToolbarButton}`,
555
- title: "Duplicate",
744
+ title: "Open source",
556
745
  type: "button",
557
- onClick: handleDuplicate,
746
+ onClick: handleOpen,
558
747
  onMouseDown: (e) => {
559
748
  e.preventDefault();
560
749
  e.stopPropagation();
561
750
  },
562
- children: /* @__PURE__ */ jsx(Copy, { size: 14 })
751
+ children: /* @__PURE__ */ jsx(ExternalLink, { size: 14 })
563
752
  }),
564
753
  /* @__PURE__ */ jsx("button", {
565
754
  className: `${editToolbarButton} ${semanticClassNames.editToolbarButton}`,
@@ -621,6 +810,84 @@ function ReplacePopover() {
621
810
  });
622
811
  }
623
812
  //#endregion
813
+ //#region src/useImageResize.ts
814
+ var MOVE_THRESHOLD_PX = 3;
815
+ function useImageResize() {
816
+ const store = useStore();
817
+ const [editor] = useLexicalComposerContext();
818
+ const finishRef = useRef(null);
819
+ useEffect(() => () => finishRef.current?.(false), []);
820
+ return { handlePointerDown: useCallback((event, side) => {
821
+ const trigger = store.get(wrapperRefAtom).current;
822
+ if (!trigger) return;
823
+ const frame = trigger.querySelector(`.${semanticClassNames.frame}`);
824
+ const figure = trigger.querySelector("figure");
825
+ const blockWrapper = trigger.closest(".rich-image-wrapper");
826
+ const container = blockWrapper?.parentElement ?? trigger.parentElement;
827
+ if (!frame || !figure || !container) return;
828
+ const containerStyle = getComputedStyle(container);
829
+ const containerWidth = container.clientWidth - Number.parseFloat(containerStyle.paddingLeft) - Number.parseFloat(containerStyle.paddingRight);
830
+ const startWidth = frame.getBoundingClientRect().width;
831
+ if (!containerWidth || containerWidth <= 0 || !startWidth) return;
832
+ event.preventDefault();
833
+ event.stopPropagation();
834
+ const layout = store.get(layoutAtom);
835
+ const factor = layout === void 0 ? 2 : 1;
836
+ const isFloat = layout === "float-left" || layout === "float-right";
837
+ const startX = event.clientX;
838
+ const handle = event.currentTarget;
839
+ try {
840
+ handle.setPointerCapture(event.pointerId);
841
+ } catch {}
842
+ store.set(resizingAtom, true);
843
+ const prevUserSelect = document.body.style.userSelect;
844
+ document.body.style.userSelect = "none";
845
+ let percent = sanitizeImageDisplayWidth(startWidth / containerWidth * 100) ?? 100;
846
+ let moved = false;
847
+ const handleMove = (moveEvent) => {
848
+ const rawDelta = moveEvent.clientX - startX;
849
+ if (!moved && Math.abs(rawDelta) < MOVE_THRESHOLD_PX) return;
850
+ moved = true;
851
+ percent = sanitizeImageDisplayWidth((startWidth + (side === "left" ? -rawDelta : rawDelta) * factor) / containerWidth * 100) ?? percent;
852
+ if (isFloat && blockWrapper) blockWrapper.style.width = `${percent}%`;
853
+ else figure.style.setProperty("--rich-image-display-width", `${percent}%`);
854
+ };
855
+ const finish = (commit) => {
856
+ if (finishRef.current !== finish) return;
857
+ finishRef.current = null;
858
+ handle.removeEventListener("pointermove", handleMove);
859
+ handle.removeEventListener("pointerup", handleEnd);
860
+ handle.removeEventListener("pointercancel", handleEnd);
861
+ document.body.style.userSelect = prevUserSelect;
862
+ store.set(resizingAtom, false);
863
+ if (!commit || !moved) return;
864
+ editor.update(() => {
865
+ const node = $getNearestNodeFromDOMNode(trigger);
866
+ if ($isImageNode(node)) node.setDisplayWidth(percent);
867
+ }, { tag: "skip-scroll-into-view" });
868
+ };
869
+ const handleEnd = () => finish(true);
870
+ finishRef.current = finish;
871
+ handle.addEventListener("pointermove", handleMove);
872
+ handle.addEventListener("pointerup", handleEnd);
873
+ handle.addEventListener("pointercancel", handleEnd);
874
+ }, [editor, store]) };
875
+ }
876
+ //#endregion
877
+ //#region src/ResizeHandles.tsx
878
+ function ResizeHandles() {
879
+ const visible = useAtomValue(toolbarVisibleAtom);
880
+ const { handlePointerDown } = useImageResize();
881
+ const visibleClass = visible ? resizeHandleVisible : "";
882
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
883
+ className: `${resizeHandle} ${resizeHandleLeft} ${visibleClass} ${semanticClassNames.resizeHandle}`.trim(),
884
+ onPointerDown: (e) => handlePointerDown(e, "left")
885
+ }), /* @__PURE__ */ jsx("span", {
886
+ className: `${resizeHandle} ${resizeHandleRight} ${visibleClass} ${semanticClassNames.resizeHandle}`.trim(),
887
+ onPointerDown: (e) => handlePointerDown(e, "right")
888
+ })] });
889
+ }
890
+ //#endregion
624
891
  //#region src/ImageEditRenderer.tsx
625
892
  var frameStateSemanticClass = {
626
893
  loading: semanticClassNames.frameLoading,
@@ -653,6 +920,8 @@ function ImageEditContent() {
653
920
  const setMetaOpen = useSetAtom(metaOpenAtom);
654
921
  const setReplaceOpen = useSetAtom(replaceOpenAtom);
655
922
  const setFocusCaptionOnOpen = useSetAtom(focusCaptionOnOpenAtom);
923
+ const displayWidth = useAtomValue(displayWidthAtom);
924
+ const layout = useAtomValue(layoutAtom);
656
925
  const handleCaptionClick = useCallback((e) => {
657
926
  e.stopPropagation();
658
927
  const scrollY = window.scrollY;
@@ -667,6 +936,7 @@ function ImageEditContent() {
667
936
  setReplaceOpen,
668
937
  setFocusCaptionOnOpen
669
938
  ]);
939
+ const figureStyle = displayWidth ? { "--rich-image-display-width": `${displayWidth}%` } : void 0;
670
940
  return /* @__PURE__ */ jsxs("div", {
671
941
  className: `${editTrigger} ${semanticClassNames.editTrigger}`,
672
942
  ref: wrapperRef,
@@ -674,6 +944,8 @@ function ImageEditContent() {
674
944
  onMouseLeave: () => setHovering(false),
675
945
  children: [src ? /* @__PURE__ */ jsxs("figure", {
676
946
  className: `${root} ${semanticClassNames.root}`,
947
+ "data-layout": layout,
948
+ style: figureStyle,
677
949
  children: [/* @__PURE__ */ jsxs("div", {
678
950
  className: `${frame} ${semanticClassNames.frame} ${frameEditMode} ${imageState[loadState]} ${frameStateSemanticClass[loadState]}`.trim(),
679
951
  style: frameStyle,
@@ -692,7 +964,8 @@ function ImageEditContent() {
692
964
  loadState === "error" && /* @__PURE__ */ jsx("span", {
693
965
  className: `_1n94osfc ${semanticClassNames.errorBadge}`,
694
966
  children: "Image failed to load"
695
- })
967
+ }),
968
+ /* @__PURE__ */ jsx(ResizeHandles, {})
696
969
  ]
697
970
  }), captionText && /* @__PURE__ */ jsx("figcaption", {
698
971
  className: `_1n94osfd ${semanticClassNames.caption}`,
@@ -1,2 +1,2 @@
1
- :root{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}:root.dark,[data-theme=dark]{--rc-text:#fafafa;--rc-text-secondary:#a3a3a3;--rc-text-tertiary:#737373;--rc-text-quaternary:#525252;--rc-bg:#0a0a0a;--rc-bg-secondary:#171717;--rc-bg-tertiary:#262626;--rc-fill:#2a2a2a;--rc-fill-secondary:#222;--rc-fill-tertiary:#1a1a1a;--rc-fill-quaternary:#141414;--rc-border:#262626;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#d4d4d4;--rc-code-bg:#262626;--rc-hr-border:#262626;--rc-quote-border:#60a5fa;--rc-quote-bg:#262626;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006}._7eow1s0{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}._7eow1s1{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.8;--rc-line-height-tight:1.4;--rc-font-family:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}._7eow1s2{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#a3a3a3;--rc-quote-bg:#fafafa;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:none;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:2px;--rc-space-sm:4px;--rc-space-md:10px;--rc-space-lg:16px;--rc-space-xl:20px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:14px;--rc-font-size-small:12px;--rc-line-height:1.5;--rc-line-height-tight:1.3;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:3px;--rc-radius-md:6px;--rc-radius-lg:12px}.dark ._7eow1s0,[data-theme=dark] ._7eow1s0,.dark._7eow1s0,[data-theme=dark]._7eow1s0,.dark ._7eow1s1,[data-theme=dark] ._7eow1s1,.dark._7eow1s1,[data-theme=dark]._7eow1s1,.dark ._7eow1s2,[data-theme=dark] ._7eow1s2,.dark._7eow1s2,[data-theme=dark]._7eow1s2{--rc-text:#fafafa;--rc-text-secondary:#a3a3a3;--rc-text-tertiary:#737373;--rc-text-quaternary:#525252;--rc-bg:#0a0a0a;--rc-bg-secondary:#171717;--rc-bg-tertiary:#262626;--rc-fill:#2a2a2a;--rc-fill-secondary:#222;--rc-fill-tertiary:#1a1a1a;--rc-fill-quaternary:#141414;--rc-border:#262626;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#d4d4d4;--rc-code-bg:#262626;--rc-hr-border:#262626;--rc-quote-border:#60a5fa;--rc-quote-bg:#262626;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006}@keyframes _1n94osf1{0%{opacity:.16;-webkit-mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 150% 0/400% no-repeat;mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 150% 0/400% no-repeat}to{opacity:1;-webkit-mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 0/400% no-repeat;mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 0/400% no-repeat}}@keyframes _1n94osfa{to{transform:rotate(360deg)}}@keyframes _1n94osfi{0%{opacity:0}to{opacity:1}}._1n94osf0{text-align:center;margin:1.25rem 0}._1n94osf2{opacity:0;width:100%;max-width:100%;height:auto;display:block;border-radius:0!important}._1n94osf6{opacity:1;animation:.42s _1n94osf1}._1n94osf7{border-radius:var(--rc-radius-md);cursor:zoom-in;justify-content:center;align-items:center;min-height:3rem;transition:transform .25s;display:inline-flex;position:relative;overflow:hidden}._1n94osf7:hover{transform:translateY(-1px)}._1n94osf8{cursor:default}._1n94osf8:hover{transform:none}._1n94osf9{cursor:default}._1n94osf9:hover{transform:none}._1n94osfb{border:2px solid color-mix(in srgb, var(--rc-text-secondary) 45%, transparent);border-top-color:color-mix(in srgb, var(--rc-text) 65%, transparent);border-radius:50%;width:1.65rem;height:1.65rem;animation:.75s linear infinite _1n94osfa;position:absolute}._1n94osfc{white-space:nowrap;font-size:var(--rc-font-size-sm);letter-spacing:-.005em;color:#fff;-webkit-backdrop-filter:blur(20px)saturate(180%);background:#ff3b30a6;border-radius:6px;padding:.3rem .7rem;font-weight:500;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}._1n94osfd{color:var(--rc-text-tertiary);font-size:var(--rc-font-size-md);margin-top:.5rem;line-height:1.5}._1n94osfe{margin:var(--rc-space-md) 0;text-align:center}._1n94osff{border-radius:var(--rc-radius-md);transition:background-color .3s;display:inline-block;position:relative;overflow:hidden}._1n94osfg{opacity:0;transition:opacity .3s}._1n94osfh{opacity:1;transition:opacity .3s}._1n94osfj{z-index:9999;cursor:zoom-out;background-color:#000000d9;justify-content:center;align-items:center;animation:.2s _1n94osfi;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}._1n94osfk{object-fit:contain;border-radius:0;max-width:90vw;max-height:90vh}.rich-image{margin:var(--rc-space-md) 0;text-align:center}.rich-image figcaption{font-size:var(--rc-font-size-md);color:var(--rc-text-secondary);margin-top:var(--rc-space-sm);line-height:var(--rc-line-height-tight)}.rich-image-container{border-radius:var(--rc-radius-md);transition:background-color .3s;display:inline-block;position:relative;overflow:hidden}.rich-image-hidden{opacity:0;transition:opacity .3s}.rich-image-visible{opacity:1;transition:opacity .3s}.rich-image-zoom-overlay{z-index:9999;cursor:zoom-out;background-color:#000000d9;justify-content:center;align-items:center;animation:.2s _1n94osfi;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}.rich-image-zoom-img{object-fit:contain;border-radius:0;max-width:90vw;max-height:90vh}._1n94osfl{cursor:default;display:block;position:relative}._1n94osfm{border:2px dashed var(--rc-border);border-radius:var(--rc-radius-md);color:var(--rc-text-secondary);font-size:var(--rc-font-size-md);cursor:pointer;flex-direction:column;justify-content:center;align-items:center;gap:8px;padding:2rem;transition:border-color .2s,color .2s,background-color .2s;display:flex}._1n94osfm:hover{border-color:var(--rc-accent);color:var(--rc-text);background-color:color-mix(in srgb, var(--rc-accent) 8%, transparent)}._1n94osfn{z-index:20;border:1px solid var(--rc-border);background:color-mix(in srgb, var(--rc-bg) 96%, transparent);box-shadow:var(--rc-shadow-top-bar);opacity:0;pointer-events:none;border-radius:10px;align-items:center;gap:4px;padding:4px;transition:opacity .15s;display:inline-flex;position:absolute;top:-2.5rem;left:50%;transform:translate(-50%)}._1n94osfo{opacity:1;pointer-events:auto}._1n94osfp{width:30px;height:30px;color:var(--rc-text-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;transition:background-color .15s,color .15s;display:inline-flex}._1n94osfp:hover{color:var(--rc-text);background-color:var(--rc-fill-secondary)}._1n94osfq:hover{color:var(--rc-alert-caution);background-color:color-mix(in srgb, var(--rc-alert-caution) 12%, transparent)}._1n94osfr{width:360px;font-size:var(--rc-font-size-base);font-family:var(--rc-font-family);z-index:30;flex-direction:column;gap:8px;padding:12px;display:flex;position:relative}._1n94osfs{background-color:var(--rc-bg-secondary);border-radius:6px;align-items:center;gap:8px;min-width:0;padding:6px 10px;display:flex}._1n94osft{color:var(--rc-text-secondary);flex-shrink:0}._1n94osfu{-webkit-appearance:none;appearance:none;color:inherit;font-size:var(--rc-font-size-sm);background-color:#0000;border:none;outline:none;flex:1;min-width:0;padding:0}._1n94osfu::placeholder{color:var(--rc-text-secondary)}._1n94osfv{border-radius:var(--rc-radius-md);border:1.5px dashed var(--rc-border);min-height:138px;color:var(--rc-text-secondary);cursor:pointer;flex-direction:column;justify-content:center;align-items:center;gap:.45rem;transition:border-color .15s,background-color .15s;display:flex}._1n94osfv:hover{border-color:color-mix(in srgb, var(--rc-accent) 45%, transparent);color:var(--rc-text);background-color:color-mix(in srgb, var(--rc-accent) 7%, transparent)}._1n94osfw{border-radius:var(--rc-radius-md);border:1px solid var(--rc-border);background-color:color-mix(in srgb, var(--rc-text) 2%, transparent);overflow:hidden}._1n94osfw img{object-fit:cover;width:100%;max-height:188px;display:block}._1n94osfx{color:var(--rc-text-secondary);font-size:var(--rc-font-size-xs);align-items:center;gap:.4rem;display:inline-flex}
1
+ :root{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}:root.dark,[data-theme=dark]{--rc-text:#fafafa;--rc-text-secondary:#a3a3a3;--rc-text-tertiary:#737373;--rc-text-quaternary:#525252;--rc-bg:#0a0a0a;--rc-bg-secondary:#171717;--rc-bg-tertiary:#262626;--rc-fill:#2a2a2a;--rc-fill-secondary:#222;--rc-fill-tertiary:#1a1a1a;--rc-fill-quaternary:#141414;--rc-border:#262626;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#d4d4d4;--rc-code-bg:#262626;--rc-hr-border:#262626;--rc-quote-border:#60a5fa;--rc-quote-bg:#262626;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006}._7eow1s0{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}._7eow1s1{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.8;--rc-line-height-tight:1.4;--rc-font-family:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}._7eow1s2{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#a3a3a3;--rc-quote-bg:#fafafa;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:none;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:2px;--rc-space-sm:4px;--rc-space-md:10px;--rc-space-lg:16px;--rc-space-xl:20px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:14px;--rc-font-size-small:12px;--rc-line-height:1.5;--rc-line-height-tight:1.3;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:3px;--rc-radius-md:6px;--rc-radius-lg:12px}.dark ._7eow1s0,[data-theme=dark] ._7eow1s0,.dark._7eow1s0,[data-theme=dark]._7eow1s0,.dark ._7eow1s1,[data-theme=dark] ._7eow1s1,.dark._7eow1s1,[data-theme=dark]._7eow1s1,.dark ._7eow1s2,[data-theme=dark] ._7eow1s2,.dark._7eow1s2,[data-theme=dark]._7eow1s2{--rc-text:#fafafa;--rc-text-secondary:#a3a3a3;--rc-text-tertiary:#737373;--rc-text-quaternary:#525252;--rc-bg:#0a0a0a;--rc-bg-secondary:#171717;--rc-bg-tertiary:#262626;--rc-fill:#2a2a2a;--rc-fill-secondary:#222;--rc-fill-tertiary:#1a1a1a;--rc-fill-quaternary:#141414;--rc-border:#262626;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#d4d4d4;--rc-code-bg:#262626;--rc-hr-border:#262626;--rc-quote-border:#60a5fa;--rc-quote-bg:#262626;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006}@keyframes _1n94osf1{0%{opacity:.16;-webkit-mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 150% 0/400% no-repeat;mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 150% 0/400% no-repeat}to{opacity:1;-webkit-mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 0/400% no-repeat;mask:linear-gradient(90deg,#000 25%,#000000e6 50%,#0000) 0/400% no-repeat}}@keyframes _1n94osfa{to{transform:rotate(360deg)}}@keyframes _1n94osfi{0%{opacity:0}to{opacity:1}}._1n94osf0{text-align:center;width:var(--rich-image-display-width,auto);max-width:100%;margin:1.25rem auto}._1n94osf0[data-layout=align-left]{text-align:left;margin-left:0;margin-right:auto}._1n94osf0[data-layout=align-right]{text-align:right;margin-left:auto;margin-right:0}._1n94osf0[data-layout=float-left]{float:left;width:var(--rich-image-display-width,50%);margin:.25rem 1.5rem 1rem 0}._1n94osf0[data-layout=float-right]{float:right;width:var(--rich-image-display-width,50%);margin:.25rem 0 1rem 1.5rem}.rich-image-wrapper[data-layout^=float] ._1n94osf0{float:none;width:auto;margin:0}._1n94osf2{opacity:0;width:100%;max-width:100%;height:auto;display:block;border-radius:0!important}._1n94osf6{opacity:1;animation:.42s _1n94osf1}._1n94osf7{border-radius:var(--rc-radius-md);cursor:zoom-in;justify-content:center;align-items:center;min-height:3rem;transition:transform .25s;display:inline-flex;position:relative;overflow:hidden}._1n94osf7:hover{transform:translateY(-1px)}._1n94osf8{cursor:default}._1n94osf8:hover{transform:none}._1n94osf9{cursor:default}._1n94osf9:hover{transform:none}._1n94osfb{border:2px solid color-mix(in srgb, var(--rc-text-secondary) 45%, transparent);border-top-color:color-mix(in srgb, var(--rc-text) 65%, transparent);border-radius:50%;width:1.65rem;height:1.65rem;animation:.75s linear infinite _1n94osfa;position:absolute}._1n94osfc{white-space:nowrap;font-size:var(--rc-font-size-sm);letter-spacing:-.005em;color:#fff;-webkit-backdrop-filter:blur(20px)saturate(180%);background:#ff3b30a6;border-radius:6px;padding:.3rem .7rem;font-weight:500;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}._1n94osfd{color:var(--rc-text-tertiary);font-size:var(--rc-font-size-md);margin-top:.5rem;line-height:1.5}._1n94osfe{margin:var(--rc-space-md) 0;text-align:center}._1n94osff{border-radius:var(--rc-radius-md);transition:background-color .3s;display:inline-block;position:relative;overflow:hidden}._1n94osfg{opacity:0;transition:opacity .3s}._1n94osfh{opacity:1;transition:opacity .3s}._1n94osfj{z-index:9999;cursor:zoom-out;background-color:#000000d9;justify-content:center;align-items:center;animation:.2s _1n94osfi;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}._1n94osfk{object-fit:contain;border-radius:0;max-width:90vw;max-height:90vh}.rich-image{margin:var(--rc-space-md) 0;text-align:center}.rich-image figcaption{font-size:var(--rc-font-size-md);color:var(--rc-text-secondary);margin-top:var(--rc-space-sm);line-height:var(--rc-line-height-tight)}.rich-image-container{border-radius:var(--rc-radius-md);transition:background-color .3s;display:inline-block;position:relative;overflow:hidden}.rich-image-hidden{opacity:0;transition:opacity .3s}.rich-image-visible{opacity:1;transition:opacity .3s}.rich-image-zoom-overlay{z-index:9999;cursor:zoom-out;background-color:#000000d9;justify-content:center;align-items:center;animation:.2s _1n94osfi;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}.rich-image-zoom-img{object-fit:contain;border-radius:0;max-width:90vw;max-height:90vh}._1n94osfl{cursor:default;display:block;position:relative}._1n94osfm{border:2px dashed var(--rc-border);border-radius:var(--rc-radius-md);color:var(--rc-text-secondary);font-size:var(--rc-font-size-md);cursor:pointer;flex-direction:column;justify-content:center;align-items:center;gap:8px;padding:2rem;transition:border-color .2s,color .2s,background-color .2s;display:flex}._1n94osfm:hover{border-color:var(--rc-accent);color:var(--rc-text);background-color:color-mix(in srgb, var(--rc-accent) 8%, transparent)}._1n94osfn{z-index:20;border:1px solid var(--rc-border);background:color-mix(in srgb, var(--rc-bg) 96%, transparent);box-shadow:var(--rc-shadow-top-bar);opacity:0;pointer-events:none;border-radius:10px;align-items:center;gap:4px;padding:4px;transition:opacity .15s;display:inline-flex;position:absolute;top:-2.5rem;left:50%;transform:translate(-50%)}._1n94osfo{opacity:1;pointer-events:auto}._1n94osfp{width:30px;height:30px;color:var(--rc-text-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;transition:background-color .15s,color .15s;display:inline-flex}._1n94osfp:hover{color:var(--rc-text);background-color:var(--rc-fill-secondary)}._1n94osfq:hover{color:var(--rc-alert-caution);background-color:color-mix(in srgb, var(--rc-alert-caution) 12%, transparent)}._1n94osfr{width:360px;font-size:var(--rc-font-size-base);font-family:var(--rc-font-family);z-index:30;flex-direction:column;gap:8px;padding:12px;display:flex;position:relative}._1n94osfs{background-color:var(--rc-bg-secondary);border-radius:6px;align-items:center;gap:8px;min-width:0;padding:6px 10px;display:flex}._1n94osft{color:var(--rc-text-secondary);flex-shrink:0}._1n94osfu{-webkit-appearance:none;appearance:none;color:inherit;font-size:var(--rc-font-size-sm);background-color:#0000;border:none;outline:none;flex:1;min-width:0;padding:0}._1n94osfu::placeholder{color:var(--rc-text-secondary)}._1n94osfv{border-radius:var(--rc-radius-md);border:1.5px dashed var(--rc-border);min-height:138px;color:var(--rc-text-secondary);cursor:pointer;flex-direction:column;justify-content:center;align-items:center;gap:.45rem;transition:border-color .15s,background-color .15s;display:flex}._1n94osfv:hover{border-color:color-mix(in srgb, var(--rc-accent) 45%, transparent);color:var(--rc-text);background-color:color-mix(in srgb, var(--rc-accent) 7%, transparent)}._1n94osfw{border-radius:var(--rc-radius-md);border:1px solid var(--rc-border);background-color:color-mix(in srgb, var(--rc-text) 2%, transparent);overflow:hidden}._1n94osfw img{object-fit:cover;width:100%;max-height:188px;display:block}._1n94osfx{color:var(--rc-text-secondary);font-size:var(--rc-font-size-xs);align-items:center;gap:.4rem;display:inline-flex}._1n94osfy{cursor:ew-resize;touch-action:none;opacity:0;z-index:10;background:#ffffffeb;border:1px solid #0000002e;border-radius:9999px;width:6px;height:36px;max-height:50%;transition:opacity .15s;position:absolute;top:50%;transform:translateY(-50%);box-shadow:0 1px 3px #00000040}._1n94osfz{left:6px}._1n94osf10{right:6px}._1n94osf11{opacity:1}._1n94osf12{font-family:var(--rc-font-family);z-index:30;align-items:center;gap:4px;padding:4px;display:flex}._1n94osf12._1n94osf12{width:-moz-fit-content;width:fit-content}._1n94osf13{align-items:center;width:132px;height:24px;display:flex;position:relative}._1n94osf14{-webkit-appearance:none;appearance:none;cursor:pointer;background:0 0;width:100%;height:24px;margin:0}._1n94osf14::-webkit-slider-runnable-track{background:linear-gradient(to right, var(--rc-text-secondary) var(--fill), var(--rc-fill) var(--fill));border-radius:9999px;height:3px}._1n94osf14::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background-color:var(--rc-bg);border:1px solid var(--rc-border);cursor:ew-resize;border-radius:50%;width:12px;height:12px;margin-top:-4.5px;box-shadow:0 1px 3px #0003}._1n94osf14::-moz-range-track{background:linear-gradient(to right, var(--rc-text-secondary) var(--fill), var(--rc-fill) var(--fill));border-radius:9999px;height:3px}._1n94osf14::-moz-range-thumb{-webkit-appearance:none;appearance:none;background-color:var(--rc-bg);border:1px solid var(--rc-border);cursor:ew-resize;border-radius:50%;width:12px;height:12px;box-shadow:0 1px 3px #0003}._1n94osf15{background-color:var(--rc-bg);pointer-events:none;border-radius:50%;width:3px;height:3px;position:absolute;top:50%;transform:translate(-50%,-50%)}._1n94osf16{text-align:right;min-width:34px;font-size:var(--rc-font-size-xs);font-variant-numeric:tabular-nums;color:var(--rc-text-secondary)}._1n94osf17{height:26px;color:var(--rc-text-secondary);font-size:var(--rc-font-size-xs);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0 8px;font-weight:500;transition:background-color .15s,color .15s;display:inline-flex}._1n94osf17:hover,._1n94osf18{color:var(--rc-text);background-color:var(--rc-fill-secondary)}@media (max-width:640px){._1n94osf0[data-layout=float-left],._1n94osf0[data-layout=float-right]{float:none;width:auto;margin:1.25rem auto}}
2
2
  /*$vite$:1*/
package/dist/static.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as ImageRenderer } from "./ImageRenderer-BihkEC_w.js";
1
+ import { t as ImageRenderer } from "./ImageRenderer-ew0e3cUJ.js";
2
2
  export { ImageRenderer };
@@ -21,6 +21,7 @@ export declare const semanticClassNames: {
21
21
  readonly replaceUploadArea: "rr-image-replace-upload-area";
22
22
  readonly replacePreview: "rr-image-replace-preview";
23
23
  readonly panelHint: "rr-image-panel-hint";
24
+ readonly resizeHandle: "rr-image-resize-handle";
24
25
  };
25
26
  export declare const root: string;
26
27
  export declare const image: string;
@@ -59,4 +60,15 @@ export declare const editInput: string;
59
60
  export declare const replaceUploadArea: string;
60
61
  export declare const replacePreview: string;
61
62
  export declare const panelHint: string;
63
+ export declare const resizeHandle: string;
64
+ export declare const resizeHandleLeft: string;
65
+ export declare const resizeHandleRight: string;
66
+ export declare const resizeHandleVisible: string;
67
+ export declare const controlPanel: string;
68
+ export declare const sizeSliderWrap: string;
69
+ export declare const sizeSlider: string;
70
+ export declare const sizeSliderTick: string;
71
+ export declare const sizeValue: string;
72
+ export declare const sizeOption: string;
73
+ export declare const editToolbarButtonActive: string;
62
74
  //# sourceMappingURL=styles.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.css.d.ts","sourceRoot":"","sources":["../src/styles.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;CAuBrB,CAAC;AAEX,eAAO,MAAM,IAAI,QAGf,CAAC;AAaH,eAAO,MAAM,KAAK,QAOhB,CAAC;AAEH,eAAO,MAAM,UAAU,gDAIrB,CAAC;AAEH,eAAO,MAAM,YAAY,QAGvB,CAAC;AAEH,eAAO,MAAM,KAAK,QAehB,CAAC;AAEH,eAAO,MAAM,aAAa,QAOxB,CAAC;AAEH,eAAO,MAAM,WAAW,QAOtB,CAAC;AAIH,eAAO,MAAM,MAAM,QAQjB,CAAC;AAEH,eAAO,MAAM,UAAU,QAerB,CAAC;AAEH,eAAO,MAAM,OAAO,QAKlB,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;CAO5B,CAAC;AAgCX,eAAO,MAAM,WAAW,QAA2B,CAAC;AACpD,eAAO,MAAM,gBAAgB,QAAgC,CAAC;AAC9D,eAAO,MAAM,aAAa,QAA6B,CAAC;AACxD,eAAO,MAAM,cAAc,QAA8B,CAAC;AA0B1D,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAClE,eAAO,MAAM,gBAAgB,QAAgC,CAAC;AAU9D,eAAO,MAAM,WAAW,QAItB,CAAC;AAEH,eAAO,MAAM,eAAe,QAoB1B,CAAC;AAEH,eAAO,MAAM,WAAW,QAiBtB,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAG7B,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAkB5B,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAOlC,CAAC;AAEH,eAAO,MAAM,SAAS,QAUpB,CAAC;AAEH,eAAO,MAAM,SAAS,QAQpB,CAAC;AAEH,eAAO,MAAM,aAAa,QAGxB,CAAC;AAEH,eAAO,MAAM,SAAS,QAepB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAmB5B,CAAC;AAEH,eAAO,MAAM,cAAc,QAKzB,CAAC;AASH,eAAO,MAAM,SAAS,QAMpB,CAAC"}
1
+ {"version":3,"file":"styles.css.d.ts","sourceRoot":"","sources":["../src/styles.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;CAwBrB,CAAC;AAEX,eAAO,MAAM,IAAI,QAsCf,CAAC;AAsBH,eAAO,MAAM,KAAK,QAOhB,CAAC;AAEH,eAAO,MAAM,UAAU,gDAIrB,CAAC;AAEH,eAAO,MAAM,YAAY,QAGvB,CAAC;AAEH,eAAO,MAAM,KAAK,QAehB,CAAC;AAEH,eAAO,MAAM,aAAa,QAOxB,CAAC;AAEH,eAAO,MAAM,WAAW,QAOtB,CAAC;AAIH,eAAO,MAAM,MAAM,QAQjB,CAAC;AAEH,eAAO,MAAM,UAAU,QAerB,CAAC;AAEH,eAAO,MAAM,OAAO,QAKlB,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;CAO5B,CAAC;AAgCX,eAAO,MAAM,WAAW,QAA2B,CAAC;AACpD,eAAO,MAAM,gBAAgB,QAAgC,CAAC;AAC9D,eAAO,MAAM,aAAa,QAA6B,CAAC;AACxD,eAAO,MAAM,cAAc,QAA8B,CAAC;AA0B1D,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAClE,eAAO,MAAM,gBAAgB,QAAgC,CAAC;AAU9D,eAAO,MAAM,WAAW,QAItB,CAAC;AAEH,eAAO,MAAM,eAAe,QAoB1B,CAAC;AAEH,eAAO,MAAM,WAAW,QAiBtB,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAG7B,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAkB5B,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAOlC,CAAC;AAEH,eAAO,MAAM,SAAS,QAUpB,CAAC;AAEH,eAAO,MAAM,SAAS,QAQpB,CAAC;AAEH,eAAO,MAAM,aAAa,QAGxB,CAAC;AAEH,eAAO,MAAM,SAAS,QAepB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAmB5B,CAAC;AAEH,eAAO,MAAM,cAAc,QAKzB,CAAC;AASH,eAAO,MAAM,SAAS,QAMpB,CAAC;AAEH,eAAO,MAAM,YAAY,QAgBvB,CAAC;AAEH,eAAO,MAAM,gBAAgB,QAAqB,CAAC;AACnD,eAAO,MAAM,iBAAiB,QAAsB,CAAC;AAErD,eAAO,MAAM,mBAAmB,QAE9B,CAAC;AAEH,eAAO,MAAM,YAAY,QAOvB,CAAC;AAQH,eAAO,MAAM,cAAc,QAMzB,CAAC;AAaH,eAAO,MAAM,UAAU,QAwBrB,CAAC;AAEH,eAAO,MAAM,cAAc,QASzB,CAAC;AAEH,eAAO,MAAM,SAAS,QAMpB,CAAC;AAEH,eAAO,MAAM,UAAU,QAoBrB,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAGlC,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { ImageLayout } from '@haklex/rich-editor/nodes';
1
2
  export declare function useImageActions(): {
2
3
  commitMeta: () => void;
3
4
  closeReplacePanel: () => void;
@@ -9,5 +10,7 @@ export declare function useImageActions(): {
9
10
  handleDuplicate: () => void;
10
11
  handleDownload: () => void;
11
12
  handleDelete: () => void;
13
+ handleSetDisplayWidth: (width?: number) => void;
14
+ handleSetLayout: (layout?: ImageLayout) => void;
12
15
  };
13
16
  //# sourceMappingURL=useImageActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useImageActions.d.ts","sourceRoot":"","sources":["../src/useImageActions.ts"],"names":[],"mappings":"AAoDA,wBAAgB,eAAe;;;8BA+Ed,IAAI,GAAG,IAAI;;;wCA6Db,OAAO;;;;;EAmBrB"}
1
+ {"version":3,"file":"useImageActions.d.ts","sourceRoot":"","sources":["../src/useImageActions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAqD7D,wBAAgB,eAAe;;;8BAwGd,IAAI,GAAG,IAAI;;;wCA6Db,OAAO;;;;;oCA/ET,MAAM;+BASL,WAAW;EA2FxB"}
@@ -0,0 +1,5 @@
1
+ export type ResizeSide = 'left' | 'right';
2
+ export declare function useImageResize(): {
3
+ handlePointerDown: (event: React.PointerEvent<HTMLElement>, side: ResizeSide) => void;
4
+ };
5
+ //# sourceMappingURL=useImageResize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useImageResize.d.ts","sourceRoot":"","sources":["../src/useImageResize.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;AAI1C,wBAAgB,cAAc;+BAQlB,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,QAAQ,UAAU;EAqF5D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haklex/rich-renderer-image",
3
- "version": "0.22.1",
3
+ "version": "0.24.0",
4
4
  "description": "Image renderer with blurhash",
5
5
  "repository": {
6
6
  "type": "git",
@@ -46,9 +46,9 @@
46
46
  "lucide-react": "^1.0.0",
47
47
  "react": ">=19",
48
48
  "react-dom": ">=19",
49
- "@haklex/rich-editor-ui": "0.22.1",
50
- "@haklex/rich-style-token": "0.22.1",
51
- "@haklex/rich-editor": "0.22.1"
49
+ "@haklex/rich-editor": "0.24.0",
50
+ "@haklex/rich-editor-ui": "0.24.0",
51
+ "@haklex/rich-style-token": "0.24.0"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public"