@tarviks/lexical-rich-editor 1.2.0 → 1.2.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/dist/index.js CHANGED
@@ -636,7 +636,6 @@ var init_ImageComponent = __esm({
636
636
  editor,
637
637
  buttonRef,
638
638
  imageRef,
639
- maxWidth,
640
639
  onResizeStart,
641
640
  onResizeEnd,
642
641
  captionsEnabled: !isLoadError && captionsEnabled
@@ -787,6 +786,9 @@ var init_ImageNode = __esm({
787
786
  const writable = this.getWritable();
788
787
  writable.__width = width;
789
788
  writable.__height = height;
789
+ if (typeof width === "number" && width > writable.__maxWidth) {
790
+ writable.__maxWidth = width;
791
+ }
790
792
  }
791
793
  setShowCaption(showCaption) {
792
794
  const writable = this.getWritable();
@@ -876,6 +878,7 @@ __export(InlineImageComponent_exports, {
876
878
  var imageCache2, useSuspenseImage2, LazyImage2, InlineImageComponent, InlineImageComponent_default;
877
879
  var init_InlineImageComponent = __esm({
878
880
  "src/Nodes/InlineImageComponent.tsx"() {
881
+ init_ImageResizer();
879
882
  init_InlineImage();
880
883
  init_InlineImageNode();
881
884
  imageCache2 = /* @__PURE__ */ new Set();
@@ -918,6 +921,29 @@ var init_InlineImageComponent = __esm({
918
921
  const buttonRef = React9.useRef(null);
919
922
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
920
923
  const isEditable = useLexicalEditable.useLexicalEditable();
924
+ const [isResizing, setIsResizing] = React9.useState(false);
925
+ const onResizeEnd = (nextWidth, nextHeight) => {
926
+ setTimeout(() => {
927
+ setIsResizing(false);
928
+ }, 200);
929
+ editor.update(() => {
930
+ const node = lexical.$getNodeByKey(nodeKey);
931
+ if ($isInlineImageNode(node)) {
932
+ node.setWidthAndHeight(nextWidth, nextHeight);
933
+ }
934
+ });
935
+ };
936
+ const onResizeStart = () => {
937
+ setIsResizing(true);
938
+ };
939
+ const setShowCaption = (show) => {
940
+ editor.update(() => {
941
+ const node = lexical.$getNodeByKey(nodeKey);
942
+ if ($isInlineImageNode(node)) {
943
+ node.setShowCaption(show);
944
+ }
945
+ });
946
+ };
921
947
  const $onDelete = React9.useCallback(
922
948
  (payload) => {
923
949
  const deleteSelection = lexical.$getSelection();
@@ -993,6 +1019,9 @@ var init_InlineImageComponent = __esm({
993
1019
  lexical.CLICK_COMMAND,
994
1020
  (payload) => {
995
1021
  const event = payload;
1022
+ if (isResizing) {
1023
+ return true;
1024
+ }
996
1025
  if (event.target === imageRef.current) {
997
1026
  if (event.shiftKey) {
998
1027
  setSelected(!isSelected);
@@ -1041,6 +1070,7 @@ var init_InlineImageComponent = __esm({
1041
1070
  }, [
1042
1071
  clearSelection,
1043
1072
  editor,
1073
+ isResizing,
1044
1074
  isSelected,
1045
1075
  nodeKey,
1046
1076
  $onDelete,
@@ -1048,20 +1078,35 @@ var init_InlineImageComponent = __esm({
1048
1078
  $onEscape,
1049
1079
  setSelected
1050
1080
  ]);
1051
- const draggable = isSelected && lexical.$isNodeSelection(selection);
1052
- const isFocused = isSelected && isEditable;
1053
- return /* @__PURE__ */ jsxRuntime.jsx(React9.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx("span", { draggable, children: /* @__PURE__ */ jsxRuntime.jsx(
1054
- LazyImage2,
1055
- {
1056
- className: isFocused ? `focused ${lexical.$isNodeSelection(selection) ? "draggable" : ""}` : null,
1057
- src,
1058
- altText,
1059
- imageRef,
1060
- width,
1061
- height,
1062
- position
1063
- }
1064
- ) }) });
1081
+ const draggable = isSelected && lexical.$isNodeSelection(selection) && !isResizing;
1082
+ const isFocused = (isSelected || isResizing) && isEditable;
1083
+ return /* @__PURE__ */ jsxRuntime.jsx(React9.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1084
+ /* @__PURE__ */ jsxRuntime.jsx("span", { draggable, children: /* @__PURE__ */ jsxRuntime.jsx(
1085
+ LazyImage2,
1086
+ {
1087
+ className: isFocused ? `focused ${lexical.$isNodeSelection(selection) ? "draggable" : ""}` : null,
1088
+ src,
1089
+ altText,
1090
+ imageRef,
1091
+ width,
1092
+ height,
1093
+ position
1094
+ }
1095
+ ) }),
1096
+ isFocused && lexical.$isNodeSelection(selection) && /* @__PURE__ */ jsxRuntime.jsx(
1097
+ ImageResizer_default,
1098
+ {
1099
+ showCaption,
1100
+ setShowCaption,
1101
+ editor,
1102
+ buttonRef,
1103
+ imageRef,
1104
+ onResizeStart,
1105
+ onResizeEnd,
1106
+ captionsEnabled: false
1107
+ }
1108
+ )
1109
+ ] }) });
1065
1110
  };
1066
1111
  InlineImageComponent_default = InlineImageComponent;
1067
1112
  }
@@ -2878,7 +2923,7 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
2878
2923
  return;
2879
2924
  }
2880
2925
  const rootElement = editor.getRootElement();
2881
- if (selection !== null && nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode) && editor.isEditable()) {
2926
+ if (isLink && selection !== null && nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode) && editor.isEditable()) {
2882
2927
  const domRect = nativeSelection.focusNode?.parentElement?.getBoundingClientRect();
2883
2928
  if (domRect) {
2884
2929
  domRect.y += 40;
@@ -2894,7 +2939,7 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
2894
2939
  setLinkUrl("");
2895
2940
  }
2896
2941
  return true;
2897
- }, [anchorElem, editor, setIsLinkEditMode, isLinkEditMode, linkUrl]);
2942
+ }, [anchorElem, editor, isLink, setIsLinkEditMode, isLinkEditMode, linkUrl]);
2898
2943
  React9.useEffect(() => {
2899
2944
  const scrollerElem = anchorElem.parentElement;
2900
2945
  const update = () => {
@@ -2992,6 +3037,7 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
2992
3037
  {
2993
3038
  ref: inputRef,
2994
3039
  className: "link-input",
3040
+ placeholder: "https://",
2995
3041
  value: editedLinkUrl,
2996
3042
  onChange: (event) => {
2997
3043
  setEditedLinkUrl(event.target.value);
@@ -3001,27 +3047,31 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
3001
3047
  }
3002
3048
  }
3003
3049
  ),
3004
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3050
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "link-actions", children: [
3005
3051
  /* @__PURE__ */ jsxRuntime.jsx(
3006
- "div",
3052
+ "button",
3007
3053
  {
3008
- className: "link-cancel",
3009
- role: "button",
3010
- tabIndex: 0,
3054
+ type: "button",
3055
+ className: "link-icon-btn link-cancel",
3056
+ title: "Cancel",
3057
+ "aria-label": "Cancel",
3011
3058
  onMouseDown: preventDefault,
3012
3059
  onClick: () => {
3013
3060
  setIsLinkEditMode(false);
3014
- }
3061
+ },
3062
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Dismiss16Regular, {})
3015
3063
  }
3016
3064
  ),
3017
3065
  /* @__PURE__ */ jsxRuntime.jsx(
3018
- "div",
3066
+ "button",
3019
3067
  {
3020
- className: "link-confirm",
3021
- role: "button",
3022
- tabIndex: 0,
3068
+ type: "button",
3069
+ className: "link-icon-btn link-confirm",
3070
+ title: "Confirm",
3071
+ "aria-label": "Confirm",
3023
3072
  onMouseDown: preventDefault,
3024
- onClick: handleLinkSubmission
3073
+ onClick: handleLinkSubmission,
3074
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Checkmark16Regular, {})
3025
3075
  }
3026
3076
  )
3027
3077
  ] })
@@ -3035,32 +3085,38 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
3035
3085
  children: linkUrl
3036
3086
  }
3037
3087
  ),
3038
- /* @__PURE__ */ jsxRuntime.jsx(
3039
- "div",
3040
- {
3041
- className: "link-edit",
3042
- role: "button",
3043
- tabIndex: 0,
3044
- onMouseDown: preventDefault,
3045
- onClick: (event) => {
3046
- event.preventDefault();
3047
- setEditedLinkUrl(linkUrl);
3048
- setIsLinkEditMode(true);
3088
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "link-actions", children: [
3089
+ /* @__PURE__ */ jsxRuntime.jsx(
3090
+ "button",
3091
+ {
3092
+ type: "button",
3093
+ className: "link-icon-btn link-edit",
3094
+ title: "Edit link",
3095
+ "aria-label": "Edit link",
3096
+ onMouseDown: preventDefault,
3097
+ onClick: (event) => {
3098
+ event.preventDefault();
3099
+ setEditedLinkUrl(linkUrl);
3100
+ setIsLinkEditMode(true);
3101
+ },
3102
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Edit16Regular, {})
3049
3103
  }
3050
- }
3051
- ),
3052
- /* @__PURE__ */ jsxRuntime.jsx(
3053
- "div",
3054
- {
3055
- className: "link-trash",
3056
- role: "button",
3057
- tabIndex: 0,
3058
- onMouseDown: preventDefault,
3059
- onClick: () => {
3060
- editor.dispatchCommand(link.TOGGLE_LINK_COMMAND, null);
3104
+ ),
3105
+ /* @__PURE__ */ jsxRuntime.jsx(
3106
+ "button",
3107
+ {
3108
+ type: "button",
3109
+ className: "link-icon-btn link-trash",
3110
+ title: "Remove link",
3111
+ "aria-label": "Remove link",
3112
+ onMouseDown: preventDefault,
3113
+ onClick: () => {
3114
+ editor.dispatchCommand(link.TOGGLE_LINK_COMMAND, null);
3115
+ },
3116
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Delete16Regular, {})
3061
3117
  }
3062
- }
3063
- )
3118
+ )
3119
+ ] })
3064
3120
  ] }) });
3065
3121
  };
3066
3122
  var useFloatingLinkEditorToolbar = (editor, anchorElem, isLinkEditMode, setIsLinkEditMode) => {
@@ -3161,74 +3217,28 @@ var readClipboardImageAsDataURL = async (event) => {
3161
3217
  }
3162
3218
  return null;
3163
3219
  };
3164
- var InsertImageByURL = ({
3165
- setIsOpen,
3166
- onClick,
3167
- disabled
3168
- }) => {
3169
- const [altText, setAltText] = React9.useState("");
3170
- const [src, setSrc] = React9.useState("");
3171
- const isDisabled = disabled || src === "";
3172
- return /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 6, padding: "10px 0px 0px 0px" }, children: [
3173
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Enter URL", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
3174
- reactComponents.Input,
3175
- {
3176
- autoFocus: !disabled,
3177
- appearance: "underline",
3178
- placeholder: "Add URL",
3179
- disabled,
3180
- onChange: (_, v) => setSrc(v.value),
3181
- value: src
3182
- }
3183
- ) }),
3184
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
3185
- reactComponents.Input,
3186
- {
3187
- placeholder: "Alt text",
3188
- disabled,
3189
- onChange: (_, v) => setAltText(v.value),
3190
- value: altText
3191
- },
3192
- "alt-text-url"
3193
- ) }),
3194
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
3195
- /* @__PURE__ */ jsxRuntime.jsx(
3196
- reactComponents.Button,
3197
- {
3198
- style: { width: "150px" },
3199
- onClick: () => !disabled && onClick({ altText, src }),
3200
- disabled: isDisabled,
3201
- size: "small",
3202
- children: "Confirm"
3203
- },
3204
- "url-confirm-btn"
3205
- ),
3206
- /* @__PURE__ */ jsxRuntime.jsx(
3207
- reactComponents.Button,
3208
- {
3209
- style: { width: "150px" },
3210
- onClick: () => setIsOpen(false),
3211
- disabled,
3212
- size: "small",
3213
- children: "Cancel"
3214
- },
3215
- "file-url-cancel"
3216
- )
3217
- ] })
3218
- ] });
3219
- };
3220
3220
  var InsertImageDialog = ({
3221
3221
  activeEditor,
3222
- disabled
3222
+ disabled,
3223
+ open: externalOpen,
3224
+ onClose
3223
3225
  }) => {
3224
3226
  const [src, setSrc] = React9.useState("");
3225
3227
  const [altText, setAltText] = React9.useState("");
3226
- const [isOpen, setIsOpen] = React9.useState(false);
3227
- const [selectedValue, setSelectedValue] = React9.useState("Upload");
3228
+ const [internalOpen, setInternalOpen] = React9.useState(false);
3228
3229
  const [fileName, setFileName] = React9.useState("");
3229
3230
  const hasModifier = React9.useRef(false);
3230
3231
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
3231
- const isDisabled = disabled || src === "";
3232
+ const isControlled = externalOpen !== void 0;
3233
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
3234
+ const isAddDisabled = disabled || src === "";
3235
+ const handleClose = () => {
3236
+ setSrc("");
3237
+ setAltText("");
3238
+ setFileName("");
3239
+ if (isControlled) onClose?.();
3240
+ else setInternalOpen(false);
3241
+ };
3232
3242
  React9.useEffect(() => {
3233
3243
  hasModifier.current = false;
3234
3244
  const handler = (e) => {
@@ -3240,10 +3250,7 @@ var InsertImageDialog = ({
3240
3250
  const onClick = (payload) => {
3241
3251
  if (disabled) return;
3242
3252
  activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, payload);
3243
- setIsOpen(false);
3244
- setAltText("");
3245
- setSrc("");
3246
- setFileName("");
3253
+ handleClose();
3247
3254
  };
3248
3255
  const loadImage = (event) => {
3249
3256
  if (disabled) return;
@@ -3258,118 +3265,108 @@ var InsertImageDialog = ({
3258
3265
  };
3259
3266
  reader.readAsDataURL(files[0]);
3260
3267
  };
3261
- return /* @__PURE__ */ jsxRuntime.jsxs(
3262
- reactComponents.Popover,
3263
- {
3264
- trapFocus: true,
3265
- withArrow: true,
3266
- open: disabled ? false : isOpen,
3267
- onOpenChange: (_, data) => {
3268
- if (!disabled) setIsOpen(data.open);
3268
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3269
+ !isControlled && /* @__PURE__ */ jsxRuntime.jsx(
3270
+ reactComponents.Button,
3271
+ {
3272
+ size: "small",
3273
+ title: "Add Image",
3274
+ disabled,
3275
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ImageAddRegular, { style: { color: iconColor } }),
3276
+ style: {
3277
+ background: isOpen && !disabled ? "#ebebeb" : "none",
3278
+ border: "none",
3279
+ margin: 2,
3280
+ opacity: disabled ? 0.55 : 1,
3281
+ cursor: disabled ? "not-allowed" : "pointer"
3282
+ },
3283
+ onClick: () => {
3284
+ if (disabled) return;
3285
+ setSrc("");
3286
+ setAltText("");
3287
+ setFileName("");
3288
+ setInternalOpen(true);
3289
+ }
3269
3290
  },
3270
- children: [
3271
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3272
- reactComponents.Button,
3273
- {
3274
- size: "small",
3275
- title: "Add Image",
3276
- disabled,
3277
- icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ImageAddRegular, { style: { color: iconColor } }),
3278
- style: {
3279
- background: isOpen && !disabled ? "#ebebeb" : "none",
3280
- border: "none",
3281
- margin: 2,
3282
- opacity: disabled ? 0.55 : 1,
3283
- cursor: disabled ? "not-allowed" : "pointer"
3284
- },
3285
- onClick: () => {
3286
- if (disabled) return;
3287
- setIsOpen((prev) => !prev);
3288
- setSrc("");
3289
- setAltText("");
3290
- setFileName("");
3291
- }
3292
- },
3293
- "upload-image"
3294
- ) }),
3295
- /* @__PURE__ */ jsxRuntime.jsxs(
3296
- reactComponents.PopoverSurface,
3297
- {
3298
- style: {
3299
- width: "320px",
3300
- opacity: disabled ? 0.6 : 1,
3301
- pointerEvents: disabled ? "none" : "auto"
3302
- },
3303
- children: [
3304
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 6 }, children: [
3305
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsxs(
3306
- "label",
3307
- {
3308
- style: {
3309
- cursor: disabled ? "not-allowed" : "pointer",
3310
- display: "flex",
3311
- alignItems: "center",
3312
- gap: 8,
3313
- opacity: disabled ? 0.75 : 1
3291
+ "upload-image"
3292
+ ),
3293
+ /* @__PURE__ */ jsxRuntime.jsx(
3294
+ reactComponents.Dialog,
3295
+ {
3296
+ open: isOpen,
3297
+ onOpenChange: (_, data) => {
3298
+ if (!data.open) handleClose();
3299
+ },
3300
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { style: { maxWidth: "400px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
3301
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: "Insert Image" }),
3302
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
3303
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsxs(
3304
+ "label",
3305
+ {
3306
+ style: {
3307
+ cursor: disabled ? "not-allowed" : "pointer",
3308
+ display: "flex",
3309
+ alignItems: "center",
3310
+ gap: 8,
3311
+ opacity: disabled ? 0.75 : 1
3312
+ },
3313
+ children: [
3314
+ /* @__PURE__ */ jsxRuntime.jsx(
3315
+ "input",
3316
+ {
3317
+ type: "file",
3318
+ accept: "image/*",
3319
+ style: { display: "none" },
3320
+ disabled,
3321
+ onChange: loadImage
3314
3322
  },
3315
- children: [
3316
- /* @__PURE__ */ jsxRuntime.jsx(
3317
- "input",
3318
- {
3319
- type: "file",
3320
- accept: "image/*",
3321
- style: { display: "none" },
3322
- disabled,
3323
- onChange: loadImage
3324
- },
3325
- "inline-image-upload"
3326
- ),
3327
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, children: [
3328
- /* @__PURE__ */ jsxRuntime.jsx(
3329
- reactIcons.AttachFilled,
3330
- {
3331
- style: {
3332
- fontSize: "16px",
3333
- color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3334
- marginTop: 2
3335
- }
3336
- }
3337
- ),
3338
- !fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3339
- ] }),
3340
- fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3341
- ]
3342
- }
3343
- ) }),
3344
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
3345
- reactComponents.Input,
3346
- {
3347
- placeholder: "Alt text",
3348
- appearance: "underline",
3349
- disabled,
3350
- onChange: (_, d) => setAltText(d.value),
3351
- value: altText
3352
- }
3353
- ) }),
3354
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
3355
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled: isDisabled, onClick: () => onClick({ altText, src }), children: "Add" }),
3356
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
3357
- ] })
3358
- ] }),
3359
- selectedValue === "URL" && /* @__PURE__ */ jsxRuntime.jsx(
3360
- InsertImageByURL,
3361
- {
3362
- disabled,
3363
- setIsOpen: (open) => setIsOpen(open),
3364
- onClick: (payload) => onClick(payload)
3365
- }
3366
- )
3367
- ]
3368
- }
3369
- )
3370
- ]
3371
- }
3372
- );
3323
+ "inline-image-upload"
3324
+ ),
3325
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, children: [
3326
+ /* @__PURE__ */ jsxRuntime.jsx(
3327
+ reactIcons.AttachFilled,
3328
+ {
3329
+ style: {
3330
+ fontSize: "16px",
3331
+ color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3332
+ marginTop: 2
3333
+ }
3334
+ }
3335
+ ),
3336
+ !fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3337
+ ] }),
3338
+ fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3339
+ ]
3340
+ }
3341
+ ) }),
3342
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
3343
+ reactComponents.Input,
3344
+ {
3345
+ placeholder: "Alt text",
3346
+ appearance: "underline",
3347
+ disabled,
3348
+ onChange: (_, d) => setAltText(d.value),
3349
+ value: altText
3350
+ }
3351
+ ) })
3352
+ ] }) }),
3353
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogActions, { children: [
3354
+ /* @__PURE__ */ jsxRuntime.jsx(
3355
+ reactComponents.Button,
3356
+ {
3357
+ appearance: "primary",
3358
+ size: "small",
3359
+ disabled: isAddDisabled,
3360
+ onClick: () => onClick({ altText, src }),
3361
+ children: "Add"
3362
+ }
3363
+ ),
3364
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
3365
+ ] })
3366
+ ] }) })
3367
+ }
3368
+ )
3369
+ ] });
3373
3370
  };
3374
3371
  var ImagesPlugin = ({ captionsEnabled }) => {
3375
3372
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
@@ -3535,17 +3532,28 @@ var useStyles = reactComponents.makeStyles({
3535
3532
  });
3536
3533
  var InsertInlineImageDialog = ({
3537
3534
  disabled,
3538
- activeEditor
3535
+ activeEditor,
3536
+ open: externalOpen,
3537
+ onClose
3539
3538
  }) => {
3540
3539
  const hasModifier = React9.useRef(false);
3541
3540
  const [src, setSrc] = React9.useState("");
3542
- const [isOpen, setIsOpen] = React9.useState(false);
3541
+ const [internalOpen, setInternalOpen] = React9.useState(false);
3543
3542
  const [altText, setAltText] = React9.useState("");
3544
3543
  const [fileName, setFileName] = React9.useState("");
3545
3544
  const [position, setPosition] = React9.useState("left");
3546
3545
  const styles = useStyles();
3547
3546
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
3548
- const isDisabled = disabled || src === "";
3547
+ const isControlled = externalOpen !== void 0;
3548
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
3549
+ const isAddDisabled = disabled || src === "";
3550
+ const handleClose = () => {
3551
+ setSrc("");
3552
+ setAltText("");
3553
+ setFileName("");
3554
+ if (isControlled) onClose?.();
3555
+ else setInternalOpen(false);
3556
+ };
3549
3557
  const loadImage = (event) => {
3550
3558
  if (disabled) return;
3551
3559
  const files = event.target.files;
@@ -3570,146 +3578,135 @@ var InsertInlineImageDialog = ({
3570
3578
  if (disabled) return;
3571
3579
  const payload = { altText, position, src };
3572
3580
  activeEditor.dispatchCommand(INSERT_INLINE_IMAGE_COMMAND, payload);
3573
- setIsOpen(false);
3574
- setAltText("");
3575
- setSrc("");
3576
- setFileName("");
3581
+ handleClose();
3577
3582
  };
3578
- return /* @__PURE__ */ jsxRuntime.jsxs(
3579
- reactComponents.Popover,
3580
- {
3581
- trapFocus: true,
3582
- withArrow: true,
3583
- open: disabled ? false : isOpen,
3584
- onOpenChange: (_, data) => {
3585
- if (!disabled) setIsOpen(data.open);
3583
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3584
+ !isControlled && /* @__PURE__ */ jsxRuntime.jsx(
3585
+ reactComponents.Button,
3586
+ {
3587
+ size: "small",
3588
+ title: "Add Inline Image",
3589
+ disabled,
3590
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ImageEditRegular, { style: { color: iconColor } }),
3591
+ style: {
3592
+ background: isOpen && !disabled ? "#ebebeb" : "none",
3593
+ border: "none",
3594
+ margin: 2,
3595
+ opacity: disabled ? 0.55 : 1,
3596
+ cursor: disabled ? "not-allowed" : "pointer"
3597
+ },
3598
+ onClick: () => {
3599
+ if (disabled) return;
3600
+ setSrc("");
3601
+ setAltText("");
3602
+ setFileName("");
3603
+ setInternalOpen(true);
3604
+ }
3586
3605
  },
3587
- children: [
3588
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3589
- reactComponents.Button,
3590
- {
3591
- size: "small",
3592
- title: "Add Inline Image",
3593
- disabled,
3594
- icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ImageEditRegular, { style: { color: iconColor } }),
3595
- style: {
3596
- background: isOpen && !disabled ? "#ebebeb" : "none",
3597
- border: "none",
3598
- margin: 2,
3599
- opacity: disabled ? 0.55 : 1,
3600
- cursor: disabled ? "not-allowed" : "pointer"
3601
- },
3602
- onClick: () => {
3603
- if (disabled) return;
3604
- setIsOpen((prev) => !prev);
3605
- setAltText("");
3606
- setSrc("");
3607
- setFileName("");
3608
- }
3609
- },
3610
- "upload-inline-image"
3611
- ) }),
3612
- /* @__PURE__ */ jsxRuntime.jsx(
3613
- reactComponents.PopoverSurface,
3614
- {
3615
- style: {
3616
- width: "400px",
3617
- opacity: disabled ? 0.6 : 1,
3618
- pointerEvents: disabled ? "none" : "auto"
3619
- },
3620
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 6, padding: "10px 0px 0px 0px" }, children: [
3621
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsxs(
3622
- "label",
3623
- {
3624
- style: {
3625
- cursor: disabled ? "not-allowed" : "pointer",
3626
- display: "flex",
3627
- alignItems: "center",
3628
- gap: 8,
3629
- opacity: disabled ? 0.75 : 1
3630
- },
3631
- children: [
3606
+ "upload-inline-image"
3607
+ ),
3608
+ /* @__PURE__ */ jsxRuntime.jsx(
3609
+ reactComponents.Dialog,
3610
+ {
3611
+ open: isOpen,
3612
+ onOpenChange: (_, data) => {
3613
+ if (!data.open) handleClose();
3614
+ },
3615
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { style: { maxWidth: "440px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
3616
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: "Insert Inline Image" }),
3617
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
3618
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsxs(
3619
+ "label",
3620
+ {
3621
+ style: {
3622
+ cursor: disabled ? "not-allowed" : "pointer",
3623
+ display: "flex",
3624
+ alignItems: "center",
3625
+ gap: 8,
3626
+ opacity: disabled ? 0.75 : 1
3627
+ },
3628
+ children: [
3629
+ /* @__PURE__ */ jsxRuntime.jsx(
3630
+ "input",
3631
+ {
3632
+ type: "file",
3633
+ accept: "image/*",
3634
+ style: { display: "none" },
3635
+ disabled,
3636
+ onChange: loadImage
3637
+ },
3638
+ "inline-image-upload"
3639
+ ),
3640
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, children: [
3632
3641
  /* @__PURE__ */ jsxRuntime.jsx(
3633
- "input",
3642
+ reactIcons.AttachFilled,
3634
3643
  {
3635
- type: "file",
3636
- accept: "image/*",
3637
- style: { display: "none" },
3638
- disabled,
3639
- onChange: loadImage
3640
- },
3641
- "inline-image-upload"
3642
- ),
3643
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, children: [
3644
- /* @__PURE__ */ jsxRuntime.jsx(
3645
- reactIcons.AttachFilled,
3646
- {
3647
- style: {
3648
- fontSize: "16px",
3649
- color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3650
- marginTop: 2
3651
- }
3644
+ style: {
3645
+ fontSize: "16px",
3646
+ color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3647
+ marginTop: 2
3652
3648
  }
3653
- ),
3654
- !fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3655
- ] }),
3656
- fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3657
- ]
3658
- }
3659
- ) }),
3660
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Position", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsxs(
3661
- reactComponents.Dropdown,
3662
- {
3663
- placeholder: "Left Align",
3664
- className: styles.alignDropdown,
3665
- disabled,
3666
- listbox: { style: { width: "120px" } },
3667
- root: { style: { borderBottom: "1px solid black" } },
3668
- children: [
3669
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Option, { text: "full", onClick: () => setPosition("full"), children: "Full" }, "full"),
3670
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Option, { text: "left", onClick: () => setPosition("left"), children: "Left" }, "left"),
3671
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Option, { text: "right", onClick: () => setPosition("right"), children: "Right" }, "right")
3672
- ]
3673
- }
3674
- ) }),
3675
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
3676
- reactComponents.Input,
3677
- {
3678
- placeholder: "Alt text",
3679
- appearance: "underline",
3680
- disabled,
3681
- value: altText,
3682
- onChange: (_, d) => setAltText(d.value)
3683
- }
3684
- ) }),
3685
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
3686
- /* @__PURE__ */ jsxRuntime.jsx(
3687
- reactComponents.Button,
3688
- {
3689
- size: "small",
3690
- disabled: isDisabled,
3691
- onClick: handleOnClick,
3692
- children: "Add"
3693
- },
3694
- "file-inline-upload-btn"
3695
- ),
3696
- /* @__PURE__ */ jsxRuntime.jsx(
3697
- reactComponents.Button,
3698
- {
3699
- size: "small",
3700
- disabled,
3701
- onClick: () => setIsOpen(false),
3702
- children: "Cancel"
3703
- },
3704
- "file-inline-upload-cancel"
3705
- )
3706
- ] })
3707
- ] })
3708
- }
3709
- )
3710
- ]
3711
- }
3712
- );
3649
+ }
3650
+ ),
3651
+ !fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3652
+ ] }),
3653
+ fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3654
+ ]
3655
+ }
3656
+ ) }),
3657
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Position", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsxs(
3658
+ reactComponents.Dropdown,
3659
+ {
3660
+ placeholder: "Left Align",
3661
+ className: styles.alignDropdown,
3662
+ disabled,
3663
+ listbox: { style: { width: "120px" } },
3664
+ root: { style: { borderBottom: "1px solid black" } },
3665
+ children: [
3666
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Option, { text: "full", onClick: () => setPosition("full"), children: "Full" }, "full"),
3667
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Option, { text: "left", onClick: () => setPosition("left"), children: "Left" }, "left"),
3668
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Option, { text: "right", onClick: () => setPosition("right"), children: "Right" }, "right")
3669
+ ]
3670
+ }
3671
+ ) }),
3672
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
3673
+ reactComponents.Input,
3674
+ {
3675
+ placeholder: "Alt text",
3676
+ appearance: "underline",
3677
+ disabled,
3678
+ value: altText,
3679
+ onChange: (_, d) => setAltText(d.value)
3680
+ }
3681
+ ) })
3682
+ ] }) }),
3683
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogActions, { children: [
3684
+ /* @__PURE__ */ jsxRuntime.jsx(
3685
+ reactComponents.Button,
3686
+ {
3687
+ appearance: "primary",
3688
+ size: "small",
3689
+ disabled: isAddDisabled,
3690
+ onClick: handleOnClick,
3691
+ children: "Add"
3692
+ },
3693
+ "file-inline-upload-btn"
3694
+ ),
3695
+ /* @__PURE__ */ jsxRuntime.jsx(
3696
+ reactComponents.Button,
3697
+ {
3698
+ size: "small",
3699
+ disabled,
3700
+ onClick: handleClose,
3701
+ children: "Cancel"
3702
+ },
3703
+ "file-inline-upload-cancel"
3704
+ )
3705
+ ] })
3706
+ ] }) })
3707
+ }
3708
+ )
3709
+ ] });
3713
3710
  };
3714
3711
  var InlineImagePlugin = () => {
3715
3712
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
@@ -5078,8 +5075,8 @@ function getToolbarGroupsByLevel(level) {
5078
5075
  // ['undo', 'redo', '|'],
5079
5076
  ["Bold", "Italic", "Underline", "|"],
5080
5077
  ["ColorPicker", "|"],
5081
- ["Link", "Table", "|"],
5082
- // ['Image', 'Youtube', 'InlineImage', '|'],
5078
+ ["Link", "|"],
5079
+ ["Insert", "|"],
5083
5080
  ["Heading", "|"],
5084
5081
  ["FontFamily", "|"],
5085
5082
  ["FontSize", "|"],
@@ -5093,9 +5090,8 @@ function getToolbarGroupsByLevel(level) {
5093
5090
  // ['undo', 'redo', '|'],
5094
5091
  ["Bold", "Italic", "Underline", "|"],
5095
5092
  ["ColorPicker", "|"],
5096
- ["Link", "Table", "|"],
5097
- // ['CodeBlock', '|'],
5098
- ["Image", "Youtube", "InlineImage", "|"],
5093
+ ["Link", "|"],
5094
+ ["Insert", "|"],
5099
5095
  ["Heading", "|"],
5100
5096
  ["FontFamily", "|"],
5101
5097
  ["FontSize", "|"],
@@ -5905,105 +5901,135 @@ var FontSizePlugin = ({ disabled }) => {
5905
5901
  "fontsize"
5906
5902
  ) });
5907
5903
  };
5908
- var InsertLinkPlugin = ({ disabled }) => {
5904
+ var VERBATIM_LINK_RE = /^https?:\/\/|^mailto:|^tel:|^#|^\//i;
5905
+ function getLinkValidationMessage(raw) {
5906
+ const trimmed = raw.trim();
5907
+ if (!trimmed) return void 0;
5908
+ if (/\s/.test(trimmed)) return "URL cannot contain spaces";
5909
+ if (!VERBATIM_LINK_RE.test(trimmed) && !trimmed.includes(".")) {
5910
+ return "Enter a valid URL (e.g. example.com)";
5911
+ }
5912
+ return void 0;
5913
+ }
5914
+ var InsertLinkPlugin = ({
5915
+ disabled,
5916
+ open: externalOpen,
5917
+ onClose
5918
+ }) => {
5909
5919
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
5910
- const [isOpen, setIsOpen] = React9.useState(false);
5920
+ const [internalOpen, setInternalOpen] = React9.useState(false);
5911
5921
  const [text, setText] = React9.useState("");
5912
5922
  const [link$1, setLink] = React9.useState("");
5913
5923
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
5924
+ const isControlled = externalOpen !== void 0;
5925
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
5926
+ const linkError = getLinkValidationMessage(link$1);
5927
+ const handleClose = () => {
5928
+ setText("");
5929
+ setLink("");
5930
+ if (isControlled) onClose?.();
5931
+ else setInternalOpen(false);
5932
+ };
5914
5933
  const insertLink = (text2, link2) => {
5915
5934
  if (disabled) return;
5935
+ if (getLinkValidationMessage(link2)) return;
5936
+ const trimmedLink = link2.trim();
5937
+ const href = VERBATIM_LINK_RE.test(trimmedLink) ? trimmedLink : `https://${trimmedLink}`;
5916
5938
  editor.update(() => {
5917
- setText("");
5918
- setLink("");
5919
5939
  const selection = lexical.$getSelection();
5920
5940
  if (lexical.$isRangeSelection(selection)) {
5921
5941
  const textNode = new lexical.TextNode(text2);
5922
- const linkNode = link.$createLinkNode(link2.startsWith("http") ? link2 : `https://${link2}`);
5942
+ const linkNode = link.$createLinkNode(href);
5923
5943
  linkNode.append(textNode);
5924
5944
  selection.insertNodes([linkNode]);
5925
5945
  }
5926
- setIsOpen(false);
5927
5946
  });
5947
+ handleClose();
5928
5948
  };
5929
- return /* @__PURE__ */ jsxRuntime.jsxs(
5930
- reactComponents.Popover,
5931
- {
5932
- trapFocus: true,
5933
- withArrow: true,
5934
- open: disabled ? false : isOpen,
5935
- onOpenChange: (_, data) => {
5936
- if (!disabled) setIsOpen(data.open);
5949
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5950
+ !isControlled && /* @__PURE__ */ jsxRuntime.jsx(
5951
+ reactComponents.Button,
5952
+ {
5953
+ size: "small",
5954
+ title: "Add link",
5955
+ disabled,
5956
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.LinkAddRegular, { style: { color: iconColor } }),
5957
+ style: {
5958
+ background: isOpen && !disabled ? "#ebebeb" : "none",
5959
+ border: "none",
5960
+ margin: 2,
5961
+ opacity: disabled ? 0.55 : 1,
5962
+ cursor: disabled ? "not-allowed" : "pointer"
5963
+ },
5964
+ onClick: () => {
5965
+ if (disabled) return;
5966
+ setInternalOpen((prev) => !prev);
5967
+ }
5937
5968
  },
5938
- children: [
5939
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(
5940
- reactComponents.Button,
5941
- {
5942
- size: "small",
5943
- title: "Add link",
5944
- disabled,
5945
- icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.LinkAddRegular, { style: { color: iconColor } }),
5946
- style: {
5947
- background: isOpen && !disabled ? "#ebebeb" : "none",
5948
- border: "none",
5949
- margin: 2,
5950
- opacity: disabled ? 0.55 : 1,
5951
- cursor: disabled ? "not-allowed" : "pointer"
5952
- },
5953
- onClick: () => {
5954
- if (!disabled) setIsOpen((prev) => !prev);
5955
- }
5956
- },
5957
- "upload-link"
5958
- ) }),
5959
- /* @__PURE__ */ jsxRuntime.jsx(
5960
- reactComponents.PopoverSurface,
5961
- {
5962
- style: {
5963
- width: "270px",
5964
- opacity: disabled ? 0.6 : 1,
5965
- pointerEvents: disabled ? "none" : "auto"
5966
- },
5967
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, children: [
5968
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
5969
- reactComponents.Input,
5970
- {
5971
- autoFocus: !disabled,
5972
- value: text,
5973
- appearance: "underline",
5974
- placeholder: "Text",
5975
- disabled,
5976
- onChange: (_, v) => setText(v.value)
5977
- }
5978
- ) }),
5979
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Link", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
5980
- reactComponents.Input,
5981
- {
5982
- value: link$1,
5983
- appearance: "underline",
5984
- placeholder: "Link",
5985
- disabled,
5986
- onChange: (_, v) => setLink(v.value)
5987
- }
5988
- ) }),
5989
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
5990
- /* @__PURE__ */ jsxRuntime.jsx(
5991
- reactComponents.Button,
5969
+ "upload-link"
5970
+ ),
5971
+ /* @__PURE__ */ jsxRuntime.jsx(
5972
+ reactComponents.Dialog,
5973
+ {
5974
+ open: isOpen,
5975
+ onOpenChange: (_, data) => {
5976
+ if (!data.open) handleClose();
5977
+ },
5978
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { style: { maxWidth: "380px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
5979
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: "Insert Link" }),
5980
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
5981
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
5982
+ reactComponents.Input,
5983
+ {
5984
+ autoFocus: !disabled,
5985
+ value: text,
5986
+ appearance: "underline",
5987
+ placeholder: "Text",
5988
+ disabled,
5989
+ onChange: (_, v) => setText(v.value)
5990
+ }
5991
+ ) }),
5992
+ /* @__PURE__ */ jsxRuntime.jsx(
5993
+ reactComponents.Field,
5994
+ {
5995
+ label: "Link",
5996
+ orientation: "horizontal",
5997
+ size: "small",
5998
+ validationState: linkError ? "error" : "none",
5999
+ validationMessage: linkError,
6000
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6001
+ reactComponents.Input,
5992
6002
  {
5993
- size: "small",
5994
- disabled: disabled || !text || !link$1,
5995
- onClick: () => insertLink(text, link$1),
5996
- children: "Add"
6003
+ value: link$1,
6004
+ appearance: "underline",
6005
+ placeholder: "Link",
6006
+ disabled,
6007
+ onChange: (_, v) => setLink(v.value),
6008
+ onKeyDown: (e) => {
6009
+ if (e.key === "Enter" && text && link$1 && !linkError) insertLink(text, link$1);
6010
+ }
5997
6011
  }
5998
- ),
5999
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
6000
- ] })
6001
- ] })
6002
- }
6003
- )
6004
- ]
6005
- }
6006
- );
6012
+ )
6013
+ }
6014
+ )
6015
+ ] }) }),
6016
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogActions, { children: [
6017
+ /* @__PURE__ */ jsxRuntime.jsx(
6018
+ reactComponents.Button,
6019
+ {
6020
+ appearance: "primary",
6021
+ size: "small",
6022
+ disabled: disabled || !text || !link$1 || !!linkError,
6023
+ onClick: () => insertLink(text, link$1),
6024
+ children: "Add"
6025
+ }
6026
+ ),
6027
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
6028
+ ] })
6029
+ ] }) })
6030
+ }
6031
+ )
6032
+ ] });
6007
6033
  };
6008
6034
  function PageSetupPlugin({ disabled, value, onChange }) {
6009
6035
  const sizeLabel = value.size === "pageless" ? "Pageless" : PAGE_SIZE_OPTIONS.find((o) => o.key === value.size)?.label ?? "Pageless";
@@ -6059,194 +6085,280 @@ function PageSetupPlugin({ disabled, value, onChange }) {
6059
6085
  }
6060
6086
  );
6061
6087
  }
6062
- var TableItemPlugin = ({ disabled }) => {
6088
+ var MAX_ROWS = 50;
6089
+ var MAX_COLS = 50;
6090
+ var TableItemPlugin = ({
6091
+ disabled,
6092
+ open: externalOpen,
6093
+ onClose
6094
+ }) => {
6063
6095
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
6064
6096
  const [columns, setColumns] = React9.useState("");
6065
6097
  const [rows, setRows] = React9.useState("");
6066
- const [isOpen, setIsOpen] = React9.useState(false);
6098
+ const [internalOpen, setInternalOpen] = React9.useState(false);
6099
+ const [rowError, setRowError] = React9.useState("");
6100
+ const [colError, setColError] = React9.useState("");
6101
+ const isControlled = externalOpen !== void 0;
6102
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
6067
6103
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
6104
+ const handleClose = () => {
6105
+ setRows("");
6106
+ setColumns("");
6107
+ setRowError("");
6108
+ setColError("");
6109
+ if (isControlled) onClose?.();
6110
+ else setInternalOpen(false);
6111
+ };
6112
+ const onRowsChange = (val) => {
6113
+ const clean = val.replace(/\D/g, "");
6114
+ setRows(clean);
6115
+ const n = Number(clean);
6116
+ if (clean && n > MAX_ROWS) setRowError(`Maximum ${MAX_ROWS} rows allowed`);
6117
+ else setRowError("");
6118
+ };
6119
+ const onColsChange = (val) => {
6120
+ const clean = val.replace(/\D/g, "");
6121
+ setColumns(clean);
6122
+ const n = Number(clean);
6123
+ if (clean && n > MAX_COLS) setColError(`Maximum ${MAX_COLS} columns allowed`);
6124
+ else setColError("");
6125
+ };
6068
6126
  const onAddTable = () => {
6069
6127
  if (disabled) return;
6070
6128
  const row = Number(rows);
6071
6129
  const col = Number(columns);
6072
6130
  if (!row || !col) return;
6131
+ if (row > MAX_ROWS || col > MAX_COLS) return;
6073
6132
  editor.update(() => {
6074
6133
  const tableNode = table.$createTableNodeWithDimensions(row, col, true);
6075
6134
  utils.$insertNodeToNearestRoot(tableNode);
6076
6135
  });
6077
- setRows("");
6078
- setColumns("");
6079
- setIsOpen(false);
6136
+ handleClose();
6080
6137
  };
6081
- return /* @__PURE__ */ jsxRuntime.jsxs(
6082
- reactComponents.Popover,
6083
- {
6084
- trapFocus: true,
6085
- withArrow: true,
6086
- open: disabled ? false : isOpen,
6087
- onOpenChange: (_, data) => {
6088
- if (!disabled) setIsOpen(data.open);
6138
+ const isAddDisabled = disabled || !rows || !columns || !!rowError || !!colError;
6139
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6140
+ !isControlled && /* @__PURE__ */ jsxRuntime.jsx(
6141
+ reactComponents.Button,
6142
+ {
6143
+ size: "small",
6144
+ title: "Add table",
6145
+ disabled,
6146
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.TableAddRegular, { style: { color: iconColor } }),
6147
+ style: {
6148
+ background: isOpen && !disabled ? "#ebebeb" : "none",
6149
+ border: "none",
6150
+ margin: 2,
6151
+ opacity: disabled ? 0.55 : 1,
6152
+ cursor: disabled ? "not-allowed" : "pointer"
6153
+ },
6154
+ onClick: () => {
6155
+ if (disabled) return;
6156
+ setRows("");
6157
+ setColumns("");
6158
+ setRowError("");
6159
+ setColError("");
6160
+ setInternalOpen(true);
6161
+ }
6089
6162
  },
6090
- children: [
6091
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6092
- reactComponents.Button,
6093
- {
6094
- size: "small",
6095
- title: "Add table",
6096
- disabled,
6097
- icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.TableAddRegular, { style: { color: iconColor } }),
6098
- style: {
6099
- background: isOpen && !disabled ? "#ebebeb" : "none",
6100
- border: "none",
6101
- margin: 2,
6102
- opacity: disabled ? 0.55 : 1,
6103
- cursor: disabled ? "not-allowed" : "pointer"
6104
- },
6105
- onClick: () => {
6106
- if (disabled) return;
6107
- setIsOpen((prev) => !prev);
6108
- setRows("");
6109
- setColumns("");
6110
- }
6111
- },
6112
- "insert-table-nodes"
6113
- ) }),
6114
- /* @__PURE__ */ jsxRuntime.jsx(
6115
- reactComponents.PopoverSurface,
6116
- {
6117
- style: {
6118
- width: "270px",
6119
- opacity: disabled ? 0.6 : 1,
6120
- pointerEvents: disabled ? "none" : "auto"
6121
- },
6122
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, children: [
6123
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Rows", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
6124
- reactComponents.Input,
6125
- {
6126
- autoFocus: !disabled,
6127
- type: "number",
6128
- min: 1,
6129
- value: rows,
6130
- placeholder: "Rows",
6131
- appearance: "underline",
6132
- disabled,
6133
- input: { style: { textAlign: "left" } },
6134
- onChange: (_, v) => setRows(v.value.replace(/\D/g, ""))
6135
- }
6136
- ) }),
6137
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "Columns", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
6138
- reactComponents.Input,
6139
- {
6140
- type: "number",
6141
- min: 1,
6142
- value: columns,
6143
- placeholder: "Columns",
6144
- appearance: "underline",
6145
- disabled,
6146
- input: { style: { textAlign: "left" } },
6147
- onChange: (_, v) => setColumns(v.value.replace(/\D/g, ""))
6148
- }
6149
- ) }),
6150
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
6151
- /* @__PURE__ */ jsxRuntime.jsx(
6152
- reactComponents.Button,
6163
+ "insert-table-nodes"
6164
+ ),
6165
+ /* @__PURE__ */ jsxRuntime.jsx(
6166
+ reactComponents.Dialog,
6167
+ {
6168
+ open: isOpen,
6169
+ onOpenChange: (_, data) => {
6170
+ if (!data.open) handleClose();
6171
+ },
6172
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { style: { maxWidth: "380px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
6173
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: "Insert Table" }),
6174
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
6175
+ /* @__PURE__ */ jsxRuntime.jsx(
6176
+ reactComponents.Field,
6177
+ {
6178
+ label: "Rows",
6179
+ orientation: "horizontal",
6180
+ size: "small",
6181
+ validationMessage: rowError || void 0,
6182
+ validationState: rowError ? "error" : "none",
6183
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6184
+ reactComponents.Input,
6153
6185
  {
6154
- size: "small",
6155
- appearance: "primary",
6156
- disabled: disabled || !rows || !columns,
6157
- onClick: onAddTable,
6158
- children: "Add"
6186
+ autoFocus: !disabled,
6187
+ type: "number",
6188
+ min: 1,
6189
+ max: MAX_ROWS,
6190
+ value: rows,
6191
+ placeholder: "Rows",
6192
+ appearance: "underline",
6193
+ disabled,
6194
+ input: { style: { textAlign: "left" } },
6195
+ onChange: (_, v) => onRowsChange(v.value)
6159
6196
  }
6160
- ),
6161
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
6162
- ] })
6163
- ] })
6164
- }
6165
- )
6166
- ]
6167
- }
6168
- );
6197
+ )
6198
+ }
6199
+ ),
6200
+ /* @__PURE__ */ jsxRuntime.jsx(
6201
+ reactComponents.Field,
6202
+ {
6203
+ label: "Columns",
6204
+ orientation: "horizontal",
6205
+ size: "small",
6206
+ validationMessage: colError || void 0,
6207
+ validationState: colError ? "error" : "none",
6208
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6209
+ reactComponents.Input,
6210
+ {
6211
+ type: "number",
6212
+ min: 1,
6213
+ max: MAX_COLS,
6214
+ value: columns,
6215
+ placeholder: "Columns",
6216
+ appearance: "underline",
6217
+ disabled,
6218
+ input: { style: { textAlign: "left" } },
6219
+ onChange: (_, v) => onColsChange(v.value)
6220
+ }
6221
+ )
6222
+ }
6223
+ )
6224
+ ] }) }),
6225
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogActions, { children: [
6226
+ /* @__PURE__ */ jsxRuntime.jsx(
6227
+ reactComponents.Button,
6228
+ {
6229
+ appearance: "primary",
6230
+ size: "small",
6231
+ disabled: isAddDisabled,
6232
+ onClick: onAddTable,
6233
+ children: "Add"
6234
+ }
6235
+ ),
6236
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
6237
+ ] })
6238
+ ] }) })
6239
+ }
6240
+ )
6241
+ ] });
6169
6242
  };
6170
- var YoutubeUploadPlugin = ({ disabled }) => {
6243
+ function extractYouTubeId(url) {
6244
+ const trimmed = url.trim();
6245
+ if (/^[\w-]{11}$/.test(trimmed)) return trimmed;
6246
+ const match = /(?:youtu\.be\/|youtube\.com\/(?:watch\?v=|embed\/|v\/|shorts\/|live\/|u\/\w\/))([^#&?]{11})/.exec(trimmed);
6247
+ return match ? match[1] : null;
6248
+ }
6249
+ var YoutubeUploadPlugin = ({
6250
+ disabled,
6251
+ open: externalOpen,
6252
+ onClose
6253
+ }) => {
6171
6254
  const [url, setURL] = React9.useState("");
6172
- const [isOpen, setIsOpen] = React9.useState(false);
6255
+ const [urlError, setUrlError] = React9.useState("");
6256
+ const [internalOpen, setInternalOpen] = React9.useState(false);
6173
6257
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
6174
6258
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#424242";
6259
+ const isControlled = externalOpen !== void 0;
6260
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
6261
+ const handleClose = () => {
6262
+ setURL("");
6263
+ setUrlError("");
6264
+ if (isControlled) onClose?.();
6265
+ else setInternalOpen(false);
6266
+ };
6175
6267
  const onHandleEmbeded = () => {
6176
6268
  if (disabled) return;
6177
6269
  if (!url) return;
6178
- const match = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/.exec(url);
6179
- const id = match && match[2]?.length === 11 ? match[2] : null;
6180
- if (!id) return;
6270
+ const id = extractYouTubeId(url);
6271
+ if (!id) {
6272
+ setUrlError("Invalid YouTube URL. Supported: watch?v=, youtu.be/, /shorts/, /live/");
6273
+ return;
6274
+ }
6275
+ setUrlError("");
6181
6276
  editor.update(() => {
6182
6277
  const node = $createYouTubeNode(id);
6183
6278
  lexical.$insertNodes([node]);
6184
6279
  });
6185
- setURL("");
6186
- setIsOpen(false);
6280
+ handleClose();
6187
6281
  };
6188
- return /* @__PURE__ */ jsxRuntime.jsxs(
6189
- reactComponents.Popover,
6190
- {
6191
- trapFocus: true,
6192
- withArrow: true,
6193
- open: disabled ? false : isOpen,
6194
- onOpenChange: (_, data) => {
6195
- if (!disabled) setIsOpen(data.open);
6282
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6283
+ !isControlled && /* @__PURE__ */ jsxRuntime.jsx(
6284
+ reactComponents.Button,
6285
+ {
6286
+ title: "Add youtube URL",
6287
+ size: "small",
6288
+ disabled,
6289
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.VideoClipRegular, { style: { color: iconColor } }),
6290
+ style: {
6291
+ background: isOpen && !disabled ? "#ebebeb" : "none",
6292
+ border: "none",
6293
+ margin: 2,
6294
+ opacity: disabled ? 0.55 : 1,
6295
+ cursor: disabled ? "not-allowed" : "pointer"
6296
+ },
6297
+ onClick: () => {
6298
+ if (disabled) return;
6299
+ setURL("");
6300
+ setUrlError("");
6301
+ setInternalOpen(true);
6302
+ }
6196
6303
  },
6197
- children: [
6198
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6199
- reactComponents.Button,
6200
- {
6201
- title: "Add youtube URL",
6202
- size: "small",
6203
- disabled,
6204
- icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.VideoClipRegular, { style: { color: iconColor } }),
6205
- style: {
6206
- background: isOpen && !disabled ? "#ebebeb" : "none",
6207
- border: "none",
6208
- margin: 2,
6209
- opacity: disabled ? 0.55 : 1,
6210
- cursor: disabled ? "not-allowed" : "pointer"
6211
- },
6212
- onClick: () => {
6213
- if (disabled) return;
6214
- setIsOpen((prev) => !prev);
6215
- setURL("");
6216
- }
6217
- },
6218
- "upload-video"
6219
- ) }),
6220
- /* @__PURE__ */ jsxRuntime.jsx(
6221
- reactComponents.PopoverSurface,
6222
- {
6223
- style: {
6224
- width: "270px",
6225
- opacity: disabled ? 0.6 : 1,
6226
- pointerEvents: disabled ? "none" : "auto"
6227
- },
6228
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, children: [
6229
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: "URL", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(
6230
- reactComponents.Input,
6231
- {
6232
- autoFocus: !disabled,
6233
- disabled,
6234
- value: url,
6235
- appearance: "underline",
6236
- placeholder: "Add Youtube video URL",
6237
- onChange: (_, v) => setURL(v.value)
6238
- }
6239
- ) }),
6240
- /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
6241
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled: disabled || !url, onClick: onHandleEmbeded, children: "Add" }),
6242
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
6243
- ] })
6244
- ] })
6245
- }
6246
- )
6247
- ]
6248
- }
6249
- );
6304
+ "upload-video"
6305
+ ),
6306
+ /* @__PURE__ */ jsxRuntime.jsx(
6307
+ reactComponents.Dialog,
6308
+ {
6309
+ open: isOpen,
6310
+ onOpenChange: (_, data) => {
6311
+ if (!data.open) handleClose();
6312
+ },
6313
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { style: { maxWidth: "420px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
6314
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: "Insert YouTube Video" }),
6315
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
6316
+ /* @__PURE__ */ jsxRuntime.jsx(
6317
+ reactComponents.Field,
6318
+ {
6319
+ label: "URL",
6320
+ orientation: "horizontal",
6321
+ size: "small",
6322
+ validationState: urlError ? "error" : "none",
6323
+ validationMessage: urlError || void 0,
6324
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6325
+ reactComponents.Input,
6326
+ {
6327
+ autoFocus: !disabled,
6328
+ disabled,
6329
+ value: url,
6330
+ appearance: "underline",
6331
+ placeholder: "Paste YouTube URL or video ID\u2026",
6332
+ onChange: (_, v) => {
6333
+ setURL(v.value);
6334
+ if (urlError) setUrlError("");
6335
+ },
6336
+ onKeyDown: (e) => {
6337
+ if (e.key === "Enter") onHandleEmbeded();
6338
+ }
6339
+ }
6340
+ )
6341
+ }
6342
+ ),
6343
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "#94a3b8", lineHeight: 1.5 }, children: "Supports: youtube.com/watch?v=\u2026, youtu.be/\u2026, /shorts/\u2026, /live/\u2026" })
6344
+ ] }) }),
6345
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogActions, { children: [
6346
+ /* @__PURE__ */ jsxRuntime.jsx(
6347
+ reactComponents.Button,
6348
+ {
6349
+ appearance: "primary",
6350
+ size: "small",
6351
+ disabled: disabled || !url,
6352
+ onClick: onHandleEmbeded,
6353
+ children: "Add"
6354
+ }
6355
+ ),
6356
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
6357
+ ] })
6358
+ ] }) })
6359
+ }
6360
+ )
6361
+ ] });
6250
6362
  };
6251
6363
  var useStyles4 = reactComponents.makeStyles({
6252
6364
  dropdown: {
@@ -6271,6 +6383,7 @@ var ALLOWED_TOKENS = {
6271
6383
  Image: true,
6272
6384
  InlineImage: true,
6273
6385
  Youtube: true,
6386
+ Insert: true,
6274
6387
  Heading: true,
6275
6388
  FontFamily: true,
6276
6389
  FontSize: true,
@@ -6302,6 +6415,7 @@ var ToolBarPlugins = (props) => {
6302
6415
  const [isLowercase, setIsLowercase] = React9.useState(false);
6303
6416
  const [isCapitalize, setIsCapitalize] = React9.useState(false);
6304
6417
  const [alignment, setAlignment] = React9.useState("left");
6418
+ const [activeInsertDialog, setActiveInsertDialog] = React9.useState(null);
6305
6419
  const lastSelectionRef = React9__namespace.default.useRef(null);
6306
6420
  const presetGroups = getToolbarGroupsByLevel(props.level);
6307
6421
  const pluginGroups = React9.useMemo(() => sanitizePluginGroups(presetGroups), [presetGroups]);
@@ -6547,6 +6661,7 @@ var ToolBarPlugins = (props) => {
6547
6661
  marginRight: 8,
6548
6662
  verticalAlign: "middle"
6549
6663
  };
6664
+ const isDisabled = !isEditable || !!props.readOnly;
6550
6665
  switch (token) {
6551
6666
  case "Bold":
6552
6667
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -6610,6 +6725,95 @@ var ToolBarPlugins = (props) => {
6610
6725
  );
6611
6726
  case "Youtube":
6612
6727
  return /* @__PURE__ */ jsxRuntime.jsx(YoutubeUploadPlugin, { disabled: !isEditable || props.readOnly }, key);
6728
+ case "Insert": {
6729
+ const menuIconColor = isDisabled ? fgDisabled : fg;
6730
+ return /* @__PURE__ */ jsxRuntime.jsxs(React9__namespace.default.Fragment, { children: [
6731
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.Menu, { children: [
6732
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6733
+ reactComponents.Button,
6734
+ {
6735
+ size: "small",
6736
+ disabled: isDisabled,
6737
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.AddRegular, { style: { color: menuIconColor } }),
6738
+ style: {
6739
+ ...getButtonStyle(false),
6740
+ gap: 4,
6741
+ paddingInline: 8
6742
+ },
6743
+ children: "Insert"
6744
+ }
6745
+ ) }),
6746
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuPopover, { children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.MenuList, { children: [
6747
+ /* @__PURE__ */ jsxRuntime.jsx(
6748
+ reactComponents.MenuItem,
6749
+ {
6750
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.TableAddRegular, { style: { color: menuIconColor } }),
6751
+ onClick: () => !isDisabled && setActiveInsertDialog("table"),
6752
+ children: "Table"
6753
+ }
6754
+ ),
6755
+ /* @__PURE__ */ jsxRuntime.jsx(
6756
+ reactComponents.MenuItem,
6757
+ {
6758
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ImageAddRegular, { style: { color: menuIconColor } }),
6759
+ onClick: () => !isDisabled && setActiveInsertDialog("image"),
6760
+ children: "Image"
6761
+ }
6762
+ ),
6763
+ /* @__PURE__ */ jsxRuntime.jsx(
6764
+ reactComponents.MenuItem,
6765
+ {
6766
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ImageEditRegular, { style: { color: menuIconColor } }),
6767
+ onClick: () => !isDisabled && setActiveInsertDialog("inlineImage"),
6768
+ children: "Inline Image"
6769
+ }
6770
+ ),
6771
+ /* @__PURE__ */ jsxRuntime.jsx(
6772
+ reactComponents.MenuItem,
6773
+ {
6774
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.VideoClipRegular, { style: { color: menuIconColor } }),
6775
+ onClick: () => !isDisabled && setActiveInsertDialog("youtube"),
6776
+ children: "YouTube"
6777
+ }
6778
+ )
6779
+ ] }) })
6780
+ ] }),
6781
+ /* @__PURE__ */ jsxRuntime.jsx(
6782
+ TableItemPlugin,
6783
+ {
6784
+ disabled: isDisabled,
6785
+ open: activeInsertDialog === "table",
6786
+ onClose: () => setActiveInsertDialog(null)
6787
+ }
6788
+ ),
6789
+ /* @__PURE__ */ jsxRuntime.jsx(
6790
+ InsertImageDialog,
6791
+ {
6792
+ activeEditor: editor,
6793
+ disabled: isDisabled,
6794
+ open: activeInsertDialog === "image",
6795
+ onClose: () => setActiveInsertDialog(null)
6796
+ }
6797
+ ),
6798
+ /* @__PURE__ */ jsxRuntime.jsx(
6799
+ InsertInlineImageDialog,
6800
+ {
6801
+ activeEditor: editor,
6802
+ disabled: isDisabled,
6803
+ open: activeInsertDialog === "inlineImage",
6804
+ onClose: () => setActiveInsertDialog(null)
6805
+ }
6806
+ ),
6807
+ /* @__PURE__ */ jsxRuntime.jsx(
6808
+ YoutubeUploadPlugin,
6809
+ {
6810
+ disabled: isDisabled,
6811
+ open: activeInsertDialog === "youtube",
6812
+ onClose: () => setActiveInsertDialog(null)
6813
+ }
6814
+ )
6815
+ ] }, key);
6816
+ }
6613
6817
  case "Heading": {
6614
6818
  const headingLabel = selectNodeType === "paragraph" ? "Normal" : HEADING_OPTION.find((h) => h.key === selectNodeType)?.text ?? selectNodeType;
6615
6819
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -7005,7 +7209,9 @@ function BrowserSpellCheckPlugin({ enabled }) {
7005
7209
  }, [editor, enabled]);
7006
7210
  return null;
7007
7211
  }
7008
- function WordCountPlugin({ onCountChange }) {
7212
+ function WordCountPlugin({
7213
+ onCountChange
7214
+ }) {
7009
7215
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
7010
7216
  React9.useEffect(() => {
7011
7217
  return editor.registerUpdateListener(({ editorState }) => {
@@ -7018,7 +7224,9 @@ function WordCountPlugin({ onCountChange }) {
7018
7224
  }, [editor, onCountChange]);
7019
7225
  return null;
7020
7226
  }
7021
- function CharCountPlugin({ onCountChange }) {
7227
+ function CharCountPlugin({
7228
+ onCountChange
7229
+ }) {
7022
7230
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
7023
7231
  React9.useEffect(() => {
7024
7232
  return editor.registerUpdateListener(({ editorState }) => {
@@ -7102,7 +7310,10 @@ function _adaptRawSpell(data, text) {
7102
7310
  }
7103
7311
  const rawGrammar = data.grammar_correction ?? data.improved_text;
7104
7312
  const grammarCorrection = rawGrammar && rawGrammar.trim() !== text.trim() ? rawGrammar.trim() : void 0;
7105
- return { issues: issues.sort((a, b) => a.offset - b.offset), grammarCorrection };
7313
+ return {
7314
+ issues: issues.sort((a, b) => a.offset - b.offset),
7315
+ grammarCorrection
7316
+ };
7106
7317
  }
7107
7318
  function _adaptRawSuggest(data) {
7108
7319
  if (!data) return null;
@@ -7157,359 +7368,385 @@ function _makeQueryFn(fn) {
7157
7368
  };
7158
7369
  };
7159
7370
  }
7160
- var ContentEditorComponent = React9.forwardRef(
7161
- (props, ref) => {
7162
- const isReadOnly = !!props.readOnly;
7163
- const resolvedSpellCheck = React9__namespace.default.useMemo(
7164
- () => props.spellCheckFn ? _makeSpellCheckFn(props.spellCheckFn) : props.useSpellCheck,
7165
- // eslint-disable-next-line react-hooks/exhaustive-deps
7166
- [props.spellCheckFn, props.useSpellCheck]
7167
- );
7168
- const resolvedQuery = React9__namespace.default.useMemo(
7169
- () => props.suggestFn ? _makeQueryFn(props.suggestFn) : props.useQuery,
7170
- // eslint-disable-next-line react-hooks/exhaustive-deps
7171
- [props.suggestFn, props.useQuery]
7172
- );
7173
- const [floatingAnchorElem, setFloatingAnchorElem] = React9.useState(null);
7174
- const [isLinkEditMode, setIsLinkEditMode] = React9.useState(false);
7175
- const [wordCount, setWordCount] = React9.useState(0);
7176
- const handleWordCount = React9.useCallback((count) => setWordCount(count), []);
7177
- const [charCount, setCharCount] = React9.useState(0);
7178
- const handleCharCount = React9.useCallback((count) => setCharCount(count), []);
7179
- const [refErrors, setRefErrors] = React9.useState([]);
7180
- const [pageSetup, setPageSetup] = React9.useState(DEFAULT_PAGE_SETUP);
7181
- const pageCanvas = resolvePageCanvasMetrics(pageSetup);
7182
- const contentEditableDomRef = React9.useRef(null);
7183
- const previousOverLimitRef = React9.useRef(false);
7184
- const focusedRef = React9.useRef(false);
7185
- const setFocused = (focused) => {
7186
- focusedRef.current = focused;
7187
- };
7188
- const containerRef = React9.useRef(null);
7189
- const onAnchorRef = (elem) => {
7190
- if (elem) setFloatingAnchorElem(elem);
7191
- };
7192
- const initialConfig = {
7193
- namespace: props.namespace,
7194
- theme,
7195
- onError: () => {
7196
- },
7197
- nodes: [
7198
- richText.HeadingNode,
7199
- richText.QuoteNode,
7200
- code.CodeHighlightNode,
7201
- code.CodeNode,
7202
- list.ListNode,
7203
- list.ListItemNode,
7204
- link.LinkNode,
7205
- link.AutoLinkNode,
7206
- table.TableNode,
7207
- table.TableRowNode,
7208
- table.TableCellNode,
7209
- ImageNode,
7210
- InlineImageNode,
7211
- YouTubeNode,
7212
- PageBreakNode,
7213
- AutocompleteNode,
7214
- SpellErrorNode,
7215
- HtmlBlockNode
7216
- ]
7217
- };
7218
- const EditorStyles = react.mergeStyleSets({
7219
- editorPlaceholder: {
7220
- color: "var(--colorNeutralForeground3, grey)",
7221
- position: "absolute",
7222
- top: props.level !== "none" /* None */ ? "17px" : "27px",
7223
- left: pageCanvas.paddingPx,
7224
- right: pageCanvas.paddingPx,
7225
- fontSize: "14px",
7226
- pointerEvents: "none",
7227
- userSelect: "none"
7228
- },
7229
- contentEditor: {
7230
- zIndex: 0,
7231
- flex: "auto",
7232
- outline: "none",
7233
- overflow: "auto",
7234
- marginTop: "0px",
7235
- position: "relative",
7236
- background: "var(--colorNeutralBackground1, #ffffff)",
7237
- justifyContent: "center",
7238
- height: props.contentHeight ?? "100%",
7239
- ...isReadOnly && {
7240
- cursor: "not-allowed",
7241
- opacity: 0.75,
7242
- userSelect: "text"
7243
- }
7244
- }
7245
- });
7246
- const urlRegExp = new RegExp(
7247
- /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/
7248
- );
7249
- const validateUrl = (url) => url === "https://" || urlRegExp.test(url);
7250
- const handleReadOnlyClickCapture = (e) => {
7251
- if (!isReadOnly) return;
7252
- const target = e.target;
7253
- const anchor = target?.closest?.("a");
7254
- if (anchor) {
7255
- e.preventDefault();
7256
- e.stopPropagation();
7371
+ var ContentEditorComponent = React9.forwardRef((props, ref) => {
7372
+ const isReadOnly = !!props.readOnly;
7373
+ const resolvedSpellCheck = React9__namespace.default.useMemo(
7374
+ () => props.spellCheckFn ? _makeSpellCheckFn(props.spellCheckFn) : props.useSpellCheck,
7375
+ // eslint-disable-next-line react-hooks/exhaustive-deps
7376
+ [props.spellCheckFn, props.useSpellCheck]
7377
+ );
7378
+ const resolvedQuery = React9__namespace.default.useMemo(
7379
+ () => props.suggestFn ? _makeQueryFn(props.suggestFn) : props.useQuery,
7380
+ // eslint-disable-next-line react-hooks/exhaustive-deps
7381
+ [props.suggestFn, props.useQuery]
7382
+ );
7383
+ const [floatingAnchorElem, setFloatingAnchorElem] = React9.useState(null);
7384
+ const [isLinkEditMode, setIsLinkEditMode] = React9.useState(false);
7385
+ const [wordCount, setWordCount] = React9.useState(0);
7386
+ const handleWordCount = React9.useCallback(
7387
+ (count) => setWordCount(count),
7388
+ []
7389
+ );
7390
+ const [charCount, setCharCount] = React9.useState(0);
7391
+ const handleCharCount = React9.useCallback(
7392
+ (count) => setCharCount(count),
7393
+ []
7394
+ );
7395
+ const [refErrors, setRefErrors] = React9.useState([]);
7396
+ const [pageSetup, setPageSetup] = React9.useState(DEFAULT_PAGE_SETUP);
7397
+ const pageCanvas = resolvePageCanvasMetrics(pageSetup);
7398
+ const contentEditableDomRef = React9.useRef(null);
7399
+ const previousOverLimitRef = React9.useRef(false);
7400
+ const focusedRef = React9.useRef(false);
7401
+ const setFocused = (focused) => {
7402
+ focusedRef.current = focused;
7403
+ };
7404
+ const containerRef = React9.useRef(null);
7405
+ const onAnchorRef = (elem) => {
7406
+ if (elem) setFloatingAnchorElem(elem);
7407
+ };
7408
+ const initialConfig = {
7409
+ namespace: props.namespace,
7410
+ theme,
7411
+ onError: () => {
7412
+ },
7413
+ nodes: [
7414
+ richText.HeadingNode,
7415
+ richText.QuoteNode,
7416
+ code.CodeHighlightNode,
7417
+ code.CodeNode,
7418
+ list.ListNode,
7419
+ list.ListItemNode,
7420
+ link.LinkNode,
7421
+ link.AutoLinkNode,
7422
+ table.TableNode,
7423
+ table.TableRowNode,
7424
+ table.TableCellNode,
7425
+ ImageNode,
7426
+ InlineImageNode,
7427
+ YouTubeNode,
7428
+ PageBreakNode,
7429
+ AutocompleteNode,
7430
+ SpellErrorNode,
7431
+ HtmlBlockNode
7432
+ ]
7433
+ };
7434
+ const EditorStyles = react.mergeStyleSets({
7435
+ editorPlaceholder: {
7436
+ color: "var(--colorNeutralForeground3, grey)",
7437
+ position: "absolute",
7438
+ top: props.level !== "none" /* None */ ? "17px" : "27px",
7439
+ left: pageCanvas.paddingPx,
7440
+ right: pageCanvas.paddingPx,
7441
+ fontSize: "14px",
7442
+ pointerEvents: "none",
7443
+ userSelect: "none"
7444
+ },
7445
+ contentEditor: {
7446
+ zIndex: 0,
7447
+ flex: "auto",
7448
+ outline: "none",
7449
+ overflow: "auto",
7450
+ marginTop: "0px",
7451
+ position: "relative",
7452
+ background: "var(--colorNeutralBackground1, #ffffff)",
7453
+ justifyContent: "center",
7454
+ height: props.contentHeight ?? "100%",
7455
+ ...isReadOnly && {
7456
+ cursor: "not-allowed",
7457
+ opacity: 0.75,
7458
+ userSelect: "text"
7257
7459
  }
7258
- };
7259
- const [touched, setTouched] = React9.useState(false);
7260
- const isOverLimit = props.wordLimit !== void 0 && wordCount > props.wordLimit;
7261
- const internalErrors = [];
7262
- if (isOverLimit) {
7263
- const m = props.errorMessages?.wordLimitExceeded;
7264
- internalErrors.push(
7265
- typeof m === "function" ? m(wordCount, props.wordLimit) : m ?? `Word limit exceeded (${wordCount} / ${props.wordLimit} words used)`
7266
- );
7267
- }
7268
- if (props.required && touched && wordCount === 0) {
7269
- internalErrors.push(
7270
- props.errorMessages?.required ?? "This field is required"
7271
- );
7272
- }
7273
- if (props.minWords !== void 0 && touched && wordCount < props.minWords) {
7274
- const m = props.errorMessages?.minWords;
7275
- internalErrors.push(
7276
- typeof m === "function" ? m(wordCount, props.minWords) : m ?? `Minimum ${props.minWords} words required (${wordCount} entered)`
7277
- );
7278
7460
  }
7279
- if (props.maxChars !== void 0 && charCount > props.maxChars) {
7280
- const m = props.errorMessages?.maxCharsExceeded;
7281
- internalErrors.push(
7282
- typeof m === "function" ? m(charCount, props.maxChars) : m ?? `Character limit exceeded (${charCount} / ${props.maxChars} characters used)`
7283
- );
7461
+ });
7462
+ const urlRegExp = new RegExp(
7463
+ /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/
7464
+ );
7465
+ const validateUrl = (url) => url === "https://" || urlRegExp.test(url);
7466
+ const handleReadOnlyClickCapture = (e) => {
7467
+ if (!isReadOnly) return;
7468
+ const target = e.target;
7469
+ const anchor = target?.closest?.("a");
7470
+ if (anchor) {
7471
+ e.preventDefault();
7472
+ e.stopPropagation();
7284
7473
  }
7285
- if (props.minChars !== void 0 && touched && charCount < props.minChars && charCount > 0) {
7286
- const m = props.errorMessages?.minCharsRequired;
7287
- internalErrors.push(
7288
- typeof m === "function" ? m(charCount, props.minChars) : m ?? `Minimum ${props.minChars} characters required (${charCount} entered)`
7289
- );
7474
+ };
7475
+ const [touched, setTouched] = React9.useState(false);
7476
+ const isOverLimit = props.wordLimit !== void 0 && wordCount > props.wordLimit;
7477
+ const internalErrors = [];
7478
+ if (isOverLimit) {
7479
+ const m = props.errorMessages?.wordLimitExceeded;
7480
+ internalErrors.push(
7481
+ typeof m === "function" ? m(wordCount, props.wordLimit) : m ?? `Word limit exceeded (${wordCount} / ${props.wordLimit} words used)`
7482
+ );
7483
+ }
7484
+ if (props.required && touched && wordCount === 0) {
7485
+ internalErrors.push(
7486
+ props.errorMessages?.required ?? "This field is required"
7487
+ );
7488
+ }
7489
+ if (props.minWords !== void 0 && touched && wordCount < props.minWords) {
7490
+ const m = props.errorMessages?.minWords;
7491
+ internalErrors.push(
7492
+ typeof m === "function" ? m(wordCount, props.minWords) : m ?? `Minimum ${props.minWords} words required (${wordCount} entered)`
7493
+ );
7494
+ }
7495
+ if (props.maxChars !== void 0 && charCount > props.maxChars) {
7496
+ const m = props.errorMessages?.maxCharsExceeded;
7497
+ internalErrors.push(
7498
+ typeof m === "function" ? m(charCount, props.maxChars) : m ?? `Character limit exceeded (${charCount} / ${props.maxChars} characters used)`
7499
+ );
7500
+ }
7501
+ if (props.minChars !== void 0 && touched && charCount < props.minChars && charCount > 0) {
7502
+ const m = props.errorMessages?.minCharsRequired;
7503
+ internalErrors.push(
7504
+ typeof m === "function" ? m(charCount, props.minChars) : m ?? `Minimum ${props.minChars} characters required (${charCount} entered)`
7505
+ );
7506
+ }
7507
+ const allErrors = [
7508
+ ...internalErrors,
7509
+ ...props.errors ?? [],
7510
+ ...refErrors
7511
+ ];
7512
+ const hasErrors = allErrors.length > 0;
7513
+ const hasRedBorder = hasErrors;
7514
+ React9.useEffect(() => {
7515
+ if (props.wordLimit === void 0 || !props.onWordLimitExceeded) return;
7516
+ const wasOverLimit = previousOverLimitRef.current;
7517
+ if (isOverLimit !== wasOverLimit) {
7518
+ props.onWordLimitExceeded({
7519
+ wordCount,
7520
+ wordLimit: props.wordLimit,
7521
+ exceeded: isOverLimit
7522
+ });
7523
+ previousOverLimitRef.current = isOverLimit;
7290
7524
  }
7291
- const allErrors = [...internalErrors, ...props.errors ?? [], ...refErrors];
7292
- const hasErrors = allErrors.length > 0;
7293
- const hasRedBorder = hasErrors;
7294
- React9.useEffect(() => {
7295
- if (props.wordLimit === void 0 || !props.onWordLimitExceeded) return;
7296
- const wasOverLimit = previousOverLimitRef.current;
7297
- if (isOverLimit !== wasOverLimit) {
7298
- props.onWordLimitExceeded({
7299
- wordCount,
7300
- wordLimit: props.wordLimit,
7301
- exceeded: isOverLimit
7302
- });
7303
- previousOverLimitRef.current = isOverLimit;
7304
- }
7305
- }, [isOverLimit, wordCount, props.wordLimit, props.onWordLimitExceeded]);
7306
- return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.FluentProvider, { theme: reactComponents.webLightTheme, style: { height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(LexicalComposer.LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, style: { height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
7307
- react.Stack,
7308
- {
7309
- style: {
7310
- zIndex: 1e3,
7311
- background: "#fff",
7312
- borderRadius: "2px",
7313
- width: props.width ?? "100%",
7314
- height: props.height ?? "100%",
7315
- margin: props.margin ?? "5px auto",
7316
- border: `1px solid ${hasRedBorder ? "#c4272c" : "var(--colorNeutralStroke1, #ccced1)"}`,
7317
- transition: "border-color 0.2s",
7318
- display: "flex",
7319
- flexDirection: "column"
7320
- },
7321
- children: [
7322
- /* @__PURE__ */ jsxRuntime.jsx(
7323
- "div",
7324
- {
7325
- style: {
7326
- pointerEvents: isReadOnly ? "none" : "auto",
7327
- position: "sticky",
7328
- opacity: isReadOnly ? 0.85 : 1
7329
- },
7330
- children: /* @__PURE__ */ jsxRuntime.jsx(
7331
- ToolBarPlugins,
7525
+ }, [isOverLimit, wordCount, props.wordLimit, props.onWordLimitExceeded]);
7526
+ return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.FluentProvider, { theme: reactComponents.webLightTheme, style: { height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(LexicalComposer.LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, style: { height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
7527
+ react.Stack,
7528
+ {
7529
+ style: {
7530
+ zIndex: 1e3,
7531
+ background: "#fff",
7532
+ borderRadius: "2px",
7533
+ width: props.width ?? "100%",
7534
+ height: props.height ?? "100%",
7535
+ margin: props.margin ?? "5px auto",
7536
+ border: `1px solid ${hasRedBorder ? "#c4272c" : "var(--colorNeutralStroke1, #ccced1)"}`,
7537
+ transition: "border-color 0.2s",
7538
+ display: "flex",
7539
+ flexDirection: "column"
7540
+ },
7541
+ children: [
7542
+ /* @__PURE__ */ jsxRuntime.jsx(
7543
+ "div",
7544
+ {
7545
+ style: {
7546
+ pointerEvents: isReadOnly ? "none" : "auto",
7547
+ position: "sticky",
7548
+ opacity: isReadOnly ? 0.85 : 1
7549
+ },
7550
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7551
+ ToolBarPlugins,
7552
+ {
7553
+ level: props.level ?? "basic" /* Basic */,
7554
+ readOnly: props.readOnly,
7555
+ pageSetup,
7556
+ onPageSetupChange: setPageSetup
7557
+ }
7558
+ )
7559
+ }
7560
+ ),
7561
+ /* @__PURE__ */ jsxRuntime.jsxs(
7562
+ "div",
7563
+ {
7564
+ style: {
7565
+ position: "relative",
7566
+ flexGrow: 1,
7567
+ padding: "15px 0px",
7568
+ overflowY: "scroll",
7569
+ overflowX: "auto",
7570
+ minWidth: 0,
7571
+ background: pageCanvas.widthPx !== void 0 ? "#eef0f2" : void 0
7572
+ },
7573
+ onClickCapture: handleReadOnlyClickCapture,
7574
+ children: [
7575
+ /* @__PURE__ */ jsxRuntime.jsx(
7576
+ LexicalRichTextPlugin.RichTextPlugin,
7332
7577
  {
7333
- level: props.level ?? "basic" /* Basic */,
7334
- readOnly: props.readOnly,
7335
- pageSetup,
7336
- onPageSetupChange: setPageSetup
7578
+ ErrorBoundary: LexicalErrorBoundary.LexicalErrorBoundary,
7579
+ contentEditable: /* @__PURE__ */ jsxRuntime.jsx(
7580
+ "div",
7581
+ {
7582
+ className: "editor",
7583
+ style: { height: "100%", position: "relative" },
7584
+ ref: onAnchorRef,
7585
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7586
+ LexicalContentEditable.ContentEditable,
7587
+ {
7588
+ ref: contentEditableDomRef,
7589
+ className: react.css(EditorStyles.contentEditor),
7590
+ style: {
7591
+ paddingTop: props.level !== "none" /* None */ ? 0 : 10,
7592
+ paddingLeft: pageCanvas.paddingPx,
7593
+ paddingRight: pageCanvas.paddingPx,
7594
+ maxWidth: pageCanvas.widthPx,
7595
+ marginLeft: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7596
+ marginRight: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7597
+ boxShadow: pageCanvas.widthPx !== void 0 ? "0 0 0 1px rgba(0,0,0,0.08), 0 2px 8px rgba(0,0,0,0.08)" : void 0
7598
+ },
7599
+ spellCheck: !resolvedSpellCheck,
7600
+ autoCorrect: resolvedSpellCheck ? "off" : void 0,
7601
+ autoCapitalize: resolvedSpellCheck ? "off" : void 0
7602
+ }
7603
+ )
7604
+ }
7605
+ ),
7606
+ placeholder: /* @__PURE__ */ jsxRuntime.jsx(react.Stack, { className: react.css(EditorStyles.editorPlaceholder), children: props.placeholder })
7607
+ }
7608
+ ),
7609
+ props.wordLimit !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
7610
+ "div",
7611
+ {
7612
+ style: {
7613
+ position: "sticky",
7614
+ bottom: 0,
7615
+ display: "flex",
7616
+ justifyContent: "flex-end",
7617
+ paddingRight: 14,
7618
+ pointerEvents: "none",
7619
+ userSelect: "none"
7620
+ },
7621
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
7622
+ "span",
7623
+ {
7624
+ style: {
7625
+ fontSize: "11px",
7626
+ color: isOverLimit ? "#c4272c" : "var(--colorNeutralForeground3, #aaa)",
7627
+ fontWeight: isOverLimit ? 600 : 400,
7628
+ transition: "color 0.2s, font-weight 0.2s"
7629
+ },
7630
+ children: [
7631
+ wordCount,
7632
+ " / ",
7633
+ props.wordLimit,
7634
+ " words"
7635
+ ]
7636
+ }
7637
+ )
7337
7638
  }
7338
7639
  )
7339
- }
7340
- ),
7341
- /* @__PURE__ */ jsxRuntime.jsxs(
7342
- "div",
7343
- {
7344
- style: {
7345
- position: "relative",
7346
- flexGrow: 1,
7347
- padding: "15px 0px",
7348
- overflowY: "scroll",
7349
- overflowX: "auto",
7350
- minWidth: 0,
7351
- background: pageCanvas.widthPx !== void 0 ? "#eef0f2" : void 0
7352
- },
7353
- onClickCapture: handleReadOnlyClickCapture,
7354
- children: [
7355
- /* @__PURE__ */ jsxRuntime.jsx(
7356
- LexicalRichTextPlugin.RichTextPlugin,
7357
- {
7358
- ErrorBoundary: LexicalErrorBoundary.LexicalErrorBoundary,
7359
- contentEditable: /* @__PURE__ */ jsxRuntime.jsx(
7360
- "div",
7361
- {
7362
- className: "editor",
7363
- style: { height: "100%", position: "relative" },
7364
- ref: onAnchorRef,
7365
- children: /* @__PURE__ */ jsxRuntime.jsx(
7366
- LexicalContentEditable.ContentEditable,
7367
- {
7368
- ref: contentEditableDomRef,
7369
- className: react.css(EditorStyles.contentEditor),
7370
- style: {
7371
- paddingTop: props.level !== "none" /* None */ ? 0 : 10,
7372
- paddingLeft: pageCanvas.paddingPx,
7373
- paddingRight: pageCanvas.paddingPx,
7374
- maxWidth: pageCanvas.widthPx,
7375
- marginLeft: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7376
- marginRight: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7377
- boxShadow: pageCanvas.widthPx !== void 0 ? "0 0 0 1px rgba(0,0,0,0.08), 0 2px 8px rgba(0,0,0,0.08)" : void 0
7378
- },
7379
- spellCheck: !resolvedSpellCheck,
7380
- autoCorrect: resolvedSpellCheck ? "off" : void 0,
7381
- autoCapitalize: resolvedSpellCheck ? "off" : void 0
7382
- }
7383
- )
7384
- }
7385
- ),
7386
- placeholder: /* @__PURE__ */ jsxRuntime.jsx(react.Stack, { className: react.css(EditorStyles.editorPlaceholder), children: props.placeholder })
7387
- }
7388
- ),
7389
- props.wordLimit !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
7390
- "div",
7391
- {
7392
- style: {
7393
- position: "sticky",
7394
- bottom: 0,
7395
- display: "flex",
7396
- justifyContent: "flex-end",
7397
- paddingRight: 14,
7398
- pointerEvents: "none",
7399
- userSelect: "none"
7400
- },
7401
- children: /* @__PURE__ */ jsxRuntime.jsxs(
7402
- "span",
7403
- {
7404
- style: {
7405
- fontSize: "11px",
7406
- color: isOverLimit ? "#c4272c" : "var(--colorNeutralForeground3, #aaa)",
7407
- fontWeight: isOverLimit ? 600 : 400,
7408
- transition: "color 0.2s, font-weight 0.2s"
7409
- },
7410
- children: [
7411
- wordCount,
7412
- " / ",
7413
- props.wordLimit,
7414
- " words"
7415
- ]
7416
- }
7417
- )
7418
- }
7419
- )
7420
- ]
7421
- }
7422
- ),
7423
- hasErrors && /* @__PURE__ */ jsxRuntime.jsx(
7424
- "div",
7425
- {
7426
- style: {
7427
- borderTop: "1px solid #fbd5d5",
7428
- background: "#fff8f8",
7429
- padding: "6px 12px 8px",
7430
- display: "flex",
7431
- flexDirection: "column",
7432
- gap: 4
7433
- },
7434
- children: allErrors.map((err, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
7435
- /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ErrorCircleRegular, { style: { fontSize: 14, color: "#c4272c", flexShrink: 0 } }),
7436
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#c4272c" }, children: err })
7437
- ] }, i))
7438
- }
7439
- ),
7440
- /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyPlugin, { readonly: isReadOnly }),
7441
- /* @__PURE__ */ jsxRuntime.jsx(BrowserSpellCheckPlugin, { enabled: !resolvedSpellCheck }),
7442
- /* @__PURE__ */ jsxRuntime.jsx(
7443
- FocusEventsPlugin,
7444
- {
7445
- onFocus: props.onFocus,
7446
- onBlur: () => {
7447
- setTouched(true);
7448
- props.onBlur?.();
7640
+ ]
7641
+ }
7642
+ ),
7643
+ hasErrors && /* @__PURE__ */ jsxRuntime.jsx(
7644
+ "div",
7645
+ {
7646
+ style: {
7647
+ borderTop: "1px solid #fbd5d5",
7648
+ background: "#fff8f8",
7649
+ padding: "6px 12px 8px",
7650
+ display: "flex",
7651
+ flexDirection: "column",
7652
+ gap: 4
7653
+ },
7654
+ children: allErrors.map((err, i) => /* @__PURE__ */ jsxRuntime.jsxs(
7655
+ "div",
7656
+ {
7657
+ style: { display: "flex", alignItems: "center", gap: 6 },
7658
+ children: [
7659
+ /* @__PURE__ */ jsxRuntime.jsx(
7660
+ reactIcons.ErrorCircleRegular,
7661
+ {
7662
+ style: { fontSize: 14, color: "#c4272c", flexShrink: 0 }
7663
+ }
7664
+ ),
7665
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#c4272c" }, children: err })
7666
+ ]
7449
7667
  },
7450
- setFocused,
7451
- containerRef
7452
- }
7453
- ),
7454
- props.autoFocus && !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(LexicalAutoFocusPlugin.AutoFocusPlugin, {}),
7455
- /* @__PURE__ */ jsxRuntime.jsx(LexicalHistoryPlugin.HistoryPlugin, {}),
7456
- /* @__PURE__ */ jsxRuntime.jsx(LexicalListPlugin.ListPlugin, {}),
7457
- /* @__PURE__ */ jsxRuntime.jsx(LexicalLinkPlugin.LinkPlugin, { validateUrl }),
7458
- /* @__PURE__ */ jsxRuntime.jsx(LexicalAutoLinkPlugin.AutoLinkPlugin, { matchers: MATCHERS }),
7459
- /* @__PURE__ */ jsxRuntime.jsx(LexicalTablePlugin.TablePlugin, { hasCellMerge: true, hasCellBackgroundColor: true }),
7460
- !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(YoutubeDeletePlugin, {}),
7461
- !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsxRuntime.jsx(TableActionMenuPlugin, {}),
7462
- !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsxRuntime.jsx(TableCellResizerPlugin, { anchorElem: floatingAnchorElem }),
7463
- !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(
7464
- FloatingLinkEditorPlugin,
7465
- {
7466
- anchorElem: floatingAnchorElem,
7467
- isLinkEditMode,
7468
- setIsLinkEditMode
7469
- }
7470
- ),
7471
- !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(ImagePlugin_default, {}),
7472
- !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(InlineImage_default, {}),
7473
- !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(PageBreakPlugin, {}),
7474
- !!resolvedQuery && !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(
7475
- AutocompletePlugin,
7476
- {
7477
- useQuery: resolvedQuery,
7478
- isReadOnly,
7479
- onSuggestionShown: props.onSuggestionShown,
7480
- onSuggestionAccept: props.onSuggestionAccept,
7481
- idleMs: props.suggestIdleMs ?? 300,
7482
- minWords: 4,
7483
- prefixWindow: 300
7484
- }
7485
- ),
7486
- !!resolvedSpellCheck && !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(
7487
- SpellCheckPlugin,
7488
- {
7489
- useSpellCheck: resolvedSpellCheck,
7490
- onSpellCheckAccept: props.onSpellCheckAccept,
7491
- idleMs: props.spellCheckIdleMs ?? 1200,
7492
- enabled: props.spellCheckEnabled !== false
7493
- }
7494
- ),
7495
- !isReadOnly && props.showFloatingToolbar && /* @__PURE__ */ jsxRuntime.jsx(CharacterStylesPopupPlugin, {}),
7496
- /* @__PURE__ */ jsxRuntime.jsx(CustomOnChangePlugin, { value: props.value, onChange: props.onChange }),
7497
- (props.wordLimit !== void 0 || props.required || props.minWords !== void 0) && /* @__PURE__ */ jsxRuntime.jsx(WordCountPlugin, { onCountChange: handleWordCount }),
7498
- (props.maxChars !== void 0 || props.minChars !== void 0) && /* @__PURE__ */ jsxRuntime.jsx(CharCountPlugin, { onCountChange: handleCharCount }),
7499
- /* @__PURE__ */ jsxRuntime.jsx(
7500
- RefApiPlugin,
7501
- {
7502
- forwardedRef: ref,
7503
- contentEditableDomRef,
7504
- focusedRef,
7505
- setRefErrors
7506
- }
7507
- )
7508
- ]
7509
- }
7510
- ) }) }) });
7511
- }
7512
- );
7668
+ i
7669
+ ))
7670
+ }
7671
+ ),
7672
+ /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyPlugin, { readonly: isReadOnly }),
7673
+ /* @__PURE__ */ jsxRuntime.jsx(BrowserSpellCheckPlugin, { enabled: !resolvedSpellCheck }),
7674
+ /* @__PURE__ */ jsxRuntime.jsx(
7675
+ FocusEventsPlugin,
7676
+ {
7677
+ onFocus: props.onFocus,
7678
+ onBlur: () => {
7679
+ setTouched(true);
7680
+ props.onBlur?.();
7681
+ },
7682
+ setFocused,
7683
+ containerRef
7684
+ }
7685
+ ),
7686
+ props.autoFocus && !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(LexicalAutoFocusPlugin.AutoFocusPlugin, {}),
7687
+ /* @__PURE__ */ jsxRuntime.jsx(LexicalHistoryPlugin.HistoryPlugin, {}),
7688
+ /* @__PURE__ */ jsxRuntime.jsx(LexicalListPlugin.ListPlugin, {}),
7689
+ /* @__PURE__ */ jsxRuntime.jsx(LexicalLinkPlugin.LinkPlugin, { validateUrl }),
7690
+ /* @__PURE__ */ jsxRuntime.jsx(LexicalAutoLinkPlugin.AutoLinkPlugin, { matchers: MATCHERS }),
7691
+ /* @__PURE__ */ jsxRuntime.jsx(LexicalTablePlugin.TablePlugin, { hasCellMerge: true, hasCellBackgroundColor: true }),
7692
+ !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(YoutubeDeletePlugin, {}),
7693
+ !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsxRuntime.jsx(TableActionMenuPlugin, {}),
7694
+ !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsxRuntime.jsx(TableCellResizerPlugin, { anchorElem: floatingAnchorElem }),
7695
+ !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(
7696
+ FloatingLinkEditorPlugin,
7697
+ {
7698
+ anchorElem: floatingAnchorElem,
7699
+ isLinkEditMode,
7700
+ setIsLinkEditMode
7701
+ }
7702
+ ),
7703
+ !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(ImagePlugin_default, {}),
7704
+ !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(InlineImage_default, {}),
7705
+ !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(PageBreakPlugin, {}),
7706
+ !!resolvedQuery && !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(
7707
+ AutocompletePlugin,
7708
+ {
7709
+ useQuery: resolvedQuery,
7710
+ isReadOnly,
7711
+ onSuggestionShown: props.onSuggestionShown,
7712
+ onSuggestionAccept: props.onSuggestionAccept,
7713
+ idleMs: props.suggestIdleMs ?? 300,
7714
+ minWords: 4,
7715
+ prefixWindow: 300
7716
+ }
7717
+ ),
7718
+ !!resolvedSpellCheck && !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(
7719
+ SpellCheckPlugin,
7720
+ {
7721
+ useSpellCheck: resolvedSpellCheck,
7722
+ onSpellCheckAccept: props.onSpellCheckAccept,
7723
+ idleMs: props.spellCheckIdleMs ?? 1200,
7724
+ enabled: props.spellCheckEnabled !== false
7725
+ }
7726
+ ),
7727
+ !isReadOnly && props.showFloatingToolbar && /* @__PURE__ */ jsxRuntime.jsx(CharacterStylesPopupPlugin, {}),
7728
+ /* @__PURE__ */ jsxRuntime.jsx(
7729
+ CustomOnChangePlugin,
7730
+ {
7731
+ value: props.value,
7732
+ onChange: props.onChange
7733
+ }
7734
+ ),
7735
+ (props.wordLimit !== void 0 || props.required || props.minWords !== void 0) && /* @__PURE__ */ jsxRuntime.jsx(WordCountPlugin, { onCountChange: handleWordCount }),
7736
+ (props.maxChars !== void 0 || props.minChars !== void 0) && /* @__PURE__ */ jsxRuntime.jsx(CharCountPlugin, { onCountChange: handleCharCount }),
7737
+ /* @__PURE__ */ jsxRuntime.jsx(
7738
+ RefApiPlugin,
7739
+ {
7740
+ forwardedRef: ref,
7741
+ contentEditableDomRef,
7742
+ focusedRef,
7743
+ setRefErrors
7744
+ }
7745
+ )
7746
+ ]
7747
+ }
7748
+ ) }) }) });
7749
+ });
7513
7750
 
7514
7751
  exports.ContentEditorComponent = ContentEditorComponent;
7515
7752
  exports.ContentEditorLevel = ContentEditorLevel;