@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.mjs CHANGED
@@ -7,8 +7,8 @@ import { useLexicalEditable } from '@lexical/react/useLexicalEditable';
7
7
  import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
8
8
  import { createCommand, DecoratorNode, COMMAND_PRIORITY_HIGH, TextNode, ElementNode, $setSelection, $getSelection, $isRangeSelection, SELECTION_CHANGE_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, $findMatchingParent, COMMAND_PRIORITY_LOW, KEY_DOWN_COMMAND, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, PASTE_COMMAND, DRAGSTART_COMMAND, DRAGOVER_COMMAND, DROP_COMMAND, $getNodeByKey, $getRoot, $createTextNode, $isTextNode, $createRangeSelection, $isElementNode, $isNodeSelection, CLICK_COMMAND, $applyNodeReplacement, FORMAT_TEXT_COMMAND, $isDecoratorNode, $getNearestNodeFromDOMNode, COMMAND_PRIORITY_CRITICAL, REDO_COMMAND, UNDO_COMMAND, getDOMSelection, KEY_ESCAPE_COMMAND, isHTMLElement, getDOMSelectionFromTarget, SKIP_SELECTION_FOCUS_TAG, createEditor, KEY_ENTER_COMMAND } from 'lexical';
9
9
  import { mergeStyleSets, Stack, css, useTheme, Callout, TextField } from '@fluentui/react';
10
- import { makeStyles, FluentProvider, webLightTheme, Menu, MenuTrigger, MenuPopover, MenuList, MenuGroup, MenuGroupHeader, MenuItem, MenuDivider, Dropdown, Option, ToolbarDivider, Button, MenuItemRadio, Popover, PopoverTrigger, PopoverSurface, Field, Input } from '@fluentui/react-components';
11
- import { ErrorCircleRegular, ChevronDown12Regular, ArrowUpRegular, RowTripleRegular, ArrowDownRegular, ArrowLeftRegular, ColumnTripleRegular, ArrowRightRegular, DeleteRegular, TextCaseUppercaseFilled, TextCaseLowercaseFilled, TextCaseTitleFilled, TextStrikethroughFilled, TextSubscriptFilled, TextSuperscriptFilled, HighlightAccentFilled, TextBulletListLtrFilled, TextNumberListLtrFilled, DocumentPageBreakRegular, CommentQuoteRegular, TextUnderlineFilled, TextItalicFilled, TextBold24Regular, DocumentRegular, TextAlignLeftFilled, TextAlignCenterFilled, TextAlignRightFilled, TextAlignJustifyFilled, VideoClipRegular, ImageEditRegular, AttachFilled, ImageAddRegular, TableAddRegular, LinkAddRegular, TextColorRegular, PaintBucket16Filled, CodeFilled, LinkFilled, Dismiss16Regular } from '@fluentui/react-icons';
10
+ import { makeStyles, FluentProvider, webLightTheme, Menu, MenuTrigger, MenuPopover, MenuList, MenuGroup, MenuGroupHeader, MenuItem, MenuDivider, Dropdown, Option, ToolbarDivider, Button, MenuItemRadio, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, Field, Input, DialogActions } from '@fluentui/react-components';
11
+ import { ErrorCircleRegular, ChevronDown12Regular, ArrowUpRegular, RowTripleRegular, ArrowDownRegular, ArrowLeftRegular, ColumnTripleRegular, ArrowRightRegular, DeleteRegular, TextCaseUppercaseFilled, TextCaseLowercaseFilled, TextCaseTitleFilled, TextStrikethroughFilled, TextSubscriptFilled, TextSuperscriptFilled, HighlightAccentFilled, TextBulletListLtrFilled, TextNumberListLtrFilled, DocumentPageBreakRegular, CommentQuoteRegular, AddRegular, TableAddRegular, ImageAddRegular, ImageEditRegular, VideoClipRegular, TextUnderlineFilled, TextItalicFilled, TextBold24Regular, DocumentRegular, TextAlignLeftFilled, TextAlignCenterFilled, TextAlignRightFilled, TextAlignJustifyFilled, AttachFilled, LinkAddRegular, TextColorRegular, PaintBucket16Filled, Dismiss16Regular, Checkmark16Regular, Edit16Regular, Delete16Regular, CodeFilled, LinkFilled } from '@fluentui/react-icons';
12
12
  import { CodeHighlightNode, CodeNode, $isCodeHighlightNode } from '@lexical/code';
13
13
  import { LinkNode, AutoLinkNode, $isLinkNode, $isAutoLinkNode, TOGGLE_LINK_COMMAND, $createLinkNode } from '@lexical/link';
14
14
  import { ListNode, ListItemNode, $isListNode, REMOVE_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';
@@ -615,7 +615,6 @@ var init_ImageComponent = __esm({
615
615
  editor,
616
616
  buttonRef,
617
617
  imageRef,
618
- maxWidth,
619
618
  onResizeStart,
620
619
  onResizeEnd,
621
620
  captionsEnabled: !isLoadError && captionsEnabled
@@ -766,6 +765,9 @@ var init_ImageNode = __esm({
766
765
  const writable = this.getWritable();
767
766
  writable.__width = width;
768
767
  writable.__height = height;
768
+ if (typeof width === "number" && width > writable.__maxWidth) {
769
+ writable.__maxWidth = width;
770
+ }
769
771
  }
770
772
  setShowCaption(showCaption) {
771
773
  const writable = this.getWritable();
@@ -855,6 +857,7 @@ __export(InlineImageComponent_exports, {
855
857
  var imageCache2, useSuspenseImage2, LazyImage2, InlineImageComponent, InlineImageComponent_default;
856
858
  var init_InlineImageComponent = __esm({
857
859
  "src/Nodes/InlineImageComponent.tsx"() {
860
+ init_ImageResizer();
858
861
  init_InlineImage();
859
862
  init_InlineImageNode();
860
863
  imageCache2 = /* @__PURE__ */ new Set();
@@ -897,6 +900,29 @@ var init_InlineImageComponent = __esm({
897
900
  const buttonRef = useRef(null);
898
901
  const [editor] = useLexicalComposerContext();
899
902
  const isEditable = useLexicalEditable();
903
+ const [isResizing, setIsResizing] = useState(false);
904
+ const onResizeEnd = (nextWidth, nextHeight) => {
905
+ setTimeout(() => {
906
+ setIsResizing(false);
907
+ }, 200);
908
+ editor.update(() => {
909
+ const node = $getNodeByKey(nodeKey);
910
+ if ($isInlineImageNode(node)) {
911
+ node.setWidthAndHeight(nextWidth, nextHeight);
912
+ }
913
+ });
914
+ };
915
+ const onResizeStart = () => {
916
+ setIsResizing(true);
917
+ };
918
+ const setShowCaption = (show) => {
919
+ editor.update(() => {
920
+ const node = $getNodeByKey(nodeKey);
921
+ if ($isInlineImageNode(node)) {
922
+ node.setShowCaption(show);
923
+ }
924
+ });
925
+ };
900
926
  const $onDelete = useCallback(
901
927
  (payload) => {
902
928
  const deleteSelection = $getSelection();
@@ -972,6 +998,9 @@ var init_InlineImageComponent = __esm({
972
998
  CLICK_COMMAND,
973
999
  (payload) => {
974
1000
  const event = payload;
1001
+ if (isResizing) {
1002
+ return true;
1003
+ }
975
1004
  if (event.target === imageRef.current) {
976
1005
  if (event.shiftKey) {
977
1006
  setSelected(!isSelected);
@@ -1020,6 +1049,7 @@ var init_InlineImageComponent = __esm({
1020
1049
  }, [
1021
1050
  clearSelection,
1022
1051
  editor,
1052
+ isResizing,
1023
1053
  isSelected,
1024
1054
  nodeKey,
1025
1055
  $onDelete,
@@ -1027,20 +1057,35 @@ var init_InlineImageComponent = __esm({
1027
1057
  $onEscape,
1028
1058
  setSelected
1029
1059
  ]);
1030
- const draggable = isSelected && $isNodeSelection(selection);
1031
- const isFocused = isSelected && isEditable;
1032
- return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx("span", { draggable, children: /* @__PURE__ */ jsx(
1033
- LazyImage2,
1034
- {
1035
- className: isFocused ? `focused ${$isNodeSelection(selection) ? "draggable" : ""}` : null,
1036
- src,
1037
- altText,
1038
- imageRef,
1039
- width,
1040
- height,
1041
- position
1042
- }
1043
- ) }) });
1060
+ const draggable = isSelected && $isNodeSelection(selection) && !isResizing;
1061
+ const isFocused = (isSelected || isResizing) && isEditable;
1062
+ return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsxs(Fragment, { children: [
1063
+ /* @__PURE__ */ jsx("span", { draggable, children: /* @__PURE__ */ jsx(
1064
+ LazyImage2,
1065
+ {
1066
+ className: isFocused ? `focused ${$isNodeSelection(selection) ? "draggable" : ""}` : null,
1067
+ src,
1068
+ altText,
1069
+ imageRef,
1070
+ width,
1071
+ height,
1072
+ position
1073
+ }
1074
+ ) }),
1075
+ isFocused && $isNodeSelection(selection) && /* @__PURE__ */ jsx(
1076
+ ImageResizer_default,
1077
+ {
1078
+ showCaption,
1079
+ setShowCaption,
1080
+ editor,
1081
+ buttonRef,
1082
+ imageRef,
1083
+ onResizeStart,
1084
+ onResizeEnd,
1085
+ captionsEnabled: false
1086
+ }
1087
+ )
1088
+ ] }) });
1044
1089
  };
1045
1090
  InlineImageComponent_default = InlineImageComponent;
1046
1091
  }
@@ -2857,7 +2902,7 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
2857
2902
  return;
2858
2903
  }
2859
2904
  const rootElement = editor.getRootElement();
2860
- if (selection !== null && nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode) && editor.isEditable()) {
2905
+ if (isLink && selection !== null && nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode) && editor.isEditable()) {
2861
2906
  const domRect = nativeSelection.focusNode?.parentElement?.getBoundingClientRect();
2862
2907
  if (domRect) {
2863
2908
  domRect.y += 40;
@@ -2873,7 +2918,7 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
2873
2918
  setLinkUrl("");
2874
2919
  }
2875
2920
  return true;
2876
- }, [anchorElem, editor, setIsLinkEditMode, isLinkEditMode, linkUrl]);
2921
+ }, [anchorElem, editor, isLink, setIsLinkEditMode, isLinkEditMode, linkUrl]);
2877
2922
  useEffect(() => {
2878
2923
  const scrollerElem = anchorElem.parentElement;
2879
2924
  const update = () => {
@@ -2971,6 +3016,7 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
2971
3016
  {
2972
3017
  ref: inputRef,
2973
3018
  className: "link-input",
3019
+ placeholder: "https://",
2974
3020
  value: editedLinkUrl,
2975
3021
  onChange: (event) => {
2976
3022
  setEditedLinkUrl(event.target.value);
@@ -2980,27 +3026,31 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
2980
3026
  }
2981
3027
  }
2982
3028
  ),
2983
- /* @__PURE__ */ jsxs("div", { children: [
3029
+ /* @__PURE__ */ jsxs("div", { className: "link-actions", children: [
2984
3030
  /* @__PURE__ */ jsx(
2985
- "div",
3031
+ "button",
2986
3032
  {
2987
- className: "link-cancel",
2988
- role: "button",
2989
- tabIndex: 0,
3033
+ type: "button",
3034
+ className: "link-icon-btn link-cancel",
3035
+ title: "Cancel",
3036
+ "aria-label": "Cancel",
2990
3037
  onMouseDown: preventDefault,
2991
3038
  onClick: () => {
2992
3039
  setIsLinkEditMode(false);
2993
- }
3040
+ },
3041
+ children: /* @__PURE__ */ jsx(Dismiss16Regular, {})
2994
3042
  }
2995
3043
  ),
2996
3044
  /* @__PURE__ */ jsx(
2997
- "div",
3045
+ "button",
2998
3046
  {
2999
- className: "link-confirm",
3000
- role: "button",
3001
- tabIndex: 0,
3047
+ type: "button",
3048
+ className: "link-icon-btn link-confirm",
3049
+ title: "Confirm",
3050
+ "aria-label": "Confirm",
3002
3051
  onMouseDown: preventDefault,
3003
- onClick: handleLinkSubmission
3052
+ onClick: handleLinkSubmission,
3053
+ children: /* @__PURE__ */ jsx(Checkmark16Regular, {})
3004
3054
  }
3005
3055
  )
3006
3056
  ] })
@@ -3014,32 +3064,38 @@ var FloatingLinkEditor = ({ editor, isLink, setIsLink, anchorElem, isLinkEditMod
3014
3064
  children: linkUrl
3015
3065
  }
3016
3066
  ),
3017
- /* @__PURE__ */ jsx(
3018
- "div",
3019
- {
3020
- className: "link-edit",
3021
- role: "button",
3022
- tabIndex: 0,
3023
- onMouseDown: preventDefault,
3024
- onClick: (event) => {
3025
- event.preventDefault();
3026
- setEditedLinkUrl(linkUrl);
3027
- setIsLinkEditMode(true);
3067
+ /* @__PURE__ */ jsxs("div", { className: "link-actions", children: [
3068
+ /* @__PURE__ */ jsx(
3069
+ "button",
3070
+ {
3071
+ type: "button",
3072
+ className: "link-icon-btn link-edit",
3073
+ title: "Edit link",
3074
+ "aria-label": "Edit link",
3075
+ onMouseDown: preventDefault,
3076
+ onClick: (event) => {
3077
+ event.preventDefault();
3078
+ setEditedLinkUrl(linkUrl);
3079
+ setIsLinkEditMode(true);
3080
+ },
3081
+ children: /* @__PURE__ */ jsx(Edit16Regular, {})
3028
3082
  }
3029
- }
3030
- ),
3031
- /* @__PURE__ */ jsx(
3032
- "div",
3033
- {
3034
- className: "link-trash",
3035
- role: "button",
3036
- tabIndex: 0,
3037
- onMouseDown: preventDefault,
3038
- onClick: () => {
3039
- editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
3083
+ ),
3084
+ /* @__PURE__ */ jsx(
3085
+ "button",
3086
+ {
3087
+ type: "button",
3088
+ className: "link-icon-btn link-trash",
3089
+ title: "Remove link",
3090
+ "aria-label": "Remove link",
3091
+ onMouseDown: preventDefault,
3092
+ onClick: () => {
3093
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
3094
+ },
3095
+ children: /* @__PURE__ */ jsx(Delete16Regular, {})
3040
3096
  }
3041
- }
3042
- )
3097
+ )
3098
+ ] })
3043
3099
  ] }) });
3044
3100
  };
3045
3101
  var useFloatingLinkEditorToolbar = (editor, anchorElem, isLinkEditMode, setIsLinkEditMode) => {
@@ -3140,74 +3196,28 @@ var readClipboardImageAsDataURL = async (event) => {
3140
3196
  }
3141
3197
  return null;
3142
3198
  };
3143
- var InsertImageByURL = ({
3144
- setIsOpen,
3145
- onClick,
3146
- disabled
3147
- }) => {
3148
- const [altText, setAltText] = useState("");
3149
- const [src, setSrc] = useState("");
3150
- const isDisabled = disabled || src === "";
3151
- return /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 6, padding: "10px 0px 0px 0px" }, children: [
3152
- /* @__PURE__ */ jsx(Field, { label: "Enter URL", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
3153
- Input,
3154
- {
3155
- autoFocus: !disabled,
3156
- appearance: "underline",
3157
- placeholder: "Add URL",
3158
- disabled,
3159
- onChange: (_, v) => setSrc(v.value),
3160
- value: src
3161
- }
3162
- ) }),
3163
- /* @__PURE__ */ jsx(Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
3164
- Input,
3165
- {
3166
- placeholder: "Alt text",
3167
- disabled,
3168
- onChange: (_, v) => setAltText(v.value),
3169
- value: altText
3170
- },
3171
- "alt-text-url"
3172
- ) }),
3173
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
3174
- /* @__PURE__ */ jsx(
3175
- Button,
3176
- {
3177
- style: { width: "150px" },
3178
- onClick: () => !disabled && onClick({ altText, src }),
3179
- disabled: isDisabled,
3180
- size: "small",
3181
- children: "Confirm"
3182
- },
3183
- "url-confirm-btn"
3184
- ),
3185
- /* @__PURE__ */ jsx(
3186
- Button,
3187
- {
3188
- style: { width: "150px" },
3189
- onClick: () => setIsOpen(false),
3190
- disabled,
3191
- size: "small",
3192
- children: "Cancel"
3193
- },
3194
- "file-url-cancel"
3195
- )
3196
- ] })
3197
- ] });
3198
- };
3199
3199
  var InsertImageDialog = ({
3200
3200
  activeEditor,
3201
- disabled
3201
+ disabled,
3202
+ open: externalOpen,
3203
+ onClose
3202
3204
  }) => {
3203
3205
  const [src, setSrc] = useState("");
3204
3206
  const [altText, setAltText] = useState("");
3205
- const [isOpen, setIsOpen] = useState(false);
3206
- const [selectedValue, setSelectedValue] = useState("Upload");
3207
+ const [internalOpen, setInternalOpen] = useState(false);
3207
3208
  const [fileName, setFileName] = useState("");
3208
3209
  const hasModifier = useRef(false);
3209
3210
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
3210
- const isDisabled = disabled || src === "";
3211
+ const isControlled = externalOpen !== void 0;
3212
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
3213
+ const isAddDisabled = disabled || src === "";
3214
+ const handleClose = () => {
3215
+ setSrc("");
3216
+ setAltText("");
3217
+ setFileName("");
3218
+ if (isControlled) onClose?.();
3219
+ else setInternalOpen(false);
3220
+ };
3211
3221
  useEffect(() => {
3212
3222
  hasModifier.current = false;
3213
3223
  const handler = (e) => {
@@ -3219,10 +3229,7 @@ var InsertImageDialog = ({
3219
3229
  const onClick = (payload) => {
3220
3230
  if (disabled) return;
3221
3231
  activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, payload);
3222
- setIsOpen(false);
3223
- setAltText("");
3224
- setSrc("");
3225
- setFileName("");
3232
+ handleClose();
3226
3233
  };
3227
3234
  const loadImage = (event) => {
3228
3235
  if (disabled) return;
@@ -3237,118 +3244,108 @@ var InsertImageDialog = ({
3237
3244
  };
3238
3245
  reader.readAsDataURL(files[0]);
3239
3246
  };
3240
- return /* @__PURE__ */ jsxs(
3241
- Popover,
3242
- {
3243
- trapFocus: true,
3244
- withArrow: true,
3245
- open: disabled ? false : isOpen,
3246
- onOpenChange: (_, data) => {
3247
- if (!disabled) setIsOpen(data.open);
3247
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3248
+ !isControlled && /* @__PURE__ */ jsx(
3249
+ Button,
3250
+ {
3251
+ size: "small",
3252
+ title: "Add Image",
3253
+ disabled,
3254
+ icon: /* @__PURE__ */ jsx(ImageAddRegular, { style: { color: iconColor } }),
3255
+ style: {
3256
+ background: isOpen && !disabled ? "#ebebeb" : "none",
3257
+ border: "none",
3258
+ margin: 2,
3259
+ opacity: disabled ? 0.55 : 1,
3260
+ cursor: disabled ? "not-allowed" : "pointer"
3261
+ },
3262
+ onClick: () => {
3263
+ if (disabled) return;
3264
+ setSrc("");
3265
+ setAltText("");
3266
+ setFileName("");
3267
+ setInternalOpen(true);
3268
+ }
3248
3269
  },
3249
- children: [
3250
- /* @__PURE__ */ jsx(PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
3251
- Button,
3252
- {
3253
- size: "small",
3254
- title: "Add Image",
3255
- disabled,
3256
- icon: /* @__PURE__ */ jsx(ImageAddRegular, { style: { color: iconColor } }),
3257
- style: {
3258
- background: isOpen && !disabled ? "#ebebeb" : "none",
3259
- border: "none",
3260
- margin: 2,
3261
- opacity: disabled ? 0.55 : 1,
3262
- cursor: disabled ? "not-allowed" : "pointer"
3263
- },
3264
- onClick: () => {
3265
- if (disabled) return;
3266
- setIsOpen((prev) => !prev);
3267
- setSrc("");
3268
- setAltText("");
3269
- setFileName("");
3270
- }
3271
- },
3272
- "upload-image"
3273
- ) }),
3274
- /* @__PURE__ */ jsxs(
3275
- PopoverSurface,
3276
- {
3277
- style: {
3278
- width: "320px",
3279
- opacity: disabled ? 0.6 : 1,
3280
- pointerEvents: disabled ? "none" : "auto"
3281
- },
3282
- children: [
3283
- /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 6 }, children: [
3284
- /* @__PURE__ */ jsx(Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxs(
3285
- "label",
3286
- {
3287
- style: {
3288
- cursor: disabled ? "not-allowed" : "pointer",
3289
- display: "flex",
3290
- alignItems: "center",
3291
- gap: 8,
3292
- opacity: disabled ? 0.75 : 1
3270
+ "upload-image"
3271
+ ),
3272
+ /* @__PURE__ */ jsx(
3273
+ Dialog,
3274
+ {
3275
+ open: isOpen,
3276
+ onOpenChange: (_, data) => {
3277
+ if (!data.open) handleClose();
3278
+ },
3279
+ children: /* @__PURE__ */ jsx(DialogSurface, { style: { maxWidth: "400px" }, children: /* @__PURE__ */ jsxs(DialogBody, { children: [
3280
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Insert Image" }),
3281
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
3282
+ /* @__PURE__ */ jsx(Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxs(
3283
+ "label",
3284
+ {
3285
+ style: {
3286
+ cursor: disabled ? "not-allowed" : "pointer",
3287
+ display: "flex",
3288
+ alignItems: "center",
3289
+ gap: 8,
3290
+ opacity: disabled ? 0.75 : 1
3291
+ },
3292
+ children: [
3293
+ /* @__PURE__ */ jsx(
3294
+ "input",
3295
+ {
3296
+ type: "file",
3297
+ accept: "image/*",
3298
+ style: { display: "none" },
3299
+ disabled,
3300
+ onChange: loadImage
3293
3301
  },
3294
- children: [
3295
- /* @__PURE__ */ jsx(
3296
- "input",
3297
- {
3298
- type: "file",
3299
- accept: "image/*",
3300
- style: { display: "none" },
3301
- disabled,
3302
- onChange: loadImage
3303
- },
3304
- "inline-image-upload"
3305
- ),
3306
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, children: [
3307
- /* @__PURE__ */ jsx(
3308
- AttachFilled,
3309
- {
3310
- style: {
3311
- fontSize: "16px",
3312
- color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3313
- marginTop: 2
3314
- }
3315
- }
3316
- ),
3317
- !fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3318
- ] }),
3319
- fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3320
- ]
3321
- }
3322
- ) }),
3323
- /* @__PURE__ */ jsx(Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
3324
- Input,
3325
- {
3326
- placeholder: "Alt text",
3327
- appearance: "underline",
3328
- disabled,
3329
- onChange: (_, d) => setAltText(d.value),
3330
- value: altText
3331
- }
3332
- ) }),
3333
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
3334
- /* @__PURE__ */ jsx(Button, { size: "small", disabled: isDisabled, onClick: () => onClick({ altText, src }), children: "Add" }),
3335
- /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
3336
- ] })
3337
- ] }),
3338
- selectedValue === "URL" && /* @__PURE__ */ jsx(
3339
- InsertImageByURL,
3340
- {
3341
- disabled,
3342
- setIsOpen: (open) => setIsOpen(open),
3343
- onClick: (payload) => onClick(payload)
3344
- }
3345
- )
3346
- ]
3347
- }
3348
- )
3349
- ]
3350
- }
3351
- );
3302
+ "inline-image-upload"
3303
+ ),
3304
+ /* @__PURE__ */ jsxs(Stack, { horizontal: true, children: [
3305
+ /* @__PURE__ */ jsx(
3306
+ AttachFilled,
3307
+ {
3308
+ style: {
3309
+ fontSize: "16px",
3310
+ color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3311
+ marginTop: 2
3312
+ }
3313
+ }
3314
+ ),
3315
+ !fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3316
+ ] }),
3317
+ fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3318
+ ]
3319
+ }
3320
+ ) }),
3321
+ /* @__PURE__ */ jsx(Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
3322
+ Input,
3323
+ {
3324
+ placeholder: "Alt text",
3325
+ appearance: "underline",
3326
+ disabled,
3327
+ onChange: (_, d) => setAltText(d.value),
3328
+ value: altText
3329
+ }
3330
+ ) })
3331
+ ] }) }),
3332
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
3333
+ /* @__PURE__ */ jsx(
3334
+ Button,
3335
+ {
3336
+ appearance: "primary",
3337
+ size: "small",
3338
+ disabled: isAddDisabled,
3339
+ onClick: () => onClick({ altText, src }),
3340
+ children: "Add"
3341
+ }
3342
+ ),
3343
+ /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
3344
+ ] })
3345
+ ] }) })
3346
+ }
3347
+ )
3348
+ ] });
3352
3349
  };
3353
3350
  var ImagesPlugin = ({ captionsEnabled }) => {
3354
3351
  const [editor] = useLexicalComposerContext();
@@ -3514,17 +3511,28 @@ var useStyles = makeStyles({
3514
3511
  });
3515
3512
  var InsertInlineImageDialog = ({
3516
3513
  disabled,
3517
- activeEditor
3514
+ activeEditor,
3515
+ open: externalOpen,
3516
+ onClose
3518
3517
  }) => {
3519
3518
  const hasModifier = useRef(false);
3520
3519
  const [src, setSrc] = useState("");
3521
- const [isOpen, setIsOpen] = useState(false);
3520
+ const [internalOpen, setInternalOpen] = useState(false);
3522
3521
  const [altText, setAltText] = useState("");
3523
3522
  const [fileName, setFileName] = useState("");
3524
3523
  const [position, setPosition] = useState("left");
3525
3524
  const styles = useStyles();
3526
3525
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
3527
- const isDisabled = disabled || src === "";
3526
+ const isControlled = externalOpen !== void 0;
3527
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
3528
+ const isAddDisabled = disabled || src === "";
3529
+ const handleClose = () => {
3530
+ setSrc("");
3531
+ setAltText("");
3532
+ setFileName("");
3533
+ if (isControlled) onClose?.();
3534
+ else setInternalOpen(false);
3535
+ };
3528
3536
  const loadImage = (event) => {
3529
3537
  if (disabled) return;
3530
3538
  const files = event.target.files;
@@ -3549,146 +3557,135 @@ var InsertInlineImageDialog = ({
3549
3557
  if (disabled) return;
3550
3558
  const payload = { altText, position, src };
3551
3559
  activeEditor.dispatchCommand(INSERT_INLINE_IMAGE_COMMAND, payload);
3552
- setIsOpen(false);
3553
- setAltText("");
3554
- setSrc("");
3555
- setFileName("");
3560
+ handleClose();
3556
3561
  };
3557
- return /* @__PURE__ */ jsxs(
3558
- Popover,
3559
- {
3560
- trapFocus: true,
3561
- withArrow: true,
3562
- open: disabled ? false : isOpen,
3563
- onOpenChange: (_, data) => {
3564
- if (!disabled) setIsOpen(data.open);
3562
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3563
+ !isControlled && /* @__PURE__ */ jsx(
3564
+ Button,
3565
+ {
3566
+ size: "small",
3567
+ title: "Add Inline Image",
3568
+ disabled,
3569
+ icon: /* @__PURE__ */ jsx(ImageEditRegular, { style: { color: iconColor } }),
3570
+ style: {
3571
+ background: isOpen && !disabled ? "#ebebeb" : "none",
3572
+ border: "none",
3573
+ margin: 2,
3574
+ opacity: disabled ? 0.55 : 1,
3575
+ cursor: disabled ? "not-allowed" : "pointer"
3576
+ },
3577
+ onClick: () => {
3578
+ if (disabled) return;
3579
+ setSrc("");
3580
+ setAltText("");
3581
+ setFileName("");
3582
+ setInternalOpen(true);
3583
+ }
3565
3584
  },
3566
- children: [
3567
- /* @__PURE__ */ jsx(PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
3568
- Button,
3569
- {
3570
- size: "small",
3571
- title: "Add Inline Image",
3572
- disabled,
3573
- icon: /* @__PURE__ */ jsx(ImageEditRegular, { style: { color: iconColor } }),
3574
- style: {
3575
- background: isOpen && !disabled ? "#ebebeb" : "none",
3576
- border: "none",
3577
- margin: 2,
3578
- opacity: disabled ? 0.55 : 1,
3579
- cursor: disabled ? "not-allowed" : "pointer"
3580
- },
3581
- onClick: () => {
3582
- if (disabled) return;
3583
- setIsOpen((prev) => !prev);
3584
- setAltText("");
3585
- setSrc("");
3586
- setFileName("");
3587
- }
3588
- },
3589
- "upload-inline-image"
3590
- ) }),
3591
- /* @__PURE__ */ jsx(
3592
- PopoverSurface,
3593
- {
3594
- style: {
3595
- width: "400px",
3596
- opacity: disabled ? 0.6 : 1,
3597
- pointerEvents: disabled ? "none" : "auto"
3598
- },
3599
- children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 6, padding: "10px 0px 0px 0px" }, children: [
3600
- /* @__PURE__ */ jsx(Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxs(
3601
- "label",
3602
- {
3603
- style: {
3604
- cursor: disabled ? "not-allowed" : "pointer",
3605
- display: "flex",
3606
- alignItems: "center",
3607
- gap: 8,
3608
- opacity: disabled ? 0.75 : 1
3609
- },
3610
- children: [
3585
+ "upload-inline-image"
3586
+ ),
3587
+ /* @__PURE__ */ jsx(
3588
+ Dialog,
3589
+ {
3590
+ open: isOpen,
3591
+ onOpenChange: (_, data) => {
3592
+ if (!data.open) handleClose();
3593
+ },
3594
+ children: /* @__PURE__ */ jsx(DialogSurface, { style: { maxWidth: "440px" }, children: /* @__PURE__ */ jsxs(DialogBody, { children: [
3595
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Insert Inline Image" }),
3596
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
3597
+ /* @__PURE__ */ jsx(Field, { label: "Upload", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxs(
3598
+ "label",
3599
+ {
3600
+ style: {
3601
+ cursor: disabled ? "not-allowed" : "pointer",
3602
+ display: "flex",
3603
+ alignItems: "center",
3604
+ gap: 8,
3605
+ opacity: disabled ? 0.75 : 1
3606
+ },
3607
+ children: [
3608
+ /* @__PURE__ */ jsx(
3609
+ "input",
3610
+ {
3611
+ type: "file",
3612
+ accept: "image/*",
3613
+ style: { display: "none" },
3614
+ disabled,
3615
+ onChange: loadImage
3616
+ },
3617
+ "inline-image-upload"
3618
+ ),
3619
+ /* @__PURE__ */ jsxs(Stack, { horizontal: true, children: [
3611
3620
  /* @__PURE__ */ jsx(
3612
- "input",
3621
+ AttachFilled,
3613
3622
  {
3614
- type: "file",
3615
- accept: "image/*",
3616
- style: { display: "none" },
3617
- disabled,
3618
- onChange: loadImage
3619
- },
3620
- "inline-image-upload"
3621
- ),
3622
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, children: [
3623
- /* @__PURE__ */ jsx(
3624
- AttachFilled,
3625
- {
3626
- style: {
3627
- fontSize: "16px",
3628
- color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3629
- marginTop: 2
3630
- }
3623
+ style: {
3624
+ fontSize: "16px",
3625
+ color: disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#808080",
3626
+ marginTop: 2
3631
3627
  }
3632
- ),
3633
- !fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3634
- ] }),
3635
- fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3636
- ]
3637
- }
3638
- ) }),
3639
- /* @__PURE__ */ jsx(Field, { label: "Position", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxs(
3640
- Dropdown,
3641
- {
3642
- placeholder: "Left Align",
3643
- className: styles.alignDropdown,
3644
- disabled,
3645
- listbox: { style: { width: "120px" } },
3646
- root: { style: { borderBottom: "1px solid black" } },
3647
- children: [
3648
- /* @__PURE__ */ jsx(Option, { text: "full", onClick: () => setPosition("full"), children: "Full" }, "full"),
3649
- /* @__PURE__ */ jsx(Option, { text: "left", onClick: () => setPosition("left"), children: "Left" }, "left"),
3650
- /* @__PURE__ */ jsx(Option, { text: "right", onClick: () => setPosition("right"), children: "Right" }, "right")
3651
- ]
3652
- }
3653
- ) }),
3654
- /* @__PURE__ */ jsx(Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
3655
- Input,
3656
- {
3657
- placeholder: "Alt text",
3658
- appearance: "underline",
3659
- disabled,
3660
- value: altText,
3661
- onChange: (_, d) => setAltText(d.value)
3662
- }
3663
- ) }),
3664
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
3665
- /* @__PURE__ */ jsx(
3666
- Button,
3667
- {
3668
- size: "small",
3669
- disabled: isDisabled,
3670
- onClick: handleOnClick,
3671
- children: "Add"
3672
- },
3673
- "file-inline-upload-btn"
3674
- ),
3675
- /* @__PURE__ */ jsx(
3676
- Button,
3677
- {
3678
- size: "small",
3679
- disabled,
3680
- onClick: () => setIsOpen(false),
3681
- children: "Cancel"
3682
- },
3683
- "file-inline-upload-cancel"
3684
- )
3685
- ] })
3686
- ] })
3687
- }
3688
- )
3689
- ]
3690
- }
3691
- );
3628
+ }
3629
+ ),
3630
+ !fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: "Upload File" })
3631
+ ] }),
3632
+ fileName && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#808080" }, children: fileName })
3633
+ ]
3634
+ }
3635
+ ) }),
3636
+ /* @__PURE__ */ jsx(Field, { label: "Position", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsxs(
3637
+ Dropdown,
3638
+ {
3639
+ placeholder: "Left Align",
3640
+ className: styles.alignDropdown,
3641
+ disabled,
3642
+ listbox: { style: { width: "120px" } },
3643
+ root: { style: { borderBottom: "1px solid black" } },
3644
+ children: [
3645
+ /* @__PURE__ */ jsx(Option, { text: "full", onClick: () => setPosition("full"), children: "Full" }, "full"),
3646
+ /* @__PURE__ */ jsx(Option, { text: "left", onClick: () => setPosition("left"), children: "Left" }, "left"),
3647
+ /* @__PURE__ */ jsx(Option, { text: "right", onClick: () => setPosition("right"), children: "Right" }, "right")
3648
+ ]
3649
+ }
3650
+ ) }),
3651
+ /* @__PURE__ */ jsx(Field, { label: "Alt Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
3652
+ Input,
3653
+ {
3654
+ placeholder: "Alt text",
3655
+ appearance: "underline",
3656
+ disabled,
3657
+ value: altText,
3658
+ onChange: (_, d) => setAltText(d.value)
3659
+ }
3660
+ ) })
3661
+ ] }) }),
3662
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
3663
+ /* @__PURE__ */ jsx(
3664
+ Button,
3665
+ {
3666
+ appearance: "primary",
3667
+ size: "small",
3668
+ disabled: isAddDisabled,
3669
+ onClick: handleOnClick,
3670
+ children: "Add"
3671
+ },
3672
+ "file-inline-upload-btn"
3673
+ ),
3674
+ /* @__PURE__ */ jsx(
3675
+ Button,
3676
+ {
3677
+ size: "small",
3678
+ disabled,
3679
+ onClick: handleClose,
3680
+ children: "Cancel"
3681
+ },
3682
+ "file-inline-upload-cancel"
3683
+ )
3684
+ ] })
3685
+ ] }) })
3686
+ }
3687
+ )
3688
+ ] });
3692
3689
  };
3693
3690
  var InlineImagePlugin = () => {
3694
3691
  const [editor] = useLexicalComposerContext();
@@ -5057,8 +5054,8 @@ function getToolbarGroupsByLevel(level) {
5057
5054
  // ['undo', 'redo', '|'],
5058
5055
  ["Bold", "Italic", "Underline", "|"],
5059
5056
  ["ColorPicker", "|"],
5060
- ["Link", "Table", "|"],
5061
- // ['Image', 'Youtube', 'InlineImage', '|'],
5057
+ ["Link", "|"],
5058
+ ["Insert", "|"],
5062
5059
  ["Heading", "|"],
5063
5060
  ["FontFamily", "|"],
5064
5061
  ["FontSize", "|"],
@@ -5072,9 +5069,8 @@ function getToolbarGroupsByLevel(level) {
5072
5069
  // ['undo', 'redo', '|'],
5073
5070
  ["Bold", "Italic", "Underline", "|"],
5074
5071
  ["ColorPicker", "|"],
5075
- ["Link", "Table", "|"],
5076
- // ['CodeBlock', '|'],
5077
- ["Image", "Youtube", "InlineImage", "|"],
5072
+ ["Link", "|"],
5073
+ ["Insert", "|"],
5078
5074
  ["Heading", "|"],
5079
5075
  ["FontFamily", "|"],
5080
5076
  ["FontSize", "|"],
@@ -5884,105 +5880,135 @@ var FontSizePlugin = ({ disabled }) => {
5884
5880
  "fontsize"
5885
5881
  ) });
5886
5882
  };
5887
- var InsertLinkPlugin = ({ disabled }) => {
5883
+ var VERBATIM_LINK_RE = /^https?:\/\/|^mailto:|^tel:|^#|^\//i;
5884
+ function getLinkValidationMessage(raw) {
5885
+ const trimmed = raw.trim();
5886
+ if (!trimmed) return void 0;
5887
+ if (/\s/.test(trimmed)) return "URL cannot contain spaces";
5888
+ if (!VERBATIM_LINK_RE.test(trimmed) && !trimmed.includes(".")) {
5889
+ return "Enter a valid URL (e.g. example.com)";
5890
+ }
5891
+ return void 0;
5892
+ }
5893
+ var InsertLinkPlugin = ({
5894
+ disabled,
5895
+ open: externalOpen,
5896
+ onClose
5897
+ }) => {
5888
5898
  const [editor] = useLexicalComposerContext();
5889
- const [isOpen, setIsOpen] = useState(false);
5899
+ const [internalOpen, setInternalOpen] = useState(false);
5890
5900
  const [text, setText] = useState("");
5891
5901
  const [link, setLink] = useState("");
5892
5902
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
5903
+ const isControlled = externalOpen !== void 0;
5904
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
5905
+ const linkError = getLinkValidationMessage(link);
5906
+ const handleClose = () => {
5907
+ setText("");
5908
+ setLink("");
5909
+ if (isControlled) onClose?.();
5910
+ else setInternalOpen(false);
5911
+ };
5893
5912
  const insertLink = (text2, link2) => {
5894
5913
  if (disabled) return;
5914
+ if (getLinkValidationMessage(link2)) return;
5915
+ const trimmedLink = link2.trim();
5916
+ const href = VERBATIM_LINK_RE.test(trimmedLink) ? trimmedLink : `https://${trimmedLink}`;
5895
5917
  editor.update(() => {
5896
- setText("");
5897
- setLink("");
5898
5918
  const selection = $getSelection();
5899
5919
  if ($isRangeSelection(selection)) {
5900
5920
  const textNode = new TextNode(text2);
5901
- const linkNode = $createLinkNode(link2.startsWith("http") ? link2 : `https://${link2}`);
5921
+ const linkNode = $createLinkNode(href);
5902
5922
  linkNode.append(textNode);
5903
5923
  selection.insertNodes([linkNode]);
5904
5924
  }
5905
- setIsOpen(false);
5906
5925
  });
5926
+ handleClose();
5907
5927
  };
5908
- return /* @__PURE__ */ jsxs(
5909
- Popover,
5910
- {
5911
- trapFocus: true,
5912
- withArrow: true,
5913
- open: disabled ? false : isOpen,
5914
- onOpenChange: (_, data) => {
5915
- if (!disabled) setIsOpen(data.open);
5928
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
5929
+ !isControlled && /* @__PURE__ */ jsx(
5930
+ Button,
5931
+ {
5932
+ size: "small",
5933
+ title: "Add link",
5934
+ disabled,
5935
+ icon: /* @__PURE__ */ jsx(LinkAddRegular, { style: { color: iconColor } }),
5936
+ style: {
5937
+ background: isOpen && !disabled ? "#ebebeb" : "none",
5938
+ border: "none",
5939
+ margin: 2,
5940
+ opacity: disabled ? 0.55 : 1,
5941
+ cursor: disabled ? "not-allowed" : "pointer"
5942
+ },
5943
+ onClick: () => {
5944
+ if (disabled) return;
5945
+ setInternalOpen((prev) => !prev);
5946
+ }
5916
5947
  },
5917
- children: [
5918
- /* @__PURE__ */ jsx(PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
5919
- Button,
5920
- {
5921
- size: "small",
5922
- title: "Add link",
5923
- disabled,
5924
- icon: /* @__PURE__ */ jsx(LinkAddRegular, { style: { color: iconColor } }),
5925
- style: {
5926
- background: isOpen && !disabled ? "#ebebeb" : "none",
5927
- border: "none",
5928
- margin: 2,
5929
- opacity: disabled ? 0.55 : 1,
5930
- cursor: disabled ? "not-allowed" : "pointer"
5931
- },
5932
- onClick: () => {
5933
- if (!disabled) setIsOpen((prev) => !prev);
5934
- }
5935
- },
5936
- "upload-link"
5937
- ) }),
5938
- /* @__PURE__ */ jsx(
5939
- PopoverSurface,
5940
- {
5941
- style: {
5942
- width: "270px",
5943
- opacity: disabled ? 0.6 : 1,
5944
- pointerEvents: disabled ? "none" : "auto"
5945
- },
5946
- children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, children: [
5947
- /* @__PURE__ */ jsx(Field, { label: "Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
5948
- Input,
5949
- {
5950
- autoFocus: !disabled,
5951
- value: text,
5952
- appearance: "underline",
5953
- placeholder: "Text",
5954
- disabled,
5955
- onChange: (_, v) => setText(v.value)
5956
- }
5957
- ) }),
5958
- /* @__PURE__ */ jsx(Field, { label: "Link", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
5959
- Input,
5960
- {
5961
- value: link,
5962
- appearance: "underline",
5963
- placeholder: "Link",
5964
- disabled,
5965
- onChange: (_, v) => setLink(v.value)
5966
- }
5967
- ) }),
5968
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
5969
- /* @__PURE__ */ jsx(
5970
- Button,
5948
+ "upload-link"
5949
+ ),
5950
+ /* @__PURE__ */ jsx(
5951
+ Dialog,
5952
+ {
5953
+ open: isOpen,
5954
+ onOpenChange: (_, data) => {
5955
+ if (!data.open) handleClose();
5956
+ },
5957
+ children: /* @__PURE__ */ jsx(DialogSurface, { style: { maxWidth: "380px" }, children: /* @__PURE__ */ jsxs(DialogBody, { children: [
5958
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Insert Link" }),
5959
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
5960
+ /* @__PURE__ */ jsx(Field, { label: "Text", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
5961
+ Input,
5962
+ {
5963
+ autoFocus: !disabled,
5964
+ value: text,
5965
+ appearance: "underline",
5966
+ placeholder: "Text",
5967
+ disabled,
5968
+ onChange: (_, v) => setText(v.value)
5969
+ }
5970
+ ) }),
5971
+ /* @__PURE__ */ jsx(
5972
+ Field,
5973
+ {
5974
+ label: "Link",
5975
+ orientation: "horizontal",
5976
+ size: "small",
5977
+ validationState: linkError ? "error" : "none",
5978
+ validationMessage: linkError,
5979
+ children: /* @__PURE__ */ jsx(
5980
+ Input,
5971
5981
  {
5972
- size: "small",
5973
- disabled: disabled || !text || !link,
5974
- onClick: () => insertLink(text, link),
5975
- children: "Add"
5982
+ value: link,
5983
+ appearance: "underline",
5984
+ placeholder: "Link",
5985
+ disabled,
5986
+ onChange: (_, v) => setLink(v.value),
5987
+ onKeyDown: (e) => {
5988
+ if (e.key === "Enter" && text && link && !linkError) insertLink(text, link);
5989
+ }
5976
5990
  }
5977
- ),
5978
- /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
5979
- ] })
5980
- ] })
5981
- }
5982
- )
5983
- ]
5984
- }
5985
- );
5991
+ )
5992
+ }
5993
+ )
5994
+ ] }) }),
5995
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
5996
+ /* @__PURE__ */ jsx(
5997
+ Button,
5998
+ {
5999
+ appearance: "primary",
6000
+ size: "small",
6001
+ disabled: disabled || !text || !link || !!linkError,
6002
+ onClick: () => insertLink(text, link),
6003
+ children: "Add"
6004
+ }
6005
+ ),
6006
+ /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
6007
+ ] })
6008
+ ] }) })
6009
+ }
6010
+ )
6011
+ ] });
5986
6012
  };
5987
6013
  function PageSetupPlugin({ disabled, value, onChange }) {
5988
6014
  const sizeLabel = value.size === "pageless" ? "Pageless" : PAGE_SIZE_OPTIONS.find((o) => o.key === value.size)?.label ?? "Pageless";
@@ -6038,194 +6064,280 @@ function PageSetupPlugin({ disabled, value, onChange }) {
6038
6064
  }
6039
6065
  );
6040
6066
  }
6041
- var TableItemPlugin = ({ disabled }) => {
6067
+ var MAX_ROWS = 50;
6068
+ var MAX_COLS = 50;
6069
+ var TableItemPlugin = ({
6070
+ disabled,
6071
+ open: externalOpen,
6072
+ onClose
6073
+ }) => {
6042
6074
  const [editor] = useLexicalComposerContext();
6043
6075
  const [columns, setColumns] = useState("");
6044
6076
  const [rows, setRows] = useState("");
6045
- const [isOpen, setIsOpen] = useState(false);
6077
+ const [internalOpen, setInternalOpen] = useState(false);
6078
+ const [rowError, setRowError] = useState("");
6079
+ const [colError, setColError] = useState("");
6080
+ const isControlled = externalOpen !== void 0;
6081
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
6046
6082
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#333333";
6083
+ const handleClose = () => {
6084
+ setRows("");
6085
+ setColumns("");
6086
+ setRowError("");
6087
+ setColError("");
6088
+ if (isControlled) onClose?.();
6089
+ else setInternalOpen(false);
6090
+ };
6091
+ const onRowsChange = (val) => {
6092
+ const clean = val.replace(/\D/g, "");
6093
+ setRows(clean);
6094
+ const n = Number(clean);
6095
+ if (clean && n > MAX_ROWS) setRowError(`Maximum ${MAX_ROWS} rows allowed`);
6096
+ else setRowError("");
6097
+ };
6098
+ const onColsChange = (val) => {
6099
+ const clean = val.replace(/\D/g, "");
6100
+ setColumns(clean);
6101
+ const n = Number(clean);
6102
+ if (clean && n > MAX_COLS) setColError(`Maximum ${MAX_COLS} columns allowed`);
6103
+ else setColError("");
6104
+ };
6047
6105
  const onAddTable = () => {
6048
6106
  if (disabled) return;
6049
6107
  const row = Number(rows);
6050
6108
  const col = Number(columns);
6051
6109
  if (!row || !col) return;
6110
+ if (row > MAX_ROWS || col > MAX_COLS) return;
6052
6111
  editor.update(() => {
6053
6112
  const tableNode = $createTableNodeWithDimensions(row, col, true);
6054
6113
  $insertNodeToNearestRoot(tableNode);
6055
6114
  });
6056
- setRows("");
6057
- setColumns("");
6058
- setIsOpen(false);
6115
+ handleClose();
6059
6116
  };
6060
- return /* @__PURE__ */ jsxs(
6061
- Popover,
6062
- {
6063
- trapFocus: true,
6064
- withArrow: true,
6065
- open: disabled ? false : isOpen,
6066
- onOpenChange: (_, data) => {
6067
- if (!disabled) setIsOpen(data.open);
6117
+ const isAddDisabled = disabled || !rows || !columns || !!rowError || !!colError;
6118
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6119
+ !isControlled && /* @__PURE__ */ jsx(
6120
+ Button,
6121
+ {
6122
+ size: "small",
6123
+ title: "Add table",
6124
+ disabled,
6125
+ icon: /* @__PURE__ */ jsx(TableAddRegular, { style: { color: iconColor } }),
6126
+ style: {
6127
+ background: isOpen && !disabled ? "#ebebeb" : "none",
6128
+ border: "none",
6129
+ margin: 2,
6130
+ opacity: disabled ? 0.55 : 1,
6131
+ cursor: disabled ? "not-allowed" : "pointer"
6132
+ },
6133
+ onClick: () => {
6134
+ if (disabled) return;
6135
+ setRows("");
6136
+ setColumns("");
6137
+ setRowError("");
6138
+ setColError("");
6139
+ setInternalOpen(true);
6140
+ }
6068
6141
  },
6069
- children: [
6070
- /* @__PURE__ */ jsx(PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
6071
- Button,
6072
- {
6073
- size: "small",
6074
- title: "Add table",
6075
- disabled,
6076
- icon: /* @__PURE__ */ jsx(TableAddRegular, { style: { color: iconColor } }),
6077
- style: {
6078
- background: isOpen && !disabled ? "#ebebeb" : "none",
6079
- border: "none",
6080
- margin: 2,
6081
- opacity: disabled ? 0.55 : 1,
6082
- cursor: disabled ? "not-allowed" : "pointer"
6083
- },
6084
- onClick: () => {
6085
- if (disabled) return;
6086
- setIsOpen((prev) => !prev);
6087
- setRows("");
6088
- setColumns("");
6089
- }
6090
- },
6091
- "insert-table-nodes"
6092
- ) }),
6093
- /* @__PURE__ */ jsx(
6094
- PopoverSurface,
6095
- {
6096
- style: {
6097
- width: "270px",
6098
- opacity: disabled ? 0.6 : 1,
6099
- pointerEvents: disabled ? "none" : "auto"
6100
- },
6101
- children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, children: [
6102
- /* @__PURE__ */ jsx(Field, { label: "Rows", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
6103
- Input,
6104
- {
6105
- autoFocus: !disabled,
6106
- type: "number",
6107
- min: 1,
6108
- value: rows,
6109
- placeholder: "Rows",
6110
- appearance: "underline",
6111
- disabled,
6112
- input: { style: { textAlign: "left" } },
6113
- onChange: (_, v) => setRows(v.value.replace(/\D/g, ""))
6114
- }
6115
- ) }),
6116
- /* @__PURE__ */ jsx(Field, { label: "Columns", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
6117
- Input,
6118
- {
6119
- type: "number",
6120
- min: 1,
6121
- value: columns,
6122
- placeholder: "Columns",
6123
- appearance: "underline",
6124
- disabled,
6125
- input: { style: { textAlign: "left" } },
6126
- onChange: (_, v) => setColumns(v.value.replace(/\D/g, ""))
6127
- }
6128
- ) }),
6129
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
6130
- /* @__PURE__ */ jsx(
6131
- Button,
6142
+ "insert-table-nodes"
6143
+ ),
6144
+ /* @__PURE__ */ jsx(
6145
+ Dialog,
6146
+ {
6147
+ open: isOpen,
6148
+ onOpenChange: (_, data) => {
6149
+ if (!data.open) handleClose();
6150
+ },
6151
+ children: /* @__PURE__ */ jsx(DialogSurface, { style: { maxWidth: "380px" }, children: /* @__PURE__ */ jsxs(DialogBody, { children: [
6152
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Insert Table" }),
6153
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
6154
+ /* @__PURE__ */ jsx(
6155
+ Field,
6156
+ {
6157
+ label: "Rows",
6158
+ orientation: "horizontal",
6159
+ size: "small",
6160
+ validationMessage: rowError || void 0,
6161
+ validationState: rowError ? "error" : "none",
6162
+ children: /* @__PURE__ */ jsx(
6163
+ Input,
6132
6164
  {
6133
- size: "small",
6134
- appearance: "primary",
6135
- disabled: disabled || !rows || !columns,
6136
- onClick: onAddTable,
6137
- children: "Add"
6165
+ autoFocus: !disabled,
6166
+ type: "number",
6167
+ min: 1,
6168
+ max: MAX_ROWS,
6169
+ value: rows,
6170
+ placeholder: "Rows",
6171
+ appearance: "underline",
6172
+ disabled,
6173
+ input: { style: { textAlign: "left" } },
6174
+ onChange: (_, v) => onRowsChange(v.value)
6138
6175
  }
6139
- ),
6140
- /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
6141
- ] })
6142
- ] })
6143
- }
6144
- )
6145
- ]
6146
- }
6147
- );
6176
+ )
6177
+ }
6178
+ ),
6179
+ /* @__PURE__ */ jsx(
6180
+ Field,
6181
+ {
6182
+ label: "Columns",
6183
+ orientation: "horizontal",
6184
+ size: "small",
6185
+ validationMessage: colError || void 0,
6186
+ validationState: colError ? "error" : "none",
6187
+ children: /* @__PURE__ */ jsx(
6188
+ Input,
6189
+ {
6190
+ type: "number",
6191
+ min: 1,
6192
+ max: MAX_COLS,
6193
+ value: columns,
6194
+ placeholder: "Columns",
6195
+ appearance: "underline",
6196
+ disabled,
6197
+ input: { style: { textAlign: "left" } },
6198
+ onChange: (_, v) => onColsChange(v.value)
6199
+ }
6200
+ )
6201
+ }
6202
+ )
6203
+ ] }) }),
6204
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
6205
+ /* @__PURE__ */ jsx(
6206
+ Button,
6207
+ {
6208
+ appearance: "primary",
6209
+ size: "small",
6210
+ disabled: isAddDisabled,
6211
+ onClick: onAddTable,
6212
+ children: "Add"
6213
+ }
6214
+ ),
6215
+ /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
6216
+ ] })
6217
+ ] }) })
6218
+ }
6219
+ )
6220
+ ] });
6148
6221
  };
6149
- var YoutubeUploadPlugin = ({ disabled }) => {
6222
+ function extractYouTubeId(url) {
6223
+ const trimmed = url.trim();
6224
+ if (/^[\w-]{11}$/.test(trimmed)) return trimmed;
6225
+ const match = /(?:youtu\.be\/|youtube\.com\/(?:watch\?v=|embed\/|v\/|shorts\/|live\/|u\/\w\/))([^#&?]{11})/.exec(trimmed);
6226
+ return match ? match[1] : null;
6227
+ }
6228
+ var YoutubeUploadPlugin = ({
6229
+ disabled,
6230
+ open: externalOpen,
6231
+ onClose
6232
+ }) => {
6150
6233
  const [url, setURL] = useState("");
6151
- const [isOpen, setIsOpen] = useState(false);
6234
+ const [urlError, setUrlError] = useState("");
6235
+ const [internalOpen, setInternalOpen] = useState(false);
6152
6236
  const [editor] = useLexicalComposerContext();
6153
6237
  const iconColor = disabled ? "var(--colorNeutralForegroundDisabled, #A6A6A6)" : "#424242";
6238
+ const isControlled = externalOpen !== void 0;
6239
+ const isOpen = isControlled ? !!externalOpen && !disabled : internalOpen && !disabled;
6240
+ const handleClose = () => {
6241
+ setURL("");
6242
+ setUrlError("");
6243
+ if (isControlled) onClose?.();
6244
+ else setInternalOpen(false);
6245
+ };
6154
6246
  const onHandleEmbeded = () => {
6155
6247
  if (disabled) return;
6156
6248
  if (!url) return;
6157
- const match = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/.exec(url);
6158
- const id = match && match[2]?.length === 11 ? match[2] : null;
6159
- if (!id) return;
6249
+ const id = extractYouTubeId(url);
6250
+ if (!id) {
6251
+ setUrlError("Invalid YouTube URL. Supported: watch?v=, youtu.be/, /shorts/, /live/");
6252
+ return;
6253
+ }
6254
+ setUrlError("");
6160
6255
  editor.update(() => {
6161
6256
  const node = $createYouTubeNode(id);
6162
6257
  $insertNodes([node]);
6163
6258
  });
6164
- setURL("");
6165
- setIsOpen(false);
6259
+ handleClose();
6166
6260
  };
6167
- return /* @__PURE__ */ jsxs(
6168
- Popover,
6169
- {
6170
- trapFocus: true,
6171
- withArrow: true,
6172
- open: disabled ? false : isOpen,
6173
- onOpenChange: (_, data) => {
6174
- if (!disabled) setIsOpen(data.open);
6261
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6262
+ !isControlled && /* @__PURE__ */ jsx(
6263
+ Button,
6264
+ {
6265
+ title: "Add youtube URL",
6266
+ size: "small",
6267
+ disabled,
6268
+ icon: /* @__PURE__ */ jsx(VideoClipRegular, { style: { color: iconColor } }),
6269
+ style: {
6270
+ background: isOpen && !disabled ? "#ebebeb" : "none",
6271
+ border: "none",
6272
+ margin: 2,
6273
+ opacity: disabled ? 0.55 : 1,
6274
+ cursor: disabled ? "not-allowed" : "pointer"
6275
+ },
6276
+ onClick: () => {
6277
+ if (disabled) return;
6278
+ setURL("");
6279
+ setUrlError("");
6280
+ setInternalOpen(true);
6281
+ }
6175
6282
  },
6176
- children: [
6177
- /* @__PURE__ */ jsx(PopoverTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
6178
- Button,
6179
- {
6180
- title: "Add youtube URL",
6181
- size: "small",
6182
- disabled,
6183
- icon: /* @__PURE__ */ jsx(VideoClipRegular, { style: { color: iconColor } }),
6184
- style: {
6185
- background: isOpen && !disabled ? "#ebebeb" : "none",
6186
- border: "none",
6187
- margin: 2,
6188
- opacity: disabled ? 0.55 : 1,
6189
- cursor: disabled ? "not-allowed" : "pointer"
6190
- },
6191
- onClick: () => {
6192
- if (disabled) return;
6193
- setIsOpen((prev) => !prev);
6194
- setURL("");
6195
- }
6196
- },
6197
- "upload-video"
6198
- ) }),
6199
- /* @__PURE__ */ jsx(
6200
- PopoverSurface,
6201
- {
6202
- style: {
6203
- width: "270px",
6204
- opacity: disabled ? 0.6 : 1,
6205
- pointerEvents: disabled ? "none" : "auto"
6206
- },
6207
- children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, children: [
6208
- /* @__PURE__ */ jsx(Field, { label: "URL", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
6209
- Input,
6210
- {
6211
- autoFocus: !disabled,
6212
- disabled,
6213
- value: url,
6214
- appearance: "underline",
6215
- placeholder: "Add Youtube video URL",
6216
- onChange: (_, v) => setURL(v.value)
6217
- }
6218
- ) }),
6219
- /* @__PURE__ */ jsxs(Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
6220
- /* @__PURE__ */ jsx(Button, { size: "small", disabled: disabled || !url, onClick: onHandleEmbeded, children: "Add" }),
6221
- /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: () => setIsOpen(false), children: "Cancel" })
6222
- ] })
6223
- ] })
6224
- }
6225
- )
6226
- ]
6227
- }
6228
- );
6283
+ "upload-video"
6284
+ ),
6285
+ /* @__PURE__ */ jsx(
6286
+ Dialog,
6287
+ {
6288
+ open: isOpen,
6289
+ onOpenChange: (_, data) => {
6290
+ if (!data.open) handleClose();
6291
+ },
6292
+ children: /* @__PURE__ */ jsx(DialogSurface, { style: { maxWidth: "420px" }, children: /* @__PURE__ */ jsxs(DialogBody, { children: [
6293
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Insert YouTube Video" }),
6294
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, style: { paddingTop: 8 }, children: [
6295
+ /* @__PURE__ */ jsx(
6296
+ Field,
6297
+ {
6298
+ label: "URL",
6299
+ orientation: "horizontal",
6300
+ size: "small",
6301
+ validationState: urlError ? "error" : "none",
6302
+ validationMessage: urlError || void 0,
6303
+ children: /* @__PURE__ */ jsx(
6304
+ Input,
6305
+ {
6306
+ autoFocus: !disabled,
6307
+ disabled,
6308
+ value: url,
6309
+ appearance: "underline",
6310
+ placeholder: "Paste YouTube URL or video ID\u2026",
6311
+ onChange: (_, v) => {
6312
+ setURL(v.value);
6313
+ if (urlError) setUrlError("");
6314
+ },
6315
+ onKeyDown: (e) => {
6316
+ if (e.key === "Enter") onHandleEmbeded();
6317
+ }
6318
+ }
6319
+ )
6320
+ }
6321
+ ),
6322
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: "#94a3b8", lineHeight: 1.5 }, children: "Supports: youtube.com/watch?v=\u2026, youtu.be/\u2026, /shorts/\u2026, /live/\u2026" })
6323
+ ] }) }),
6324
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
6325
+ /* @__PURE__ */ jsx(
6326
+ Button,
6327
+ {
6328
+ appearance: "primary",
6329
+ size: "small",
6330
+ disabled: disabled || !url,
6331
+ onClick: onHandleEmbeded,
6332
+ children: "Add"
6333
+ }
6334
+ ),
6335
+ /* @__PURE__ */ jsx(Button, { size: "small", disabled, onClick: handleClose, children: "Cancel" })
6336
+ ] })
6337
+ ] }) })
6338
+ }
6339
+ )
6340
+ ] });
6229
6341
  };
6230
6342
  var useStyles4 = makeStyles({
6231
6343
  dropdown: {
@@ -6250,6 +6362,7 @@ var ALLOWED_TOKENS = {
6250
6362
  Image: true,
6251
6363
  InlineImage: true,
6252
6364
  Youtube: true,
6365
+ Insert: true,
6253
6366
  Heading: true,
6254
6367
  FontFamily: true,
6255
6368
  FontSize: true,
@@ -6281,6 +6394,7 @@ var ToolBarPlugins = (props) => {
6281
6394
  const [isLowercase, setIsLowercase] = useState(false);
6282
6395
  const [isCapitalize, setIsCapitalize] = useState(false);
6283
6396
  const [alignment, setAlignment] = useState("left");
6397
+ const [activeInsertDialog, setActiveInsertDialog] = useState(null);
6284
6398
  const lastSelectionRef = React9__default.useRef(null);
6285
6399
  const presetGroups = getToolbarGroupsByLevel(props.level);
6286
6400
  const pluginGroups = useMemo(() => sanitizePluginGroups(presetGroups), [presetGroups]);
@@ -6526,6 +6640,7 @@ var ToolBarPlugins = (props) => {
6526
6640
  marginRight: 8,
6527
6641
  verticalAlign: "middle"
6528
6642
  };
6643
+ const isDisabled = !isEditable || !!props.readOnly;
6529
6644
  switch (token) {
6530
6645
  case "Bold":
6531
6646
  return /* @__PURE__ */ jsx(
@@ -6589,6 +6704,95 @@ var ToolBarPlugins = (props) => {
6589
6704
  );
6590
6705
  case "Youtube":
6591
6706
  return /* @__PURE__ */ jsx(YoutubeUploadPlugin, { disabled: !isEditable || props.readOnly }, key);
6707
+ case "Insert": {
6708
+ const menuIconColor = isDisabled ? fgDisabled : fg;
6709
+ return /* @__PURE__ */ jsxs(React9__default.Fragment, { children: [
6710
+ /* @__PURE__ */ jsxs(Menu, { children: [
6711
+ /* @__PURE__ */ jsx(MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
6712
+ Button,
6713
+ {
6714
+ size: "small",
6715
+ disabled: isDisabled,
6716
+ icon: /* @__PURE__ */ jsx(AddRegular, { style: { color: menuIconColor } }),
6717
+ style: {
6718
+ ...getButtonStyle(false),
6719
+ gap: 4,
6720
+ paddingInline: 8
6721
+ },
6722
+ children: "Insert"
6723
+ }
6724
+ ) }),
6725
+ /* @__PURE__ */ jsx(MenuPopover, { children: /* @__PURE__ */ jsxs(MenuList, { children: [
6726
+ /* @__PURE__ */ jsx(
6727
+ MenuItem,
6728
+ {
6729
+ icon: /* @__PURE__ */ jsx(TableAddRegular, { style: { color: menuIconColor } }),
6730
+ onClick: () => !isDisabled && setActiveInsertDialog("table"),
6731
+ children: "Table"
6732
+ }
6733
+ ),
6734
+ /* @__PURE__ */ jsx(
6735
+ MenuItem,
6736
+ {
6737
+ icon: /* @__PURE__ */ jsx(ImageAddRegular, { style: { color: menuIconColor } }),
6738
+ onClick: () => !isDisabled && setActiveInsertDialog("image"),
6739
+ children: "Image"
6740
+ }
6741
+ ),
6742
+ /* @__PURE__ */ jsx(
6743
+ MenuItem,
6744
+ {
6745
+ icon: /* @__PURE__ */ jsx(ImageEditRegular, { style: { color: menuIconColor } }),
6746
+ onClick: () => !isDisabled && setActiveInsertDialog("inlineImage"),
6747
+ children: "Inline Image"
6748
+ }
6749
+ ),
6750
+ /* @__PURE__ */ jsx(
6751
+ MenuItem,
6752
+ {
6753
+ icon: /* @__PURE__ */ jsx(VideoClipRegular, { style: { color: menuIconColor } }),
6754
+ onClick: () => !isDisabled && setActiveInsertDialog("youtube"),
6755
+ children: "YouTube"
6756
+ }
6757
+ )
6758
+ ] }) })
6759
+ ] }),
6760
+ /* @__PURE__ */ jsx(
6761
+ TableItemPlugin,
6762
+ {
6763
+ disabled: isDisabled,
6764
+ open: activeInsertDialog === "table",
6765
+ onClose: () => setActiveInsertDialog(null)
6766
+ }
6767
+ ),
6768
+ /* @__PURE__ */ jsx(
6769
+ InsertImageDialog,
6770
+ {
6771
+ activeEditor: editor,
6772
+ disabled: isDisabled,
6773
+ open: activeInsertDialog === "image",
6774
+ onClose: () => setActiveInsertDialog(null)
6775
+ }
6776
+ ),
6777
+ /* @__PURE__ */ jsx(
6778
+ InsertInlineImageDialog,
6779
+ {
6780
+ activeEditor: editor,
6781
+ disabled: isDisabled,
6782
+ open: activeInsertDialog === "inlineImage",
6783
+ onClose: () => setActiveInsertDialog(null)
6784
+ }
6785
+ ),
6786
+ /* @__PURE__ */ jsx(
6787
+ YoutubeUploadPlugin,
6788
+ {
6789
+ disabled: isDisabled,
6790
+ open: activeInsertDialog === "youtube",
6791
+ onClose: () => setActiveInsertDialog(null)
6792
+ }
6793
+ )
6794
+ ] }, key);
6795
+ }
6592
6796
  case "Heading": {
6593
6797
  const headingLabel = selectNodeType === "paragraph" ? "Normal" : HEADING_OPTION.find((h) => h.key === selectNodeType)?.text ?? selectNodeType;
6594
6798
  return /* @__PURE__ */ jsxs(
@@ -6984,7 +7188,9 @@ function BrowserSpellCheckPlugin({ enabled }) {
6984
7188
  }, [editor, enabled]);
6985
7189
  return null;
6986
7190
  }
6987
- function WordCountPlugin({ onCountChange }) {
7191
+ function WordCountPlugin({
7192
+ onCountChange
7193
+ }) {
6988
7194
  const [editor] = useLexicalComposerContext();
6989
7195
  useEffect(() => {
6990
7196
  return editor.registerUpdateListener(({ editorState }) => {
@@ -6997,7 +7203,9 @@ function WordCountPlugin({ onCountChange }) {
6997
7203
  }, [editor, onCountChange]);
6998
7204
  return null;
6999
7205
  }
7000
- function CharCountPlugin({ onCountChange }) {
7206
+ function CharCountPlugin({
7207
+ onCountChange
7208
+ }) {
7001
7209
  const [editor] = useLexicalComposerContext();
7002
7210
  useEffect(() => {
7003
7211
  return editor.registerUpdateListener(({ editorState }) => {
@@ -7081,7 +7289,10 @@ function _adaptRawSpell(data, text) {
7081
7289
  }
7082
7290
  const rawGrammar = data.grammar_correction ?? data.improved_text;
7083
7291
  const grammarCorrection = rawGrammar && rawGrammar.trim() !== text.trim() ? rawGrammar.trim() : void 0;
7084
- return { issues: issues.sort((a, b) => a.offset - b.offset), grammarCorrection };
7292
+ return {
7293
+ issues: issues.sort((a, b) => a.offset - b.offset),
7294
+ grammarCorrection
7295
+ };
7085
7296
  }
7086
7297
  function _adaptRawSuggest(data) {
7087
7298
  if (!data) return null;
@@ -7136,359 +7347,385 @@ function _makeQueryFn(fn) {
7136
7347
  };
7137
7348
  };
7138
7349
  }
7139
- var ContentEditorComponent = forwardRef(
7140
- (props, ref) => {
7141
- const isReadOnly = !!props.readOnly;
7142
- const resolvedSpellCheck = React9__default.useMemo(
7143
- () => props.spellCheckFn ? _makeSpellCheckFn(props.spellCheckFn) : props.useSpellCheck,
7144
- // eslint-disable-next-line react-hooks/exhaustive-deps
7145
- [props.spellCheckFn, props.useSpellCheck]
7146
- );
7147
- const resolvedQuery = React9__default.useMemo(
7148
- () => props.suggestFn ? _makeQueryFn(props.suggestFn) : props.useQuery,
7149
- // eslint-disable-next-line react-hooks/exhaustive-deps
7150
- [props.suggestFn, props.useQuery]
7151
- );
7152
- const [floatingAnchorElem, setFloatingAnchorElem] = useState(null);
7153
- const [isLinkEditMode, setIsLinkEditMode] = useState(false);
7154
- const [wordCount, setWordCount] = useState(0);
7155
- const handleWordCount = useCallback((count) => setWordCount(count), []);
7156
- const [charCount, setCharCount] = useState(0);
7157
- const handleCharCount = useCallback((count) => setCharCount(count), []);
7158
- const [refErrors, setRefErrors] = useState([]);
7159
- const [pageSetup, setPageSetup] = useState(DEFAULT_PAGE_SETUP);
7160
- const pageCanvas = resolvePageCanvasMetrics(pageSetup);
7161
- const contentEditableDomRef = useRef(null);
7162
- const previousOverLimitRef = useRef(false);
7163
- const focusedRef = useRef(false);
7164
- const setFocused = (focused) => {
7165
- focusedRef.current = focused;
7166
- };
7167
- const containerRef = useRef(null);
7168
- const onAnchorRef = (elem) => {
7169
- if (elem) setFloatingAnchorElem(elem);
7170
- };
7171
- const initialConfig = {
7172
- namespace: props.namespace,
7173
- theme,
7174
- onError: () => {
7175
- },
7176
- nodes: [
7177
- HeadingNode,
7178
- QuoteNode,
7179
- CodeHighlightNode,
7180
- CodeNode,
7181
- ListNode,
7182
- ListItemNode,
7183
- LinkNode,
7184
- AutoLinkNode,
7185
- TableNode,
7186
- TableRowNode,
7187
- TableCellNode,
7188
- ImageNode,
7189
- InlineImageNode,
7190
- YouTubeNode,
7191
- PageBreakNode,
7192
- AutocompleteNode,
7193
- SpellErrorNode,
7194
- HtmlBlockNode
7195
- ]
7196
- };
7197
- const EditorStyles = mergeStyleSets({
7198
- editorPlaceholder: {
7199
- color: "var(--colorNeutralForeground3, grey)",
7200
- position: "absolute",
7201
- top: props.level !== "none" /* None */ ? "17px" : "27px",
7202
- left: pageCanvas.paddingPx,
7203
- right: pageCanvas.paddingPx,
7204
- fontSize: "14px",
7205
- pointerEvents: "none",
7206
- userSelect: "none"
7207
- },
7208
- contentEditor: {
7209
- zIndex: 0,
7210
- flex: "auto",
7211
- outline: "none",
7212
- overflow: "auto",
7213
- marginTop: "0px",
7214
- position: "relative",
7215
- background: "var(--colorNeutralBackground1, #ffffff)",
7216
- justifyContent: "center",
7217
- height: props.contentHeight ?? "100%",
7218
- ...isReadOnly && {
7219
- cursor: "not-allowed",
7220
- opacity: 0.75,
7221
- userSelect: "text"
7222
- }
7223
- }
7224
- });
7225
- const urlRegExp = new RegExp(
7226
- /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/
7227
- );
7228
- const validateUrl = (url) => url === "https://" || urlRegExp.test(url);
7229
- const handleReadOnlyClickCapture = (e) => {
7230
- if (!isReadOnly) return;
7231
- const target = e.target;
7232
- const anchor = target?.closest?.("a");
7233
- if (anchor) {
7234
- e.preventDefault();
7235
- e.stopPropagation();
7350
+ var ContentEditorComponent = forwardRef((props, ref) => {
7351
+ const isReadOnly = !!props.readOnly;
7352
+ const resolvedSpellCheck = React9__default.useMemo(
7353
+ () => props.spellCheckFn ? _makeSpellCheckFn(props.spellCheckFn) : props.useSpellCheck,
7354
+ // eslint-disable-next-line react-hooks/exhaustive-deps
7355
+ [props.spellCheckFn, props.useSpellCheck]
7356
+ );
7357
+ const resolvedQuery = React9__default.useMemo(
7358
+ () => props.suggestFn ? _makeQueryFn(props.suggestFn) : props.useQuery,
7359
+ // eslint-disable-next-line react-hooks/exhaustive-deps
7360
+ [props.suggestFn, props.useQuery]
7361
+ );
7362
+ const [floatingAnchorElem, setFloatingAnchorElem] = useState(null);
7363
+ const [isLinkEditMode, setIsLinkEditMode] = useState(false);
7364
+ const [wordCount, setWordCount] = useState(0);
7365
+ const handleWordCount = useCallback(
7366
+ (count) => setWordCount(count),
7367
+ []
7368
+ );
7369
+ const [charCount, setCharCount] = useState(0);
7370
+ const handleCharCount = useCallback(
7371
+ (count) => setCharCount(count),
7372
+ []
7373
+ );
7374
+ const [refErrors, setRefErrors] = useState([]);
7375
+ const [pageSetup, setPageSetup] = useState(DEFAULT_PAGE_SETUP);
7376
+ const pageCanvas = resolvePageCanvasMetrics(pageSetup);
7377
+ const contentEditableDomRef = useRef(null);
7378
+ const previousOverLimitRef = useRef(false);
7379
+ const focusedRef = useRef(false);
7380
+ const setFocused = (focused) => {
7381
+ focusedRef.current = focused;
7382
+ };
7383
+ const containerRef = useRef(null);
7384
+ const onAnchorRef = (elem) => {
7385
+ if (elem) setFloatingAnchorElem(elem);
7386
+ };
7387
+ const initialConfig = {
7388
+ namespace: props.namespace,
7389
+ theme,
7390
+ onError: () => {
7391
+ },
7392
+ nodes: [
7393
+ HeadingNode,
7394
+ QuoteNode,
7395
+ CodeHighlightNode,
7396
+ CodeNode,
7397
+ ListNode,
7398
+ ListItemNode,
7399
+ LinkNode,
7400
+ AutoLinkNode,
7401
+ TableNode,
7402
+ TableRowNode,
7403
+ TableCellNode,
7404
+ ImageNode,
7405
+ InlineImageNode,
7406
+ YouTubeNode,
7407
+ PageBreakNode,
7408
+ AutocompleteNode,
7409
+ SpellErrorNode,
7410
+ HtmlBlockNode
7411
+ ]
7412
+ };
7413
+ const EditorStyles = mergeStyleSets({
7414
+ editorPlaceholder: {
7415
+ color: "var(--colorNeutralForeground3, grey)",
7416
+ position: "absolute",
7417
+ top: props.level !== "none" /* None */ ? "17px" : "27px",
7418
+ left: pageCanvas.paddingPx,
7419
+ right: pageCanvas.paddingPx,
7420
+ fontSize: "14px",
7421
+ pointerEvents: "none",
7422
+ userSelect: "none"
7423
+ },
7424
+ contentEditor: {
7425
+ zIndex: 0,
7426
+ flex: "auto",
7427
+ outline: "none",
7428
+ overflow: "auto",
7429
+ marginTop: "0px",
7430
+ position: "relative",
7431
+ background: "var(--colorNeutralBackground1, #ffffff)",
7432
+ justifyContent: "center",
7433
+ height: props.contentHeight ?? "100%",
7434
+ ...isReadOnly && {
7435
+ cursor: "not-allowed",
7436
+ opacity: 0.75,
7437
+ userSelect: "text"
7236
7438
  }
7237
- };
7238
- const [touched, setTouched] = useState(false);
7239
- const isOverLimit = props.wordLimit !== void 0 && wordCount > props.wordLimit;
7240
- const internalErrors = [];
7241
- if (isOverLimit) {
7242
- const m = props.errorMessages?.wordLimitExceeded;
7243
- internalErrors.push(
7244
- typeof m === "function" ? m(wordCount, props.wordLimit) : m ?? `Word limit exceeded (${wordCount} / ${props.wordLimit} words used)`
7245
- );
7246
- }
7247
- if (props.required && touched && wordCount === 0) {
7248
- internalErrors.push(
7249
- props.errorMessages?.required ?? "This field is required"
7250
- );
7251
- }
7252
- if (props.minWords !== void 0 && touched && wordCount < props.minWords) {
7253
- const m = props.errorMessages?.minWords;
7254
- internalErrors.push(
7255
- typeof m === "function" ? m(wordCount, props.minWords) : m ?? `Minimum ${props.minWords} words required (${wordCount} entered)`
7256
- );
7257
7439
  }
7258
- if (props.maxChars !== void 0 && charCount > props.maxChars) {
7259
- const m = props.errorMessages?.maxCharsExceeded;
7260
- internalErrors.push(
7261
- typeof m === "function" ? m(charCount, props.maxChars) : m ?? `Character limit exceeded (${charCount} / ${props.maxChars} characters used)`
7262
- );
7440
+ });
7441
+ const urlRegExp = new RegExp(
7442
+ /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/
7443
+ );
7444
+ const validateUrl = (url) => url === "https://" || urlRegExp.test(url);
7445
+ const handleReadOnlyClickCapture = (e) => {
7446
+ if (!isReadOnly) return;
7447
+ const target = e.target;
7448
+ const anchor = target?.closest?.("a");
7449
+ if (anchor) {
7450
+ e.preventDefault();
7451
+ e.stopPropagation();
7263
7452
  }
7264
- if (props.minChars !== void 0 && touched && charCount < props.minChars && charCount > 0) {
7265
- const m = props.errorMessages?.minCharsRequired;
7266
- internalErrors.push(
7267
- typeof m === "function" ? m(charCount, props.minChars) : m ?? `Minimum ${props.minChars} characters required (${charCount} entered)`
7268
- );
7453
+ };
7454
+ const [touched, setTouched] = useState(false);
7455
+ const isOverLimit = props.wordLimit !== void 0 && wordCount > props.wordLimit;
7456
+ const internalErrors = [];
7457
+ if (isOverLimit) {
7458
+ const m = props.errorMessages?.wordLimitExceeded;
7459
+ internalErrors.push(
7460
+ typeof m === "function" ? m(wordCount, props.wordLimit) : m ?? `Word limit exceeded (${wordCount} / ${props.wordLimit} words used)`
7461
+ );
7462
+ }
7463
+ if (props.required && touched && wordCount === 0) {
7464
+ internalErrors.push(
7465
+ props.errorMessages?.required ?? "This field is required"
7466
+ );
7467
+ }
7468
+ if (props.minWords !== void 0 && touched && wordCount < props.minWords) {
7469
+ const m = props.errorMessages?.minWords;
7470
+ internalErrors.push(
7471
+ typeof m === "function" ? m(wordCount, props.minWords) : m ?? `Minimum ${props.minWords} words required (${wordCount} entered)`
7472
+ );
7473
+ }
7474
+ if (props.maxChars !== void 0 && charCount > props.maxChars) {
7475
+ const m = props.errorMessages?.maxCharsExceeded;
7476
+ internalErrors.push(
7477
+ typeof m === "function" ? m(charCount, props.maxChars) : m ?? `Character limit exceeded (${charCount} / ${props.maxChars} characters used)`
7478
+ );
7479
+ }
7480
+ if (props.minChars !== void 0 && touched && charCount < props.minChars && charCount > 0) {
7481
+ const m = props.errorMessages?.minCharsRequired;
7482
+ internalErrors.push(
7483
+ typeof m === "function" ? m(charCount, props.minChars) : m ?? `Minimum ${props.minChars} characters required (${charCount} entered)`
7484
+ );
7485
+ }
7486
+ const allErrors = [
7487
+ ...internalErrors,
7488
+ ...props.errors ?? [],
7489
+ ...refErrors
7490
+ ];
7491
+ const hasErrors = allErrors.length > 0;
7492
+ const hasRedBorder = hasErrors;
7493
+ useEffect(() => {
7494
+ if (props.wordLimit === void 0 || !props.onWordLimitExceeded) return;
7495
+ const wasOverLimit = previousOverLimitRef.current;
7496
+ if (isOverLimit !== wasOverLimit) {
7497
+ props.onWordLimitExceeded({
7498
+ wordCount,
7499
+ wordLimit: props.wordLimit,
7500
+ exceeded: isOverLimit
7501
+ });
7502
+ previousOverLimitRef.current = isOverLimit;
7269
7503
  }
7270
- const allErrors = [...internalErrors, ...props.errors ?? [], ...refErrors];
7271
- const hasErrors = allErrors.length > 0;
7272
- const hasRedBorder = hasErrors;
7273
- useEffect(() => {
7274
- if (props.wordLimit === void 0 || !props.onWordLimitExceeded) return;
7275
- const wasOverLimit = previousOverLimitRef.current;
7276
- if (isOverLimit !== wasOverLimit) {
7277
- props.onWordLimitExceeded({
7278
- wordCount,
7279
- wordLimit: props.wordLimit,
7280
- exceeded: isOverLimit
7281
- });
7282
- previousOverLimitRef.current = isOverLimit;
7283
- }
7284
- }, [isOverLimit, wordCount, props.wordLimit, props.onWordLimitExceeded]);
7285
- return /* @__PURE__ */ jsx(FluentProvider, { theme: webLightTheme, style: { height: "100%" }, children: /* @__PURE__ */ jsx(LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsx("div", { ref: containerRef, style: { height: "100%" }, children: /* @__PURE__ */ jsxs(
7286
- Stack,
7287
- {
7288
- style: {
7289
- zIndex: 1e3,
7290
- background: "#fff",
7291
- borderRadius: "2px",
7292
- width: props.width ?? "100%",
7293
- height: props.height ?? "100%",
7294
- margin: props.margin ?? "5px auto",
7295
- border: `1px solid ${hasRedBorder ? "#c4272c" : "var(--colorNeutralStroke1, #ccced1)"}`,
7296
- transition: "border-color 0.2s",
7297
- display: "flex",
7298
- flexDirection: "column"
7299
- },
7300
- children: [
7301
- /* @__PURE__ */ jsx(
7302
- "div",
7303
- {
7304
- style: {
7305
- pointerEvents: isReadOnly ? "none" : "auto",
7306
- position: "sticky",
7307
- opacity: isReadOnly ? 0.85 : 1
7308
- },
7309
- children: /* @__PURE__ */ jsx(
7310
- ToolBarPlugins,
7504
+ }, [isOverLimit, wordCount, props.wordLimit, props.onWordLimitExceeded]);
7505
+ return /* @__PURE__ */ jsx(FluentProvider, { theme: webLightTheme, style: { height: "100%" }, children: /* @__PURE__ */ jsx(LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsx("div", { ref: containerRef, style: { height: "100%" }, children: /* @__PURE__ */ jsxs(
7506
+ Stack,
7507
+ {
7508
+ style: {
7509
+ zIndex: 1e3,
7510
+ background: "#fff",
7511
+ borderRadius: "2px",
7512
+ width: props.width ?? "100%",
7513
+ height: props.height ?? "100%",
7514
+ margin: props.margin ?? "5px auto",
7515
+ border: `1px solid ${hasRedBorder ? "#c4272c" : "var(--colorNeutralStroke1, #ccced1)"}`,
7516
+ transition: "border-color 0.2s",
7517
+ display: "flex",
7518
+ flexDirection: "column"
7519
+ },
7520
+ children: [
7521
+ /* @__PURE__ */ jsx(
7522
+ "div",
7523
+ {
7524
+ style: {
7525
+ pointerEvents: isReadOnly ? "none" : "auto",
7526
+ position: "sticky",
7527
+ opacity: isReadOnly ? 0.85 : 1
7528
+ },
7529
+ children: /* @__PURE__ */ jsx(
7530
+ ToolBarPlugins,
7531
+ {
7532
+ level: props.level ?? "basic" /* Basic */,
7533
+ readOnly: props.readOnly,
7534
+ pageSetup,
7535
+ onPageSetupChange: setPageSetup
7536
+ }
7537
+ )
7538
+ }
7539
+ ),
7540
+ /* @__PURE__ */ jsxs(
7541
+ "div",
7542
+ {
7543
+ style: {
7544
+ position: "relative",
7545
+ flexGrow: 1,
7546
+ padding: "15px 0px",
7547
+ overflowY: "scroll",
7548
+ overflowX: "auto",
7549
+ minWidth: 0,
7550
+ background: pageCanvas.widthPx !== void 0 ? "#eef0f2" : void 0
7551
+ },
7552
+ onClickCapture: handleReadOnlyClickCapture,
7553
+ children: [
7554
+ /* @__PURE__ */ jsx(
7555
+ RichTextPlugin,
7311
7556
  {
7312
- level: props.level ?? "basic" /* Basic */,
7313
- readOnly: props.readOnly,
7314
- pageSetup,
7315
- onPageSetupChange: setPageSetup
7557
+ ErrorBoundary: LexicalErrorBoundary,
7558
+ contentEditable: /* @__PURE__ */ jsx(
7559
+ "div",
7560
+ {
7561
+ className: "editor",
7562
+ style: { height: "100%", position: "relative" },
7563
+ ref: onAnchorRef,
7564
+ children: /* @__PURE__ */ jsx(
7565
+ ContentEditable,
7566
+ {
7567
+ ref: contentEditableDomRef,
7568
+ className: css(EditorStyles.contentEditor),
7569
+ style: {
7570
+ paddingTop: props.level !== "none" /* None */ ? 0 : 10,
7571
+ paddingLeft: pageCanvas.paddingPx,
7572
+ paddingRight: pageCanvas.paddingPx,
7573
+ maxWidth: pageCanvas.widthPx,
7574
+ marginLeft: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7575
+ marginRight: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7576
+ 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
7577
+ },
7578
+ spellCheck: !resolvedSpellCheck,
7579
+ autoCorrect: resolvedSpellCheck ? "off" : void 0,
7580
+ autoCapitalize: resolvedSpellCheck ? "off" : void 0
7581
+ }
7582
+ )
7583
+ }
7584
+ ),
7585
+ placeholder: /* @__PURE__ */ jsx(Stack, { className: css(EditorStyles.editorPlaceholder), children: props.placeholder })
7586
+ }
7587
+ ),
7588
+ props.wordLimit !== void 0 && /* @__PURE__ */ jsx(
7589
+ "div",
7590
+ {
7591
+ style: {
7592
+ position: "sticky",
7593
+ bottom: 0,
7594
+ display: "flex",
7595
+ justifyContent: "flex-end",
7596
+ paddingRight: 14,
7597
+ pointerEvents: "none",
7598
+ userSelect: "none"
7599
+ },
7600
+ children: /* @__PURE__ */ jsxs(
7601
+ "span",
7602
+ {
7603
+ style: {
7604
+ fontSize: "11px",
7605
+ color: isOverLimit ? "#c4272c" : "var(--colorNeutralForeground3, #aaa)",
7606
+ fontWeight: isOverLimit ? 600 : 400,
7607
+ transition: "color 0.2s, font-weight 0.2s"
7608
+ },
7609
+ children: [
7610
+ wordCount,
7611
+ " / ",
7612
+ props.wordLimit,
7613
+ " words"
7614
+ ]
7615
+ }
7616
+ )
7316
7617
  }
7317
7618
  )
7318
- }
7319
- ),
7320
- /* @__PURE__ */ jsxs(
7321
- "div",
7322
- {
7323
- style: {
7324
- position: "relative",
7325
- flexGrow: 1,
7326
- padding: "15px 0px",
7327
- overflowY: "scroll",
7328
- overflowX: "auto",
7329
- minWidth: 0,
7330
- background: pageCanvas.widthPx !== void 0 ? "#eef0f2" : void 0
7331
- },
7332
- onClickCapture: handleReadOnlyClickCapture,
7333
- children: [
7334
- /* @__PURE__ */ jsx(
7335
- RichTextPlugin,
7336
- {
7337
- ErrorBoundary: LexicalErrorBoundary,
7338
- contentEditable: /* @__PURE__ */ jsx(
7339
- "div",
7340
- {
7341
- className: "editor",
7342
- style: { height: "100%", position: "relative" },
7343
- ref: onAnchorRef,
7344
- children: /* @__PURE__ */ jsx(
7345
- ContentEditable,
7346
- {
7347
- ref: contentEditableDomRef,
7348
- className: css(EditorStyles.contentEditor),
7349
- style: {
7350
- paddingTop: props.level !== "none" /* None */ ? 0 : 10,
7351
- paddingLeft: pageCanvas.paddingPx,
7352
- paddingRight: pageCanvas.paddingPx,
7353
- maxWidth: pageCanvas.widthPx,
7354
- marginLeft: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7355
- marginRight: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7356
- 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
7357
- },
7358
- spellCheck: !resolvedSpellCheck,
7359
- autoCorrect: resolvedSpellCheck ? "off" : void 0,
7360
- autoCapitalize: resolvedSpellCheck ? "off" : void 0
7361
- }
7362
- )
7363
- }
7364
- ),
7365
- placeholder: /* @__PURE__ */ jsx(Stack, { className: css(EditorStyles.editorPlaceholder), children: props.placeholder })
7366
- }
7367
- ),
7368
- props.wordLimit !== void 0 && /* @__PURE__ */ jsx(
7369
- "div",
7370
- {
7371
- style: {
7372
- position: "sticky",
7373
- bottom: 0,
7374
- display: "flex",
7375
- justifyContent: "flex-end",
7376
- paddingRight: 14,
7377
- pointerEvents: "none",
7378
- userSelect: "none"
7379
- },
7380
- children: /* @__PURE__ */ jsxs(
7381
- "span",
7382
- {
7383
- style: {
7384
- fontSize: "11px",
7385
- color: isOverLimit ? "#c4272c" : "var(--colorNeutralForeground3, #aaa)",
7386
- fontWeight: isOverLimit ? 600 : 400,
7387
- transition: "color 0.2s, font-weight 0.2s"
7388
- },
7389
- children: [
7390
- wordCount,
7391
- " / ",
7392
- props.wordLimit,
7393
- " words"
7394
- ]
7395
- }
7396
- )
7397
- }
7398
- )
7399
- ]
7400
- }
7401
- ),
7402
- hasErrors && /* @__PURE__ */ jsx(
7403
- "div",
7404
- {
7405
- style: {
7406
- borderTop: "1px solid #fbd5d5",
7407
- background: "#fff8f8",
7408
- padding: "6px 12px 8px",
7409
- display: "flex",
7410
- flexDirection: "column",
7411
- gap: 4
7412
- },
7413
- children: allErrors.map((err, i) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
7414
- /* @__PURE__ */ jsx(ErrorCircleRegular, { style: { fontSize: 14, color: "#c4272c", flexShrink: 0 } }),
7415
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#c4272c" }, children: err })
7416
- ] }, i))
7417
- }
7418
- ),
7419
- /* @__PURE__ */ jsx(ReadOnlyPlugin, { readonly: isReadOnly }),
7420
- /* @__PURE__ */ jsx(BrowserSpellCheckPlugin, { enabled: !resolvedSpellCheck }),
7421
- /* @__PURE__ */ jsx(
7422
- FocusEventsPlugin,
7423
- {
7424
- onFocus: props.onFocus,
7425
- onBlur: () => {
7426
- setTouched(true);
7427
- props.onBlur?.();
7619
+ ]
7620
+ }
7621
+ ),
7622
+ hasErrors && /* @__PURE__ */ jsx(
7623
+ "div",
7624
+ {
7625
+ style: {
7626
+ borderTop: "1px solid #fbd5d5",
7627
+ background: "#fff8f8",
7628
+ padding: "6px 12px 8px",
7629
+ display: "flex",
7630
+ flexDirection: "column",
7631
+ gap: 4
7632
+ },
7633
+ children: allErrors.map((err, i) => /* @__PURE__ */ jsxs(
7634
+ "div",
7635
+ {
7636
+ style: { display: "flex", alignItems: "center", gap: 6 },
7637
+ children: [
7638
+ /* @__PURE__ */ jsx(
7639
+ ErrorCircleRegular,
7640
+ {
7641
+ style: { fontSize: 14, color: "#c4272c", flexShrink: 0 }
7642
+ }
7643
+ ),
7644
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#c4272c" }, children: err })
7645
+ ]
7428
7646
  },
7429
- setFocused,
7430
- containerRef
7431
- }
7432
- ),
7433
- props.autoFocus && !isReadOnly && /* @__PURE__ */ jsx(AutoFocusPlugin, {}),
7434
- /* @__PURE__ */ jsx(HistoryPlugin, {}),
7435
- /* @__PURE__ */ jsx(ListPlugin, {}),
7436
- /* @__PURE__ */ jsx(LinkPlugin, { validateUrl }),
7437
- /* @__PURE__ */ jsx(AutoLinkPlugin, { matchers: MATCHERS }),
7438
- /* @__PURE__ */ jsx(TablePlugin, { hasCellMerge: true, hasCellBackgroundColor: true }),
7439
- !isReadOnly && /* @__PURE__ */ jsx(YoutubeDeletePlugin, {}),
7440
- !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsx(TableActionMenuPlugin, {}),
7441
- !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsx(TableCellResizerPlugin, { anchorElem: floatingAnchorElem }),
7442
- !isReadOnly && /* @__PURE__ */ jsx(
7443
- FloatingLinkEditorPlugin,
7444
- {
7445
- anchorElem: floatingAnchorElem,
7446
- isLinkEditMode,
7447
- setIsLinkEditMode
7448
- }
7449
- ),
7450
- !isReadOnly && /* @__PURE__ */ jsx(ImagePlugin_default, {}),
7451
- !isReadOnly && /* @__PURE__ */ jsx(InlineImage_default, {}),
7452
- !isReadOnly && /* @__PURE__ */ jsx(PageBreakPlugin, {}),
7453
- !!resolvedQuery && !isReadOnly && /* @__PURE__ */ jsx(
7454
- AutocompletePlugin,
7455
- {
7456
- useQuery: resolvedQuery,
7457
- isReadOnly,
7458
- onSuggestionShown: props.onSuggestionShown,
7459
- onSuggestionAccept: props.onSuggestionAccept,
7460
- idleMs: props.suggestIdleMs ?? 300,
7461
- minWords: 4,
7462
- prefixWindow: 300
7463
- }
7464
- ),
7465
- !!resolvedSpellCheck && !isReadOnly && /* @__PURE__ */ jsx(
7466
- SpellCheckPlugin,
7467
- {
7468
- useSpellCheck: resolvedSpellCheck,
7469
- onSpellCheckAccept: props.onSpellCheckAccept,
7470
- idleMs: props.spellCheckIdleMs ?? 1200,
7471
- enabled: props.spellCheckEnabled !== false
7472
- }
7473
- ),
7474
- !isReadOnly && props.showFloatingToolbar && /* @__PURE__ */ jsx(CharacterStylesPopupPlugin, {}),
7475
- /* @__PURE__ */ jsx(CustomOnChangePlugin, { value: props.value, onChange: props.onChange }),
7476
- (props.wordLimit !== void 0 || props.required || props.minWords !== void 0) && /* @__PURE__ */ jsx(WordCountPlugin, { onCountChange: handleWordCount }),
7477
- (props.maxChars !== void 0 || props.minChars !== void 0) && /* @__PURE__ */ jsx(CharCountPlugin, { onCountChange: handleCharCount }),
7478
- /* @__PURE__ */ jsx(
7479
- RefApiPlugin,
7480
- {
7481
- forwardedRef: ref,
7482
- contentEditableDomRef,
7483
- focusedRef,
7484
- setRefErrors
7485
- }
7486
- )
7487
- ]
7488
- }
7489
- ) }) }) });
7490
- }
7491
- );
7647
+ i
7648
+ ))
7649
+ }
7650
+ ),
7651
+ /* @__PURE__ */ jsx(ReadOnlyPlugin, { readonly: isReadOnly }),
7652
+ /* @__PURE__ */ jsx(BrowserSpellCheckPlugin, { enabled: !resolvedSpellCheck }),
7653
+ /* @__PURE__ */ jsx(
7654
+ FocusEventsPlugin,
7655
+ {
7656
+ onFocus: props.onFocus,
7657
+ onBlur: () => {
7658
+ setTouched(true);
7659
+ props.onBlur?.();
7660
+ },
7661
+ setFocused,
7662
+ containerRef
7663
+ }
7664
+ ),
7665
+ props.autoFocus && !isReadOnly && /* @__PURE__ */ jsx(AutoFocusPlugin, {}),
7666
+ /* @__PURE__ */ jsx(HistoryPlugin, {}),
7667
+ /* @__PURE__ */ jsx(ListPlugin, {}),
7668
+ /* @__PURE__ */ jsx(LinkPlugin, { validateUrl }),
7669
+ /* @__PURE__ */ jsx(AutoLinkPlugin, { matchers: MATCHERS }),
7670
+ /* @__PURE__ */ jsx(TablePlugin, { hasCellMerge: true, hasCellBackgroundColor: true }),
7671
+ !isReadOnly && /* @__PURE__ */ jsx(YoutubeDeletePlugin, {}),
7672
+ !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsx(TableActionMenuPlugin, {}),
7673
+ !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsx(TableCellResizerPlugin, { anchorElem: floatingAnchorElem }),
7674
+ !isReadOnly && /* @__PURE__ */ jsx(
7675
+ FloatingLinkEditorPlugin,
7676
+ {
7677
+ anchorElem: floatingAnchorElem,
7678
+ isLinkEditMode,
7679
+ setIsLinkEditMode
7680
+ }
7681
+ ),
7682
+ !isReadOnly && /* @__PURE__ */ jsx(ImagePlugin_default, {}),
7683
+ !isReadOnly && /* @__PURE__ */ jsx(InlineImage_default, {}),
7684
+ !isReadOnly && /* @__PURE__ */ jsx(PageBreakPlugin, {}),
7685
+ !!resolvedQuery && !isReadOnly && /* @__PURE__ */ jsx(
7686
+ AutocompletePlugin,
7687
+ {
7688
+ useQuery: resolvedQuery,
7689
+ isReadOnly,
7690
+ onSuggestionShown: props.onSuggestionShown,
7691
+ onSuggestionAccept: props.onSuggestionAccept,
7692
+ idleMs: props.suggestIdleMs ?? 300,
7693
+ minWords: 4,
7694
+ prefixWindow: 300
7695
+ }
7696
+ ),
7697
+ !!resolvedSpellCheck && !isReadOnly && /* @__PURE__ */ jsx(
7698
+ SpellCheckPlugin,
7699
+ {
7700
+ useSpellCheck: resolvedSpellCheck,
7701
+ onSpellCheckAccept: props.onSpellCheckAccept,
7702
+ idleMs: props.spellCheckIdleMs ?? 1200,
7703
+ enabled: props.spellCheckEnabled !== false
7704
+ }
7705
+ ),
7706
+ !isReadOnly && props.showFloatingToolbar && /* @__PURE__ */ jsx(CharacterStylesPopupPlugin, {}),
7707
+ /* @__PURE__ */ jsx(
7708
+ CustomOnChangePlugin,
7709
+ {
7710
+ value: props.value,
7711
+ onChange: props.onChange
7712
+ }
7713
+ ),
7714
+ (props.wordLimit !== void 0 || props.required || props.minWords !== void 0) && /* @__PURE__ */ jsx(WordCountPlugin, { onCountChange: handleWordCount }),
7715
+ (props.maxChars !== void 0 || props.minChars !== void 0) && /* @__PURE__ */ jsx(CharCountPlugin, { onCountChange: handleCharCount }),
7716
+ /* @__PURE__ */ jsx(
7717
+ RefApiPlugin,
7718
+ {
7719
+ forwardedRef: ref,
7720
+ contentEditableDomRef,
7721
+ focusedRef,
7722
+ setRefErrors
7723
+ }
7724
+ )
7725
+ ]
7726
+ }
7727
+ ) }) }) });
7728
+ });
7492
7729
 
7493
7730
  export { ContentEditorComponent, ContentEditorLevel };
7494
7731
  //# sourceMappingURL=index.mjs.map