@tarviks/lexical-rich-editor 1.0.4 → 1.0.6
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/README.md +3 -3
- package/dist/index.css +23 -4
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +55 -8
- package/dist/index.d.ts +55 -8
- package/dist/index.js +615 -316
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +617 -318
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -5,9 +5,10 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
5
5
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
6
6
|
import { useLexicalEditable } from '@lexical/react/useLexicalEditable';
|
|
7
7
|
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
|
|
8
|
-
import { createCommand, DecoratorNode, COMMAND_PRIORITY_HIGH, TextNode, ElementNode,
|
|
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, createEditor, KEY_ENTER_COMMAND } from 'lexical';
|
|
9
9
|
import { mergeStyleSets, Stack, css, useTheme, Callout, TextField, DefaultButton } from '@fluentui/react';
|
|
10
|
-
import { makeStyles, FluentProvider, webLightTheme,
|
|
10
|
+
import { makeStyles, FluentProvider, webLightTheme, Menu, MenuTrigger, MenuPopover, MenuList, MenuGroup, MenuGroupHeader, MenuItem, MenuDivider, Dropdown, Option, ToolbarDivider, Button, 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, TextAlignLeftFilled, TextAlignCenterFilled, TextAlignRightFilled, TextAlignJustifyFilled, VideoClipRegular, ImageEditRegular, AttachFilled, ImageAddRegular, TableAddRegular, LinkAddRegular, TextColorRegular, PaintBucket16Filled, CodeFilled, LinkFilled } from '@fluentui/react-icons';
|
|
11
12
|
import { CodeHighlightNode, CodeNode, $isCodeHighlightNode } from '@lexical/code';
|
|
12
13
|
import { LinkNode, AutoLinkNode, $isLinkNode, $isAutoLinkNode, TOGGLE_LINK_COMMAND, $createLinkNode } from '@lexical/link';
|
|
13
14
|
import { ListNode, ListItemNode, $isListNode, REMOVE_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';
|
|
@@ -25,7 +26,6 @@ import { HeadingNode, QuoteNode, $isHeadingNode, $createQuoteNode, $createHeadin
|
|
|
25
26
|
import { TableNode, TableRowNode, TableCellNode, $isTableSelection, $isTableNode, $isTableCellNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $deleteTableRowAtSelection, $deleteTableColumnAtSelection, $getTableNodeFromLexicalNodeOrThrow, getDOMCellFromTarget, getTableObserverFromTableElement, $getTableRowIndexFromTableCellNode, $isTableRowNode, $getTableColumnIndexFromTableCellNode, $createTableNodeWithDimensions } from '@lexical/table';
|
|
26
27
|
import { BlockWithAlignableContents } from '@lexical/react/LexicalBlockWithAlignableContents';
|
|
27
28
|
import { DecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
|
|
28
|
-
import { DeleteRegular, ArrowUpRegular, RowTripleRegular, ArrowDownRegular, ArrowLeftRegular, ColumnTripleRegular, ArrowRightRegular, TextCaseUppercaseFilled, TextCaseLowercaseFilled, TextCaseTitleFilled, TextStrikethroughFilled, TextSubscriptFilled, TextSuperscriptFilled, HighlightAccentFilled, TextBulletListLtrFilled, TextNumberListLtrFilled, DocumentPageBreakRegular, CommentQuoteRegular, TextUnderlineFilled, TextItalicFilled, TextBold24Regular, TextAlignLeftFilled, TextAlignCenterFilled, TextAlignRightFilled, TextAlignJustifyFilled, VideoClipRegular, ImageEditRegular, AttachFilled, ImageAddRegular, TableAddRegular, LinkAddRegular, TextColorRegular, PaintBucket16Filled, CodeFilled, LinkFilled } from '@fluentui/react-icons';
|
|
29
29
|
import { $setBlocksType, $patchStyleText, $isAtNodeEnd, $getSelectionStyleValueForProperty } from '@lexical/selection';
|
|
30
30
|
import { createPortal } from 'react-dom';
|
|
31
31
|
import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html';
|
|
@@ -222,80 +222,107 @@ var init_ImageResizer = __esm({
|
|
|
222
222
|
document.removeEventListener("pointerup", handlePointerUp);
|
|
223
223
|
}
|
|
224
224
|
};
|
|
225
|
-
return
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
onPointerDown: (event) => {
|
|
231
|
-
handlePointerDown(event, Direction.north);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
),
|
|
235
|
-
/* @__PURE__ */ jsx(
|
|
236
|
-
"div",
|
|
237
|
-
{
|
|
238
|
-
className: "image-resizer image-resizer-ne",
|
|
239
|
-
onPointerDown: (event) => {
|
|
240
|
-
handlePointerDown(event, Direction.north | Direction.east);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
),
|
|
244
|
-
/* @__PURE__ */ jsx(
|
|
245
|
-
"div",
|
|
246
|
-
{
|
|
247
|
-
className: "image-resizer image-resizer-e",
|
|
248
|
-
onPointerDown: (event) => {
|
|
249
|
-
handlePointerDown(event, Direction.east);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
),
|
|
253
|
-
/* @__PURE__ */ jsx(
|
|
254
|
-
"div",
|
|
255
|
-
{
|
|
256
|
-
className: "image-resizer image-resizer-se",
|
|
257
|
-
onPointerDown: (event) => {
|
|
258
|
-
handlePointerDown(event, Direction.south | Direction.east);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
),
|
|
262
|
-
/* @__PURE__ */ jsx(
|
|
263
|
-
"div",
|
|
264
|
-
{
|
|
265
|
-
className: "image-resizer image-resizer-s",
|
|
266
|
-
onPointerDown: (event) => {
|
|
267
|
-
handlePointerDown(event, Direction.south);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
),
|
|
271
|
-
/* @__PURE__ */ jsx(
|
|
272
|
-
"div",
|
|
273
|
-
{
|
|
274
|
-
className: "image-resizer image-resizer-sw",
|
|
275
|
-
onPointerDown: (event) => {
|
|
276
|
-
handlePointerDown(event, Direction.south | Direction.west);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
),
|
|
280
|
-
/* @__PURE__ */ jsx(
|
|
281
|
-
"div",
|
|
282
|
-
{
|
|
283
|
-
className: "image-resizer image-resizer-w",
|
|
284
|
-
onPointerDown: (event) => {
|
|
285
|
-
handlePointerDown(event, Direction.west);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
),
|
|
289
|
-
/* @__PURE__ */ jsx(
|
|
225
|
+
return (
|
|
226
|
+
// Overlay that exactly covers the image container (position:relative parent).
|
|
227
|
+
// pointer-events:none lets clicks pass through to the image; each handle
|
|
228
|
+
// re-enables pointer-events so drag-resize still works.
|
|
229
|
+
/* @__PURE__ */ jsxs(
|
|
290
230
|
"div",
|
|
291
231
|
{
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
232
|
+
ref: controlWrapperRef,
|
|
233
|
+
style: {
|
|
234
|
+
position: "absolute",
|
|
235
|
+
top: 0,
|
|
236
|
+
right: 0,
|
|
237
|
+
bottom: 0,
|
|
238
|
+
left: 0,
|
|
239
|
+
pointerEvents: "none"
|
|
240
|
+
},
|
|
241
|
+
children: [
|
|
242
|
+
/* @__PURE__ */ jsx(
|
|
243
|
+
"div",
|
|
244
|
+
{
|
|
245
|
+
className: "image-resizer image-resizer-n",
|
|
246
|
+
style: { pointerEvents: "auto" },
|
|
247
|
+
onPointerDown: (event) => {
|
|
248
|
+
handlePointerDown(event, Direction.north);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
),
|
|
252
|
+
/* @__PURE__ */ jsx(
|
|
253
|
+
"div",
|
|
254
|
+
{
|
|
255
|
+
className: "image-resizer image-resizer-ne",
|
|
256
|
+
style: { pointerEvents: "auto" },
|
|
257
|
+
onPointerDown: (event) => {
|
|
258
|
+
handlePointerDown(event, Direction.north | Direction.east);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
),
|
|
262
|
+
/* @__PURE__ */ jsx(
|
|
263
|
+
"div",
|
|
264
|
+
{
|
|
265
|
+
className: "image-resizer image-resizer-e",
|
|
266
|
+
style: { pointerEvents: "auto" },
|
|
267
|
+
onPointerDown: (event) => {
|
|
268
|
+
handlePointerDown(event, Direction.east);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
),
|
|
272
|
+
/* @__PURE__ */ jsx(
|
|
273
|
+
"div",
|
|
274
|
+
{
|
|
275
|
+
className: "image-resizer image-resizer-se",
|
|
276
|
+
style: { pointerEvents: "auto" },
|
|
277
|
+
onPointerDown: (event) => {
|
|
278
|
+
handlePointerDown(event, Direction.south | Direction.east);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
),
|
|
282
|
+
/* @__PURE__ */ jsx(
|
|
283
|
+
"div",
|
|
284
|
+
{
|
|
285
|
+
className: "image-resizer image-resizer-s",
|
|
286
|
+
style: { pointerEvents: "auto" },
|
|
287
|
+
onPointerDown: (event) => {
|
|
288
|
+
handlePointerDown(event, Direction.south);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
/* @__PURE__ */ jsx(
|
|
293
|
+
"div",
|
|
294
|
+
{
|
|
295
|
+
className: "image-resizer image-resizer-sw",
|
|
296
|
+
style: { pointerEvents: "auto" },
|
|
297
|
+
onPointerDown: (event) => {
|
|
298
|
+
handlePointerDown(event, Direction.south | Direction.west);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
),
|
|
302
|
+
/* @__PURE__ */ jsx(
|
|
303
|
+
"div",
|
|
304
|
+
{
|
|
305
|
+
className: "image-resizer image-resizer-w",
|
|
306
|
+
style: { pointerEvents: "auto" },
|
|
307
|
+
onPointerDown: (event) => {
|
|
308
|
+
handlePointerDown(event, Direction.west);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
),
|
|
312
|
+
/* @__PURE__ */ jsx(
|
|
313
|
+
"div",
|
|
314
|
+
{
|
|
315
|
+
className: "image-resizer image-resizer-nw",
|
|
316
|
+
style: { pointerEvents: "auto" },
|
|
317
|
+
onPointerDown: (event) => {
|
|
318
|
+
handlePointerDown(event, Direction.north | Direction.west);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
)
|
|
322
|
+
]
|
|
296
323
|
}
|
|
297
324
|
)
|
|
298
|
-
|
|
325
|
+
);
|
|
299
326
|
};
|
|
300
327
|
ImageResizer_default = ImageResizer;
|
|
301
328
|
}
|
|
@@ -3546,6 +3573,204 @@ function PageBreakPlugin() {
|
|
|
3546
3573
|
}, [editor]);
|
|
3547
3574
|
return null;
|
|
3548
3575
|
}
|
|
3576
|
+
|
|
3577
|
+
// src/Utils/Sanitize.ts
|
|
3578
|
+
var DROP_ENTIRELY = /* @__PURE__ */ new Set([
|
|
3579
|
+
"script",
|
|
3580
|
+
"noscript",
|
|
3581
|
+
"style",
|
|
3582
|
+
"object",
|
|
3583
|
+
"embed",
|
|
3584
|
+
"form",
|
|
3585
|
+
"input",
|
|
3586
|
+
"button",
|
|
3587
|
+
"select",
|
|
3588
|
+
"textarea",
|
|
3589
|
+
"meta",
|
|
3590
|
+
"link",
|
|
3591
|
+
"base"
|
|
3592
|
+
]);
|
|
3593
|
+
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
3594
|
+
// Block
|
|
3595
|
+
"p",
|
|
3596
|
+
"h1",
|
|
3597
|
+
"h2",
|
|
3598
|
+
"h3",
|
|
3599
|
+
"h4",
|
|
3600
|
+
"h5",
|
|
3601
|
+
"h6",
|
|
3602
|
+
"ul",
|
|
3603
|
+
"ol",
|
|
3604
|
+
"li",
|
|
3605
|
+
"blockquote",
|
|
3606
|
+
"pre",
|
|
3607
|
+
"div",
|
|
3608
|
+
"table",
|
|
3609
|
+
"thead",
|
|
3610
|
+
"tbody",
|
|
3611
|
+
"tfoot",
|
|
3612
|
+
"tr",
|
|
3613
|
+
"td",
|
|
3614
|
+
"th",
|
|
3615
|
+
// Inline
|
|
3616
|
+
"span",
|
|
3617
|
+
"a",
|
|
3618
|
+
"strong",
|
|
3619
|
+
"b",
|
|
3620
|
+
"em",
|
|
3621
|
+
"i",
|
|
3622
|
+
"u",
|
|
3623
|
+
"s",
|
|
3624
|
+
"del",
|
|
3625
|
+
"strike",
|
|
3626
|
+
"sub",
|
|
3627
|
+
"sup",
|
|
3628
|
+
"mark",
|
|
3629
|
+
"code",
|
|
3630
|
+
"br",
|
|
3631
|
+
"hr",
|
|
3632
|
+
// Media / embeds
|
|
3633
|
+
"img",
|
|
3634
|
+
"iframe"
|
|
3635
|
+
]);
|
|
3636
|
+
var ALLOWED_ATTRS = /* @__PURE__ */ new Set([
|
|
3637
|
+
// Presentation
|
|
3638
|
+
"class",
|
|
3639
|
+
"style",
|
|
3640
|
+
"dir",
|
|
3641
|
+
"lang",
|
|
3642
|
+
// Anchors
|
|
3643
|
+
"href",
|
|
3644
|
+
"target",
|
|
3645
|
+
"rel",
|
|
3646
|
+
// Images
|
|
3647
|
+
"src",
|
|
3648
|
+
"alt",
|
|
3649
|
+
"width",
|
|
3650
|
+
"height",
|
|
3651
|
+
// Tables
|
|
3652
|
+
"colspan",
|
|
3653
|
+
"rowspan",
|
|
3654
|
+
// Lists — <ol type="a"> and <ol start="2">
|
|
3655
|
+
"start",
|
|
3656
|
+
"type",
|
|
3657
|
+
// Lexical-internal data markers
|
|
3658
|
+
"data-lex-block",
|
|
3659
|
+
"data-kind",
|
|
3660
|
+
"data-lexical-decorator",
|
|
3661
|
+
// Misc
|
|
3662
|
+
"title",
|
|
3663
|
+
"allowfullscreen"
|
|
3664
|
+
]);
|
|
3665
|
+
var DANGEROUS_URL = /^\s*(javascript|data\s*:|vbscript)/i;
|
|
3666
|
+
function sanitizeElement(el) {
|
|
3667
|
+
for (const child of Array.from(el.children)) {
|
|
3668
|
+
sanitizeElement(child);
|
|
3669
|
+
}
|
|
3670
|
+
const tag = el.tagName.toLowerCase();
|
|
3671
|
+
if (DROP_ENTIRELY.has(tag)) {
|
|
3672
|
+
el.parentNode?.removeChild(el);
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3675
|
+
if (tag === "iframe") {
|
|
3676
|
+
const src = el.getAttribute("src") ?? "";
|
|
3677
|
+
const isYouTube = /^\s*https:\/\/(www\.)?(youtube\.com|youtube-nocookie\.com)\/embed\/[^?&/]+/i.test(src);
|
|
3678
|
+
if (!isYouTube) {
|
|
3679
|
+
el.parentNode?.removeChild(el);
|
|
3680
|
+
return;
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
if (!ALLOWED_TAGS.has(tag)) {
|
|
3684
|
+
while (el.firstChild) {
|
|
3685
|
+
el.parentNode?.insertBefore(el.firstChild, el);
|
|
3686
|
+
}
|
|
3687
|
+
el.parentNode?.removeChild(el);
|
|
3688
|
+
return;
|
|
3689
|
+
}
|
|
3690
|
+
for (const { name, value } of Array.from(el.attributes)) {
|
|
3691
|
+
const lname = name.toLowerCase();
|
|
3692
|
+
if (!ALLOWED_ATTRS.has(lname)) {
|
|
3693
|
+
el.removeAttribute(name);
|
|
3694
|
+
continue;
|
|
3695
|
+
}
|
|
3696
|
+
if (lname === "href" || lname === "src") {
|
|
3697
|
+
if (DANGEROUS_URL.test(value)) {
|
|
3698
|
+
el.removeAttribute(name);
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
if (lname === "style") {
|
|
3702
|
+
const safe = value.replace(/expression\s*\(/gi, "(").replace(/url\s*\(\s*['"]?\s*javascript:/gi, "url(");
|
|
3703
|
+
el.setAttribute("style", safe);
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
if (tag === "a" && (el.getAttribute("target") || "").toLowerCase() === "_blank") {
|
|
3707
|
+
const rel = (el.getAttribute("rel") || "").trim();
|
|
3708
|
+
const tokens = new Set(
|
|
3709
|
+
rel.split(/\s+/).filter(Boolean).map((t) => t.toLowerCase())
|
|
3710
|
+
);
|
|
3711
|
+
tokens.add("noopener");
|
|
3712
|
+
tokens.add("noreferrer");
|
|
3713
|
+
el.setAttribute("rel", Array.from(tokens).join(" "));
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
function sanitizeHtml(html) {
|
|
3717
|
+
if (!html || typeof html !== "string") return "";
|
|
3718
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
3719
|
+
for (const child of Array.from(doc.body.children)) {
|
|
3720
|
+
sanitizeElement(child);
|
|
3721
|
+
}
|
|
3722
|
+
return doc.body.innerHTML;
|
|
3723
|
+
}
|
|
3724
|
+
var BLOCK_TAGS = /* @__PURE__ */ new Set([
|
|
3725
|
+
"p",
|
|
3726
|
+
"h1",
|
|
3727
|
+
"h2",
|
|
3728
|
+
"h3",
|
|
3729
|
+
"h4",
|
|
3730
|
+
"h5",
|
|
3731
|
+
"h6",
|
|
3732
|
+
"div",
|
|
3733
|
+
"ul",
|
|
3734
|
+
"ol",
|
|
3735
|
+
"li",
|
|
3736
|
+
"table",
|
|
3737
|
+
"blockquote",
|
|
3738
|
+
"pre",
|
|
3739
|
+
"hr"
|
|
3740
|
+
]);
|
|
3741
|
+
function normalizeToBlockHtml(html) {
|
|
3742
|
+
if (!html) return "";
|
|
3743
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
3744
|
+
const body = doc.body;
|
|
3745
|
+
const childNodes = Array.from(body.childNodes);
|
|
3746
|
+
const needsWrap = childNodes.some((node) => {
|
|
3747
|
+
if (node.nodeType === Node.TEXT_NODE) return !!node.nodeValue?.trim();
|
|
3748
|
+
if (node.nodeType === Node.ELEMENT_NODE)
|
|
3749
|
+
return !BLOCK_TAGS.has(node.tagName.toLowerCase());
|
|
3750
|
+
return false;
|
|
3751
|
+
});
|
|
3752
|
+
if (!needsWrap) return html;
|
|
3753
|
+
while (body.firstChild) body.removeChild(body.firstChild);
|
|
3754
|
+
let pendingP = null;
|
|
3755
|
+
for (const node of childNodes) {
|
|
3756
|
+
const isBlock = node.nodeType === Node.ELEMENT_NODE && BLOCK_TAGS.has(node.tagName.toLowerCase());
|
|
3757
|
+
const isWhitespace = node.nodeType === Node.TEXT_NODE && !node.nodeValue?.trim();
|
|
3758
|
+
if (isBlock) {
|
|
3759
|
+
if (pendingP) {
|
|
3760
|
+
body.appendChild(pendingP);
|
|
3761
|
+
pendingP = null;
|
|
3762
|
+
}
|
|
3763
|
+
body.appendChild(node);
|
|
3764
|
+
} else if (!isWhitespace) {
|
|
3765
|
+
if (!pendingP) pendingP = doc.createElement("p");
|
|
3766
|
+
pendingP.appendChild(node);
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3769
|
+
if (pendingP) body.appendChild(pendingP);
|
|
3770
|
+
return body.innerHTML;
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
// src/Utils/Helper.ts
|
|
3549
3774
|
function findBlockByKind(kind) {
|
|
3550
3775
|
const root = $getRoot();
|
|
3551
3776
|
for (const child of root.getChildren()) {
|
|
@@ -3554,8 +3779,9 @@ function findBlockByKind(kind) {
|
|
|
3554
3779
|
return null;
|
|
3555
3780
|
}
|
|
3556
3781
|
function importHtmlIntoBlock(editor, block, html) {
|
|
3782
|
+
const safe = normalizeToBlockHtml(sanitizeHtml(html));
|
|
3557
3783
|
const parser = new DOMParser();
|
|
3558
|
-
const doc = parser.parseFromString(
|
|
3784
|
+
const doc = parser.parseFromString(safe || "<p></p>", "text/html");
|
|
3559
3785
|
const nodes = $generateNodesFromDOM(editor, doc);
|
|
3560
3786
|
block.clear();
|
|
3561
3787
|
block.append(...nodes);
|
|
@@ -3594,7 +3820,8 @@ function hasBlock(editor, kind) {
|
|
|
3594
3820
|
function RefApiPlugin({
|
|
3595
3821
|
forwardedRef,
|
|
3596
3822
|
contentEditableDomRef,
|
|
3597
|
-
focusedRef
|
|
3823
|
+
focusedRef,
|
|
3824
|
+
setRefErrors
|
|
3598
3825
|
}) {
|
|
3599
3826
|
const [editor] = useLexicalComposerContext();
|
|
3600
3827
|
useImperativeHandle(
|
|
@@ -3633,12 +3860,14 @@ function RefApiPlugin({
|
|
|
3633
3860
|
},
|
|
3634
3861
|
isFocused: () => focusedRef.current,
|
|
3635
3862
|
getEditor: () => editor,
|
|
3863
|
+
setErrors: (messages) => setRefErrors(messages),
|
|
3864
|
+
clearErrors: () => setRefErrors([]),
|
|
3636
3865
|
// Generic blocks (signature, footer, banner, etc.)
|
|
3637
3866
|
upsertBlock: (spec) => upsertBlock(editor, spec),
|
|
3638
3867
|
removeBlock: (kind) => removeBlock(editor, kind),
|
|
3639
3868
|
hasBlock: (kind) => hasBlock(editor, kind)
|
|
3640
3869
|
}),
|
|
3641
|
-
[editor, contentEditableDomRef, focusedRef]
|
|
3870
|
+
[editor, contentEditableDomRef, focusedRef, setRefErrors]
|
|
3642
3871
|
);
|
|
3643
3872
|
return null;
|
|
3644
3873
|
}
|
|
@@ -4278,8 +4507,8 @@ function SpellCheckPlugin({
|
|
|
4278
4507
|
function TableActionMenuPlugin({ disabled = false }) {
|
|
4279
4508
|
const [editor] = useLexicalComposerContext();
|
|
4280
4509
|
const [isInTable, setIsInTable] = React6.useState(false);
|
|
4510
|
+
const [anchorRect, setAnchorRect] = React6.useState(null);
|
|
4281
4511
|
const [open, setOpen] = React6.useState(false);
|
|
4282
|
-
const [menuPos, setMenuPos] = React6.useState(null);
|
|
4283
4512
|
const updateFromSelection = React6.useCallback(() => {
|
|
4284
4513
|
const root = editor.getRootElement();
|
|
4285
4514
|
if (!root) return;
|
|
@@ -4288,21 +4517,34 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
4288
4517
|
if ($isTableSelection(selection)) {
|
|
4289
4518
|
const tableNode = selection.getNodes().find((n) => $isTableNode(n));
|
|
4290
4519
|
if (tableNode) {
|
|
4291
|
-
|
|
4292
|
-
|
|
4520
|
+
const dom = editor.getElementByKey(tableNode.getKey());
|
|
4521
|
+
if (dom) {
|
|
4522
|
+
setIsInTable(true);
|
|
4523
|
+
setAnchorRect(dom.getBoundingClientRect());
|
|
4524
|
+
return;
|
|
4525
|
+
}
|
|
4293
4526
|
}
|
|
4294
4527
|
}
|
|
4295
4528
|
if (!$isRangeSelection(selection)) {
|
|
4296
4529
|
setIsInTable(false);
|
|
4530
|
+
setAnchorRect(null);
|
|
4297
4531
|
return;
|
|
4298
4532
|
}
|
|
4299
4533
|
const anchorNode = selection.anchor.getNode();
|
|
4300
4534
|
const cellNode = $isTableCellNode(anchorNode) ? anchorNode : $findMatchingParent(anchorNode, (n) => $isTableCellNode(n));
|
|
4301
4535
|
if (!cellNode || !$isTableCellNode(cellNode)) {
|
|
4302
4536
|
setIsInTable(false);
|
|
4537
|
+
setAnchorRect(null);
|
|
4538
|
+
return;
|
|
4539
|
+
}
|
|
4540
|
+
const cellDom = editor.getElementByKey(cellNode.getKey());
|
|
4541
|
+
if (!cellDom) {
|
|
4542
|
+
setIsInTable(false);
|
|
4543
|
+
setAnchorRect(null);
|
|
4303
4544
|
return;
|
|
4304
4545
|
}
|
|
4305
4546
|
setIsInTable(true);
|
|
4547
|
+
setAnchorRect(cellDom.getBoundingClientRect());
|
|
4306
4548
|
});
|
|
4307
4549
|
}, [editor]);
|
|
4308
4550
|
React6.useEffect(() => {
|
|
@@ -4364,33 +4606,18 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
4364
4606
|
React6.useEffect(() => {
|
|
4365
4607
|
if (!isInTable && open) setOpen(false);
|
|
4366
4608
|
}, [isInTable, open]);
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
if (!
|
|
4370
|
-
const
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
return;
|
|
4378
|
-
}
|
|
4379
|
-
if ($isRangeSelection(selection)) {
|
|
4380
|
-
const node = selection.anchor.getNode();
|
|
4381
|
-
const cell = $isTableCellNode(node) ? node : $findMatchingParent(node, (n) => $isTableCellNode(n));
|
|
4382
|
-
if (cell) inTable = true;
|
|
4383
|
-
}
|
|
4384
|
-
});
|
|
4385
|
-
if (inTable) {
|
|
4386
|
-
e.preventDefault();
|
|
4387
|
-
setMenuPos({ x: e.clientX, y: e.clientY });
|
|
4388
|
-
setOpen(true);
|
|
4389
|
-
}
|
|
4609
|
+
const canShow = isInTable && !!anchorRect && !disabled;
|
|
4610
|
+
const handleStyle = React6.useMemo(() => {
|
|
4611
|
+
if (!anchorRect) return void 0;
|
|
4612
|
+
const top = Math.max(8, anchorRect.top + 6);
|
|
4613
|
+
const left = Math.max(8, anchorRect.right - 34);
|
|
4614
|
+
return {
|
|
4615
|
+
position: "fixed",
|
|
4616
|
+
top,
|
|
4617
|
+
left,
|
|
4618
|
+
zIndex: 9999
|
|
4390
4619
|
};
|
|
4391
|
-
|
|
4392
|
-
return () => root.removeEventListener("contextmenu", handleContextMenu);
|
|
4393
|
-
}, [editor, disabled]);
|
|
4620
|
+
}, [anchorRect]);
|
|
4394
4621
|
const dangerStyle = {
|
|
4395
4622
|
color: "var(--colorPaletteRedForeground1)"
|
|
4396
4623
|
};
|
|
@@ -4423,55 +4650,63 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
4423
4650
|
const table = $getTableNodeFromLexicalNodeOrThrow(cell);
|
|
4424
4651
|
table.remove();
|
|
4425
4652
|
});
|
|
4426
|
-
|
|
4427
|
-
if (!menuPos) return void 0;
|
|
4428
|
-
return {
|
|
4429
|
-
getBoundingClientRect: () => new DOMRect(menuPos.x, menuPos.y, 0, 0)
|
|
4430
|
-
};
|
|
4431
|
-
}, [menuPos]);
|
|
4432
|
-
if (disabled) return null;
|
|
4653
|
+
if (!canShow || !handleStyle) return null;
|
|
4433
4654
|
return createPortal(
|
|
4434
|
-
/* @__PURE__ */ jsx(
|
|
4435
|
-
/* @__PURE__ */
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
/* @__PURE__ */ jsx(
|
|
4450
|
-
|
|
4655
|
+
/* @__PURE__ */ jsx("div", { style: handleStyle, className: "aoTableActionHandleRoot", children: /* @__PURE__ */ jsxs(Menu, { open, onOpenChange: (_, data) => setOpen(data.open), children: [
|
|
4656
|
+
/* @__PURE__ */ jsx(MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
|
|
4657
|
+
"button",
|
|
4658
|
+
{
|
|
4659
|
+
type: "button",
|
|
4660
|
+
className: "aoTableActionHandleBtn",
|
|
4661
|
+
"aria-label": "Table options",
|
|
4662
|
+
onMouseDown: (e) => {
|
|
4663
|
+
e.preventDefault();
|
|
4664
|
+
},
|
|
4665
|
+
children: /* @__PURE__ */ jsx(ChevronDown12Regular, {})
|
|
4666
|
+
}
|
|
4667
|
+
) }),
|
|
4668
|
+
/* @__PURE__ */ jsx(MenuPopover, { className: "aoTableActionPopover", children: /* @__PURE__ */ jsxs(MenuList, { children: [
|
|
4669
|
+
/* @__PURE__ */ jsxs(MenuGroup, { children: [
|
|
4670
|
+
/* @__PURE__ */ jsx(MenuGroupHeader, { children: "Insert" }),
|
|
4671
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(RowTripleRegular, {}), onClick: insertRowAbove, children: /* @__PURE__ */ jsxs("span", { className: "aoMenuRow", children: [
|
|
4672
|
+
/* @__PURE__ */ jsxs("span", { className: "aoMenuLabel", children: [
|
|
4673
|
+
/* @__PURE__ */ jsx(ArrowUpRegular, {}),
|
|
4674
|
+
" Row above"
|
|
4675
|
+
] }),
|
|
4676
|
+
/* @__PURE__ */ jsx("span", { className: "aoMenuShortcut", children: "Alt \u21E7 \u2191" })
|
|
4677
|
+
] }) }),
|
|
4678
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(RowTripleRegular, {}), onClick: insertRowBelow, children: /* @__PURE__ */ jsxs("span", { className: "aoMenuRow", children: [
|
|
4679
|
+
/* @__PURE__ */ jsxs("span", { className: "aoMenuLabel", children: [
|
|
4680
|
+
/* @__PURE__ */ jsx(ArrowDownRegular, {}),
|
|
4681
|
+
" Row below"
|
|
4682
|
+
] }),
|
|
4683
|
+
/* @__PURE__ */ jsx("span", { className: "aoMenuShortcut", children: "Alt \u21E7 \u2193" })
|
|
4684
|
+
] }) }),
|
|
4685
|
+
/* @__PURE__ */ jsx(MenuDivider, {}),
|
|
4686
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(ColumnTripleRegular, {}), onClick: insertColLeft, children: /* @__PURE__ */ jsxs("span", { className: "aoMenuRow", children: [
|
|
4687
|
+
/* @__PURE__ */ jsxs("span", { className: "aoMenuLabel", children: [
|
|
4688
|
+
/* @__PURE__ */ jsx(ArrowLeftRegular, {}),
|
|
4689
|
+
" Column left"
|
|
4690
|
+
] }),
|
|
4691
|
+
/* @__PURE__ */ jsx("span", { className: "aoMenuShortcut", children: "Alt \u21E7 \u2190" })
|
|
4692
|
+
] }) }),
|
|
4693
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(ColumnTripleRegular, {}), onClick: insertColRight, children: /* @__PURE__ */ jsxs("span", { className: "aoMenuRow", children: [
|
|
4694
|
+
/* @__PURE__ */ jsxs("span", { className: "aoMenuLabel", children: [
|
|
4695
|
+
/* @__PURE__ */ jsx(ArrowRightRegular, {}),
|
|
4696
|
+
" Column right"
|
|
4697
|
+
] }),
|
|
4698
|
+
/* @__PURE__ */ jsx("span", { className: "aoMenuShortcut", children: "Alt \u21E7 \u2192" })
|
|
4699
|
+
] }) })
|
|
4700
|
+
] }),
|
|
4451
4701
|
/* @__PURE__ */ jsx(MenuDivider, {}),
|
|
4452
|
-
/* @__PURE__ */
|
|
4453
|
-
/* @__PURE__ */
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
/* @__PURE__ */ jsxs("span", { className: "aoMenuLabel", children: [
|
|
4461
|
-
/* @__PURE__ */ jsx(ArrowRightRegular, {}),
|
|
4462
|
-
" Column right"
|
|
4463
|
-
] }),
|
|
4464
|
-
/* @__PURE__ */ jsx("span", { className: "aoMenuShortcut", children: "Alt \u21E7 \u2192" })
|
|
4465
|
-
] }) })
|
|
4466
|
-
] }),
|
|
4467
|
-
/* @__PURE__ */ jsx(MenuDivider, {}),
|
|
4468
|
-
/* @__PURE__ */ jsxs(MenuGroup, { children: [
|
|
4469
|
-
/* @__PURE__ */ jsx(MenuGroupHeader, { children: "Delete" }),
|
|
4470
|
-
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(DeleteRegular, {}), onClick: deleteRow, style: dangerStyle, children: "Delete row" }),
|
|
4471
|
-
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(DeleteRegular, {}), onClick: deleteCol, style: dangerStyle, children: "Delete column" }),
|
|
4472
|
-
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(DeleteRegular, {}), onClick: deleteTable, style: dangerStyle, children: "Delete table" })
|
|
4473
|
-
] })
|
|
4474
|
-
] }) }) }),
|
|
4702
|
+
/* @__PURE__ */ jsxs(MenuGroup, { children: [
|
|
4703
|
+
/* @__PURE__ */ jsx(MenuGroupHeader, { children: "Delete" }),
|
|
4704
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(DeleteRegular, {}), onClick: deleteRow, style: dangerStyle, children: "Delete row" }),
|
|
4705
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(DeleteRegular, {}), onClick: deleteCol, style: dangerStyle, children: "Delete column" }),
|
|
4706
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(DeleteRegular, {}), onClick: deleteTable, style: dangerStyle, children: "Delete table" })
|
|
4707
|
+
] })
|
|
4708
|
+
] }) })
|
|
4709
|
+
] }) }),
|
|
4475
4710
|
document.body
|
|
4476
4711
|
);
|
|
4477
4712
|
}
|
|
@@ -4775,13 +5010,6 @@ function getToolbarGroupsByLevel(level) {
|
|
|
4775
5010
|
];
|
|
4776
5011
|
}
|
|
4777
5012
|
}
|
|
4778
|
-
var DEFAULT_FONT_SIZE = 15;
|
|
4779
|
-
var formatParagraph = (editor) => {
|
|
4780
|
-
editor.update(() => {
|
|
4781
|
-
const selection = $getSelection();
|
|
4782
|
-
$setBlocksType(selection, () => $createParagraphNode());
|
|
4783
|
-
});
|
|
4784
|
-
};
|
|
4785
5013
|
var PRESET = [
|
|
4786
5014
|
"#000000",
|
|
4787
5015
|
"#434343",
|
|
@@ -4857,11 +5085,12 @@ var hsvToRgb = (h, s, v) => {
|
|
|
4857
5085
|
b: Math.round((bb + m) * 255)
|
|
4858
5086
|
};
|
|
4859
5087
|
};
|
|
4860
|
-
function useDrag(onMove, onEnd) {
|
|
5088
|
+
function useDrag(onMove, onEnd, interactingRef) {
|
|
4861
5089
|
const draggingRef = React6.useRef(false);
|
|
4862
5090
|
const start = React6.useCallback(
|
|
4863
5091
|
(e) => {
|
|
4864
5092
|
draggingRef.current = true;
|
|
5093
|
+
if (interactingRef) interactingRef.current = true;
|
|
4865
5094
|
onMove(e.clientX, e.clientY);
|
|
4866
5095
|
const move = (ev) => {
|
|
4867
5096
|
if (!draggingRef.current) return;
|
|
@@ -4871,17 +5100,55 @@ function useDrag(onMove, onEnd) {
|
|
|
4871
5100
|
draggingRef.current = false;
|
|
4872
5101
|
window.removeEventListener("mousemove", move);
|
|
4873
5102
|
window.removeEventListener("mouseup", up);
|
|
5103
|
+
if (interactingRef) {
|
|
5104
|
+
const clearFlag = () => {
|
|
5105
|
+
interactingRef.current = false;
|
|
5106
|
+
};
|
|
5107
|
+
window.addEventListener("click", clearFlag, { once: true });
|
|
5108
|
+
setTimeout(() => {
|
|
5109
|
+
window.removeEventListener("click", clearFlag);
|
|
5110
|
+
interactingRef.current = false;
|
|
5111
|
+
}, 0);
|
|
5112
|
+
}
|
|
4874
5113
|
};
|
|
4875
5114
|
window.addEventListener("mousemove", move);
|
|
4876
5115
|
window.addEventListener("mouseup", up);
|
|
4877
5116
|
},
|
|
4878
|
-
[onMove, onEnd]
|
|
5117
|
+
[onMove, onEnd, interactingRef]
|
|
4879
5118
|
);
|
|
4880
5119
|
return start;
|
|
4881
5120
|
}
|
|
4882
5121
|
var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
|
|
4883
5122
|
const [open, setOpen] = React6.useState(false);
|
|
4884
5123
|
const btnRef = React6.useRef(null);
|
|
5124
|
+
const interactingRef = React6.useRef(false);
|
|
5125
|
+
const handleDismiss = React6.useCallback(() => setOpen(false), []);
|
|
5126
|
+
const preventDismissOnEvent = React6.useCallback(
|
|
5127
|
+
(ev) => {
|
|
5128
|
+
if (interactingRef.current) return true;
|
|
5129
|
+
return ev.type !== "click";
|
|
5130
|
+
},
|
|
5131
|
+
[]
|
|
5132
|
+
);
|
|
5133
|
+
const [, forceReposition] = React6.useState(0);
|
|
5134
|
+
React6.useEffect(() => {
|
|
5135
|
+
if (!open) return;
|
|
5136
|
+
let rafId = null;
|
|
5137
|
+
const reposition = () => {
|
|
5138
|
+
if (rafId != null) return;
|
|
5139
|
+
rafId = requestAnimationFrame(() => {
|
|
5140
|
+
rafId = null;
|
|
5141
|
+
forceReposition((n) => n + 1);
|
|
5142
|
+
});
|
|
5143
|
+
};
|
|
5144
|
+
window.addEventListener("scroll", reposition, true);
|
|
5145
|
+
window.addEventListener("resize", reposition);
|
|
5146
|
+
return () => {
|
|
5147
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
5148
|
+
window.removeEventListener("scroll", reposition, true);
|
|
5149
|
+
window.removeEventListener("resize", reposition);
|
|
5150
|
+
};
|
|
5151
|
+
}, [open]);
|
|
4885
5152
|
const [hex, setHex] = React6.useState(normalizeHex(value || "#000000"));
|
|
4886
5153
|
const { r, g, b } = React6.useMemo(() => hexToRgb(hex), [hex]);
|
|
4887
5154
|
const hsv = React6.useMemo(() => rgbToHsv(r, g, b), [r, g, b]);
|
|
@@ -4922,7 +5189,7 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
|
|
|
4922
5189
|
},
|
|
4923
5190
|
[h, commitHsv]
|
|
4924
5191
|
);
|
|
4925
|
-
const startSV = useDrag(onSVMove);
|
|
5192
|
+
const startSV = useDrag(onSVMove, void 0, interactingRef);
|
|
4926
5193
|
const hueRef = React6.useRef(null);
|
|
4927
5194
|
const onHueMove = React6.useCallback(
|
|
4928
5195
|
(clientX) => {
|
|
@@ -4935,7 +5202,7 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
|
|
|
4935
5202
|
},
|
|
4936
5203
|
[s, v, commitHsv]
|
|
4937
5204
|
);
|
|
4938
|
-
const startHue = useDrag((x) => onHueMove(x));
|
|
5205
|
+
const startHue = useDrag((x) => onHueMove(x), void 0, interactingRef);
|
|
4939
5206
|
const svThumb = React6.useMemo(() => ({ left: `${s * 100}%`, top: `${(1 - v) * 100}%` }), [s, v]);
|
|
4940
5207
|
const hueThumb = React6.useMemo(() => ({ left: `${h / 360 * 100}%` }), [h]);
|
|
4941
5208
|
const hueColor = React6.useMemo(() => {
|
|
@@ -4984,10 +5251,11 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
|
|
|
4984
5251
|
Callout,
|
|
4985
5252
|
{
|
|
4986
5253
|
target: btnRef,
|
|
4987
|
-
onDismiss:
|
|
5254
|
+
onDismiss: handleDismiss,
|
|
4988
5255
|
setInitialFocus: true,
|
|
4989
5256
|
directionalHint: 4,
|
|
4990
5257
|
className: "aoColorCallout",
|
|
5258
|
+
preventDismissOnEvent,
|
|
4991
5259
|
children: /* @__PURE__ */ jsxs(Stack, { tokens: { childrenGap: 10 }, styles: { root: { padding: 12, width: 320 } }, children: [
|
|
4992
5260
|
/* @__PURE__ */ jsxs("div", { className: "aoLexRow", children: [
|
|
4993
5261
|
/* @__PURE__ */ jsx("div", { className: "aoLexSwatch", style: { background: hex } }),
|
|
@@ -5087,7 +5355,9 @@ var ColorPickerPlugin = ({ disabled }) => {
|
|
|
5087
5355
|
}, [editor]);
|
|
5088
5356
|
const applyStyle = (args) => {
|
|
5089
5357
|
if (disabled) return;
|
|
5090
|
-
editor.
|
|
5358
|
+
const root = editor.getRootElement();
|
|
5359
|
+
const editorIsActive = !!lastRangeSelectionRef.current && !!root && (document.activeElement === root || root.contains(document.activeElement));
|
|
5360
|
+
if (editorIsActive) editor.focus();
|
|
5091
5361
|
editor.update(() => {
|
|
5092
5362
|
const saved = lastRangeSelectionRef.current;
|
|
5093
5363
|
if (saved) {
|
|
@@ -5226,6 +5496,7 @@ var FontFamilyPlugin = ({ disabled = false }) => {
|
|
|
5226
5496
|
"font-family"
|
|
5227
5497
|
);
|
|
5228
5498
|
};
|
|
5499
|
+
var DEFAULT_FONT_SIZE = 15;
|
|
5229
5500
|
var FONT_SIZE_OPTIONS = [
|
|
5230
5501
|
"8",
|
|
5231
5502
|
"9",
|
|
@@ -5526,21 +5797,27 @@ var TableItemPlugin = ({ disabled }) => {
|
|
|
5526
5797
|
Input,
|
|
5527
5798
|
{
|
|
5528
5799
|
autoFocus: !disabled,
|
|
5800
|
+
type: "number",
|
|
5801
|
+
min: 1,
|
|
5529
5802
|
value: rows,
|
|
5530
5803
|
placeholder: "Rows",
|
|
5531
5804
|
appearance: "underline",
|
|
5532
5805
|
disabled,
|
|
5533
|
-
|
|
5806
|
+
input: { style: { textAlign: "left" } },
|
|
5807
|
+
onChange: (_, v) => setRows(v.value.replace(/\D/g, ""))
|
|
5534
5808
|
}
|
|
5535
5809
|
) }),
|
|
5536
5810
|
/* @__PURE__ */ jsx(Field, { label: "Columns", orientation: "horizontal", size: "small", children: /* @__PURE__ */ jsx(
|
|
5537
5811
|
Input,
|
|
5538
5812
|
{
|
|
5813
|
+
type: "number",
|
|
5814
|
+
min: 1,
|
|
5539
5815
|
value: columns,
|
|
5540
5816
|
placeholder: "Columns",
|
|
5541
5817
|
appearance: "underline",
|
|
5542
5818
|
disabled,
|
|
5543
|
-
|
|
5819
|
+
input: { style: { textAlign: "left" } },
|
|
5820
|
+
onChange: (_, v) => setColumns(v.value.replace(/\D/g, ""))
|
|
5544
5821
|
}
|
|
5545
5822
|
) }),
|
|
5546
5823
|
/* @__PURE__ */ jsxs(Stack, { horizontal: true, horizontalAlign: "end", tokens: { childrenGap: 6 }, children: [
|
|
@@ -5697,8 +5974,7 @@ var ToolBarPlugins = (props) => {
|
|
|
5697
5974
|
const [isLowercase, setIsLowercase] = useState(false);
|
|
5698
5975
|
const [isCapitalize, setIsCapitalize] = useState(false);
|
|
5699
5976
|
const [alignment, setAlignment] = useState("left");
|
|
5700
|
-
const
|
|
5701
|
-
const [tableNodeKey, setTableNodeKey] = useState(null);
|
|
5977
|
+
const lastSelectionRef = React6__default.useRef(null);
|
|
5702
5978
|
const presetGroups = getToolbarGroupsByLevel(props.level);
|
|
5703
5979
|
const pluginGroups = useMemo(() => sanitizePluginGroups(presetGroups), [presetGroups]);
|
|
5704
5980
|
const updateToolbarPlugins = () => {
|
|
@@ -5715,8 +5991,6 @@ var ToolBarPlugins = (props) => {
|
|
|
5715
5991
|
setIsLowercase(false);
|
|
5716
5992
|
setIsCapitalize(false);
|
|
5717
5993
|
setSelectNodeType("paragraph");
|
|
5718
|
-
setIsInTable(false);
|
|
5719
|
-
setTableNodeKey(null);
|
|
5720
5994
|
return;
|
|
5721
5995
|
}
|
|
5722
5996
|
setIsBold(selection.hasFormat("bold"));
|
|
@@ -5732,21 +6006,8 @@ var ToolBarPlugins = (props) => {
|
|
|
5732
6006
|
const anchorNode = selection.anchor.getNode();
|
|
5733
6007
|
if (anchorNode.getKey() === "root") {
|
|
5734
6008
|
setSelectNodeType("paragraph");
|
|
5735
|
-
setIsInTable(false);
|
|
5736
|
-
setTableNodeKey(null);
|
|
5737
6009
|
return;
|
|
5738
6010
|
}
|
|
5739
|
-
let tableAncestorKey = null;
|
|
5740
|
-
let cursor = anchorNode.getParent();
|
|
5741
|
-
while (cursor !== null) {
|
|
5742
|
-
if (cursor.getType() === "table") {
|
|
5743
|
-
tableAncestorKey = cursor.getKey();
|
|
5744
|
-
break;
|
|
5745
|
-
}
|
|
5746
|
-
cursor = cursor.getParent();
|
|
5747
|
-
}
|
|
5748
|
-
setIsInTable(tableAncestorKey !== null);
|
|
5749
|
-
setTableNodeKey(tableAncestorKey);
|
|
5750
6011
|
const element = anchorNode.getTopLevelElementOrThrow();
|
|
5751
6012
|
setAlignment(
|
|
5752
6013
|
typeof element.getFormatType === "function" ? element.getFormatType() || "left" : "left"
|
|
@@ -5767,12 +6028,21 @@ var ToolBarPlugins = (props) => {
|
|
|
5767
6028
|
["paragraph", "h1", "h2", "h3", "h4", "h5", "h6", "ul", "ol", "quote", "code"].includes(type) ? type : "paragraph"
|
|
5768
6029
|
);
|
|
5769
6030
|
};
|
|
6031
|
+
const applyToBlock = React6__default.useCallback(
|
|
6032
|
+
(fn) => {
|
|
6033
|
+
editor.update(() => {
|
|
6034
|
+
const saved = lastSelectionRef.current;
|
|
6035
|
+
if (saved) $setSelection(saved.clone());
|
|
6036
|
+
const sel = $getSelection();
|
|
6037
|
+
if ($isRangeSelection(sel)) fn(sel);
|
|
6038
|
+
});
|
|
6039
|
+
},
|
|
6040
|
+
[editor]
|
|
6041
|
+
);
|
|
5770
6042
|
const formatQuote = () => {
|
|
5771
|
-
|
|
5772
|
-
const selection = $getSelection();
|
|
5773
|
-
if (!$isRangeSelection(selection)) return;
|
|
6043
|
+
applyToBlock((selection) => {
|
|
5774
6044
|
if (selectNodeType === "quote") {
|
|
5775
|
-
|
|
6045
|
+
$setBlocksType(selection, () => $createParagraphNode());
|
|
5776
6046
|
} else {
|
|
5777
6047
|
$setBlocksType(selection, () => $createQuoteNode());
|
|
5778
6048
|
}
|
|
@@ -5791,6 +6061,8 @@ var ToolBarPlugins = (props) => {
|
|
|
5791
6061
|
editor.registerCommand(
|
|
5792
6062
|
SELECTION_CHANGE_COMMAND,
|
|
5793
6063
|
() => {
|
|
6064
|
+
const sel = $getSelection();
|
|
6065
|
+
if ($isRangeSelection(sel)) lastSelectionRef.current = sel.clone();
|
|
5794
6066
|
updateToolbarPlugins();
|
|
5795
6067
|
return false;
|
|
5796
6068
|
},
|
|
@@ -5822,16 +6094,52 @@ var ToolBarPlugins = (props) => {
|
|
|
5822
6094
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "highlight");
|
|
5823
6095
|
break;
|
|
5824
6096
|
case "leftAlign" /* LeftAlign */:
|
|
5825
|
-
|
|
6097
|
+
applyToBlock((sel) => {
|
|
6098
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6099
|
+
sel.getNodes().forEach((n) => {
|
|
6100
|
+
const t = n.getTopLevelElementOrThrow();
|
|
6101
|
+
if (!seen.has(t.getKey())) {
|
|
6102
|
+
seen.add(t.getKey());
|
|
6103
|
+
t.setFormat("left");
|
|
6104
|
+
}
|
|
6105
|
+
});
|
|
6106
|
+
});
|
|
5826
6107
|
break;
|
|
5827
6108
|
case "rightAlign" /* RightAlign */:
|
|
5828
|
-
|
|
6109
|
+
applyToBlock((sel) => {
|
|
6110
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6111
|
+
sel.getNodes().forEach((n) => {
|
|
6112
|
+
const t = n.getTopLevelElementOrThrow();
|
|
6113
|
+
if (!seen.has(t.getKey())) {
|
|
6114
|
+
seen.add(t.getKey());
|
|
6115
|
+
t.setFormat("right");
|
|
6116
|
+
}
|
|
6117
|
+
});
|
|
6118
|
+
});
|
|
5829
6119
|
break;
|
|
5830
6120
|
case "centerAlign" /* CenterAlign */:
|
|
5831
|
-
|
|
6121
|
+
applyToBlock((sel) => {
|
|
6122
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6123
|
+
sel.getNodes().forEach((n) => {
|
|
6124
|
+
const t = n.getTopLevelElementOrThrow();
|
|
6125
|
+
if (!seen.has(t.getKey())) {
|
|
6126
|
+
seen.add(t.getKey());
|
|
6127
|
+
t.setFormat("center");
|
|
6128
|
+
}
|
|
6129
|
+
});
|
|
6130
|
+
});
|
|
5832
6131
|
break;
|
|
5833
6132
|
case "justifyAlign" /* JustifyAlign */:
|
|
5834
|
-
|
|
6133
|
+
applyToBlock((sel) => {
|
|
6134
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6135
|
+
sel.getNodes().forEach((n) => {
|
|
6136
|
+
const t = n.getTopLevelElementOrThrow();
|
|
6137
|
+
if (!seen.has(t.getKey())) {
|
|
6138
|
+
seen.add(t.getKey());
|
|
6139
|
+
t.setFormat("justify");
|
|
6140
|
+
}
|
|
6141
|
+
});
|
|
6142
|
+
});
|
|
5835
6143
|
break;
|
|
5836
6144
|
case "undo" /* Undo */:
|
|
5837
6145
|
editor.dispatchCommand(UNDO_COMMAND, void 0);
|
|
@@ -5851,14 +6159,8 @@ var ToolBarPlugins = (props) => {
|
|
|
5851
6159
|
}
|
|
5852
6160
|
};
|
|
5853
6161
|
const updateHeading = (heading) => {
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
if ($isRangeSelection(selection)) {
|
|
5857
|
-
$setBlocksType(selection, () => $createHeadingNode(heading));
|
|
5858
|
-
}
|
|
5859
|
-
});
|
|
5860
|
-
editor.getEditorState().read(() => {
|
|
5861
|
-
updateToolbarPlugins();
|
|
6162
|
+
applyToBlock((selection) => {
|
|
6163
|
+
$setBlocksType(selection, () => $createHeadingNode(heading));
|
|
5862
6164
|
});
|
|
5863
6165
|
};
|
|
5864
6166
|
const renderToken = (token, groupIndex, tokenIndex) => {
|
|
@@ -5997,7 +6299,7 @@ var ToolBarPlugins = (props) => {
|
|
|
5997
6299
|
const val = data.optionValue;
|
|
5998
6300
|
if (!val) return;
|
|
5999
6301
|
if (val === "paragraph") {
|
|
6000
|
-
|
|
6302
|
+
applyToBlock((sel) => $setBlocksType(sel, () => $createParagraphNode()));
|
|
6001
6303
|
setSelectNodeType("paragraph");
|
|
6002
6304
|
} else {
|
|
6003
6305
|
updateHeading(val);
|
|
@@ -6081,16 +6383,10 @@ var ToolBarPlugins = (props) => {
|
|
|
6081
6383
|
onHandleSelectOption("highlight" /* Highlight */);
|
|
6082
6384
|
break;
|
|
6083
6385
|
case "ul-list":
|
|
6084
|
-
editor.dispatchCommand(
|
|
6085
|
-
selectNodeType === "ul" ? REMOVE_LIST_COMMAND : INSERT_UNORDERED_LIST_COMMAND,
|
|
6086
|
-
void 0
|
|
6087
|
-
);
|
|
6386
|
+
editor.dispatchCommand(selectNodeType === "ul" ? REMOVE_LIST_COMMAND : INSERT_UNORDERED_LIST_COMMAND, void 0);
|
|
6088
6387
|
break;
|
|
6089
6388
|
case "ol-list":
|
|
6090
|
-
editor.dispatchCommand(
|
|
6091
|
-
selectNodeType === "ol" ? REMOVE_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND,
|
|
6092
|
-
void 0
|
|
6093
|
-
);
|
|
6389
|
+
editor.dispatchCommand(selectNodeType === "ol" ? REMOVE_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND, void 0);
|
|
6094
6390
|
break;
|
|
6095
6391
|
case "page-break":
|
|
6096
6392
|
editor.dispatchCommand(INSERT_PAGE_BREAK, void 0);
|
|
@@ -6126,12 +6422,7 @@ var ToolBarPlugins = (props) => {
|
|
|
6126
6422
|
"Superscript"
|
|
6127
6423
|
] }),
|
|
6128
6424
|
/* @__PURE__ */ jsxs(Option, { value: "highlight", text: "Highlight", children: [
|
|
6129
|
-
/* @__PURE__ */ jsx(
|
|
6130
|
-
HighlightAccentFilled,
|
|
6131
|
-
{
|
|
6132
|
-
style: { ...optionIconStyle, color: isEditable ? brand : fgDisabled }
|
|
6133
|
-
}
|
|
6134
|
-
),
|
|
6425
|
+
/* @__PURE__ */ jsx(HighlightAccentFilled, { style: { ...optionIconStyle, color: isEditable ? brand : fgDisabled } }),
|
|
6135
6426
|
"Highlight"
|
|
6136
6427
|
] }),
|
|
6137
6428
|
/* @__PURE__ */ jsxs(Option, { value: "ul-list", text: "Bullet list", children: [
|
|
@@ -6167,30 +6458,10 @@ var ToolBarPlugins = (props) => {
|
|
|
6167
6458
|
// );
|
|
6168
6459
|
case "Align": {
|
|
6169
6460
|
const ALIGN_OPTIONS = [
|
|
6170
|
-
{
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
action: "leftAlign" /* LeftAlign */
|
|
6175
|
-
},
|
|
6176
|
-
{
|
|
6177
|
-
value: "center",
|
|
6178
|
-
label: "Center Align",
|
|
6179
|
-
icon: /* @__PURE__ */ jsx(TextAlignCenterFilled, { style: optionIconStyle }),
|
|
6180
|
-
action: "centerAlign" /* CenterAlign */
|
|
6181
|
-
},
|
|
6182
|
-
{
|
|
6183
|
-
value: "right",
|
|
6184
|
-
label: "Right Align",
|
|
6185
|
-
icon: /* @__PURE__ */ jsx(TextAlignRightFilled, { style: optionIconStyle }),
|
|
6186
|
-
action: "rightAlign" /* RightAlign */
|
|
6187
|
-
},
|
|
6188
|
-
{
|
|
6189
|
-
value: "justify",
|
|
6190
|
-
label: "Justify Align",
|
|
6191
|
-
icon: /* @__PURE__ */ jsx(TextAlignJustifyFilled, { style: optionIconStyle }),
|
|
6192
|
-
action: "justifyAlign" /* JustifyAlign */
|
|
6193
|
-
}
|
|
6461
|
+
{ value: "left", label: "Left Align", icon: /* @__PURE__ */ jsx(TextAlignLeftFilled, { style: optionIconStyle }), action: "leftAlign" /* LeftAlign */ },
|
|
6462
|
+
{ value: "center", label: "Center Align", icon: /* @__PURE__ */ jsx(TextAlignCenterFilled, { style: optionIconStyle }), action: "centerAlign" /* CenterAlign */ },
|
|
6463
|
+
{ value: "right", label: "Right Align", icon: /* @__PURE__ */ jsx(TextAlignRightFilled, { style: optionIconStyle }), action: "rightAlign" /* RightAlign */ },
|
|
6464
|
+
{ value: "justify", label: "Justify Align", icon: /* @__PURE__ */ jsx(TextAlignJustifyFilled, { style: optionIconStyle }), action: "justifyAlign" /* JustifyAlign */ }
|
|
6194
6465
|
];
|
|
6195
6466
|
const alignLabel = ALIGN_OPTIONS.find((o) => o.value === alignment)?.label ?? "Left Align";
|
|
6196
6467
|
return /* @__PURE__ */ jsx(
|
|
@@ -6224,69 +6495,29 @@ var ToolBarPlugins = (props) => {
|
|
|
6224
6495
|
if (!pluginGroups || pluginGroups.length === 0) {
|
|
6225
6496
|
return null;
|
|
6226
6497
|
}
|
|
6227
|
-
return /* @__PURE__ */
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
),
|
|
6251
|
-
isInTable && /* @__PURE__ */ jsxs(
|
|
6252
|
-
"div",
|
|
6253
|
-
{
|
|
6254
|
-
style: {
|
|
6255
|
-
display: "flex",
|
|
6256
|
-
alignItems: "center",
|
|
6257
|
-
gap: 6,
|
|
6258
|
-
padding: "2px 8px",
|
|
6259
|
-
borderBottom: "1px solid #ccced1",
|
|
6260
|
-
background: "#fff8f8"
|
|
6261
|
-
},
|
|
6262
|
-
children: [
|
|
6263
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#888", userSelect: "none" }, children: "Table" }),
|
|
6264
|
-
/* @__PURE__ */ jsx(
|
|
6265
|
-
Button,
|
|
6266
|
-
{
|
|
6267
|
-
size: "small",
|
|
6268
|
-
icon: /* @__PURE__ */ jsx(DeleteRegular, { style: { color: "#c4272c" } }),
|
|
6269
|
-
title: "Delete table",
|
|
6270
|
-
style: {
|
|
6271
|
-
background: "transparent",
|
|
6272
|
-
border: "none",
|
|
6273
|
-
color: "#c4272c",
|
|
6274
|
-
fontWeight: 500
|
|
6275
|
-
},
|
|
6276
|
-
onClick: () => {
|
|
6277
|
-
editor.update(() => {
|
|
6278
|
-
if (!tableNodeKey) return;
|
|
6279
|
-
const node = $getNodeByKey(tableNodeKey);
|
|
6280
|
-
if (node?.getType() === "table") node.remove();
|
|
6281
|
-
});
|
|
6282
|
-
},
|
|
6283
|
-
children: "Delete Table"
|
|
6284
|
-
}
|
|
6285
|
-
)
|
|
6286
|
-
]
|
|
6287
|
-
}
|
|
6288
|
-
)
|
|
6289
|
-
] });
|
|
6498
|
+
return /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(
|
|
6499
|
+
"div",
|
|
6500
|
+
{
|
|
6501
|
+
role: "toolbar",
|
|
6502
|
+
"aria-label": "Editor toolbar",
|
|
6503
|
+
style: {
|
|
6504
|
+
display: "flex",
|
|
6505
|
+
flexWrap: "wrap",
|
|
6506
|
+
alignItems: "center",
|
|
6507
|
+
borderBottom: "1px solid #ccced1",
|
|
6508
|
+
background: "#ffffff",
|
|
6509
|
+
padding: "0px",
|
|
6510
|
+
minHeight: 36
|
|
6511
|
+
},
|
|
6512
|
+
children: pluginGroups.map((group, groupIndex) => /* @__PURE__ */ jsx(React6__default.Fragment, { children: group.map((token, tokenIndex) => {
|
|
6513
|
+
try {
|
|
6514
|
+
return renderToken(token, groupIndex, tokenIndex);
|
|
6515
|
+
} catch {
|
|
6516
|
+
return null;
|
|
6517
|
+
}
|
|
6518
|
+
}) }, `group-${groupIndex}`))
|
|
6519
|
+
}
|
|
6520
|
+
) });
|
|
6290
6521
|
};
|
|
6291
6522
|
function isYoutubeLikeNode(node) {
|
|
6292
6523
|
try {
|
|
@@ -6439,10 +6670,23 @@ function BrowserSpellCheckPlugin({ enabled }) {
|
|
|
6439
6670
|
function WordCountPlugin({ onCountChange }) {
|
|
6440
6671
|
const [editor] = useLexicalComposerContext();
|
|
6441
6672
|
useEffect(() => {
|
|
6442
|
-
return editor.registerUpdateListener(() => {
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6673
|
+
return editor.registerUpdateListener(({ editorState }) => {
|
|
6674
|
+
editorState.read(() => {
|
|
6675
|
+
const text = $getRoot().getTextContent();
|
|
6676
|
+
const words = text.trim() === "" ? 0 : text.trim().split(/\s+/).length;
|
|
6677
|
+
onCountChange(words);
|
|
6678
|
+
});
|
|
6679
|
+
});
|
|
6680
|
+
}, [editor, onCountChange]);
|
|
6681
|
+
return null;
|
|
6682
|
+
}
|
|
6683
|
+
function CharCountPlugin({ onCountChange }) {
|
|
6684
|
+
const [editor] = useLexicalComposerContext();
|
|
6685
|
+
useEffect(() => {
|
|
6686
|
+
return editor.registerUpdateListener(({ editorState }) => {
|
|
6687
|
+
editorState.read(() => {
|
|
6688
|
+
onCountChange($getRoot().getTextContent().length);
|
|
6689
|
+
});
|
|
6446
6690
|
});
|
|
6447
6691
|
}, [editor, onCountChange]);
|
|
6448
6692
|
return null;
|
|
@@ -6592,6 +6836,9 @@ var ContentEditorComponent = forwardRef(
|
|
|
6592
6836
|
const [isLinkEditMode, setIsLinkEditMode] = useState(false);
|
|
6593
6837
|
const [wordCount, setWordCount] = useState(0);
|
|
6594
6838
|
const handleWordCount = useCallback((count) => setWordCount(count), []);
|
|
6839
|
+
const [charCount, setCharCount] = useState(0);
|
|
6840
|
+
const handleCharCount = useCallback((count) => setCharCount(count), []);
|
|
6841
|
+
const [refErrors, setRefErrors] = useState([]);
|
|
6595
6842
|
const contentEditableDomRef = useRef(null);
|
|
6596
6843
|
const previousOverLimitRef = useRef(false);
|
|
6597
6844
|
const focusedRef = useRef(false);
|
|
@@ -6671,7 +6918,41 @@ var ContentEditorComponent = forwardRef(
|
|
|
6671
6918
|
e.stopPropagation();
|
|
6672
6919
|
}
|
|
6673
6920
|
};
|
|
6921
|
+
const [touched, setTouched] = useState(false);
|
|
6674
6922
|
const isOverLimit = props.wordLimit !== void 0 && wordCount > props.wordLimit;
|
|
6923
|
+
const internalErrors = [];
|
|
6924
|
+
if (isOverLimit) {
|
|
6925
|
+
const m = props.errorMessages?.wordLimitExceeded;
|
|
6926
|
+
internalErrors.push(
|
|
6927
|
+
typeof m === "function" ? m(wordCount, props.wordLimit) : m ?? `Word limit exceeded (${wordCount} / ${props.wordLimit} words used)`
|
|
6928
|
+
);
|
|
6929
|
+
}
|
|
6930
|
+
if (props.required && touched && wordCount === 0) {
|
|
6931
|
+
internalErrors.push(
|
|
6932
|
+
props.errorMessages?.required ?? "This field is required"
|
|
6933
|
+
);
|
|
6934
|
+
}
|
|
6935
|
+
if (props.minWords !== void 0 && touched && wordCount < props.minWords) {
|
|
6936
|
+
const m = props.errorMessages?.minWords;
|
|
6937
|
+
internalErrors.push(
|
|
6938
|
+
typeof m === "function" ? m(wordCount, props.minWords) : m ?? `Minimum ${props.minWords} words required (${wordCount} entered)`
|
|
6939
|
+
);
|
|
6940
|
+
}
|
|
6941
|
+
if (props.maxChars !== void 0 && charCount > props.maxChars) {
|
|
6942
|
+
const m = props.errorMessages?.maxCharsExceeded;
|
|
6943
|
+
internalErrors.push(
|
|
6944
|
+
typeof m === "function" ? m(charCount, props.maxChars) : m ?? `Character limit exceeded (${charCount} / ${props.maxChars} characters used)`
|
|
6945
|
+
);
|
|
6946
|
+
}
|
|
6947
|
+
if (props.minChars !== void 0 && touched && charCount < props.minChars && charCount > 0) {
|
|
6948
|
+
const m = props.errorMessages?.minCharsRequired;
|
|
6949
|
+
internalErrors.push(
|
|
6950
|
+
typeof m === "function" ? m(charCount, props.minChars) : m ?? `Minimum ${props.minChars} characters required (${charCount} entered)`
|
|
6951
|
+
);
|
|
6952
|
+
}
|
|
6953
|
+
const allErrors = [...internalErrors, ...props.errors ?? [], ...refErrors];
|
|
6954
|
+
const hasErrors = allErrors.length > 0;
|
|
6955
|
+
const hasRedBorder = hasErrors;
|
|
6675
6956
|
useEffect(() => {
|
|
6676
6957
|
if (props.wordLimit === void 0 || !props.onWordLimitExceeded) return;
|
|
6677
6958
|
const wasOverLimit = previousOverLimitRef.current;
|
|
@@ -6694,7 +6975,7 @@ var ContentEditorComponent = forwardRef(
|
|
|
6694
6975
|
width: props.width ?? "100%",
|
|
6695
6976
|
height: props.height ?? "100%",
|
|
6696
6977
|
margin: props.margin ?? "5px auto",
|
|
6697
|
-
border: `1px solid ${
|
|
6978
|
+
border: `1px solid ${hasRedBorder ? "#c4272c" : "var(--colorNeutralStroke1, #ccced1)"}`,
|
|
6698
6979
|
transition: "border-color 0.2s",
|
|
6699
6980
|
display: "flex",
|
|
6700
6981
|
flexDirection: "column"
|
|
@@ -6724,7 +7005,9 @@ var ContentEditorComponent = forwardRef(
|
|
|
6724
7005
|
position: "relative",
|
|
6725
7006
|
flexGrow: 1,
|
|
6726
7007
|
padding: "15px 0px",
|
|
6727
|
-
overflowY: "scroll"
|
|
7008
|
+
overflowY: "scroll",
|
|
7009
|
+
overflowX: "auto",
|
|
7010
|
+
minWidth: 0
|
|
6728
7011
|
},
|
|
6729
7012
|
onClickCapture: handleReadOnlyClickCapture,
|
|
6730
7013
|
children: [
|
|
@@ -6788,13 +7071,33 @@ var ContentEditorComponent = forwardRef(
|
|
|
6788
7071
|
]
|
|
6789
7072
|
}
|
|
6790
7073
|
),
|
|
7074
|
+
hasErrors && /* @__PURE__ */ jsx(
|
|
7075
|
+
"div",
|
|
7076
|
+
{
|
|
7077
|
+
style: {
|
|
7078
|
+
borderTop: "1px solid #fbd5d5",
|
|
7079
|
+
background: "#fff8f8",
|
|
7080
|
+
padding: "6px 12px 8px",
|
|
7081
|
+
display: "flex",
|
|
7082
|
+
flexDirection: "column",
|
|
7083
|
+
gap: 4
|
|
7084
|
+
},
|
|
7085
|
+
children: allErrors.map((err, i) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
7086
|
+
/* @__PURE__ */ jsx(ErrorCircleRegular, { style: { fontSize: 14, color: "#c4272c", flexShrink: 0 } }),
|
|
7087
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#c4272c" }, children: err })
|
|
7088
|
+
] }, i))
|
|
7089
|
+
}
|
|
7090
|
+
),
|
|
6791
7091
|
/* @__PURE__ */ jsx(ReadOnlyPlugin, { readonly: isReadOnly }),
|
|
6792
7092
|
/* @__PURE__ */ jsx(BrowserSpellCheckPlugin, { enabled: !resolvedSpellCheck }),
|
|
6793
7093
|
/* @__PURE__ */ jsx(
|
|
6794
7094
|
FocusEventsPlugin,
|
|
6795
7095
|
{
|
|
6796
7096
|
onFocus: props.onFocus,
|
|
6797
|
-
onBlur:
|
|
7097
|
+
onBlur: () => {
|
|
7098
|
+
setTouched(true);
|
|
7099
|
+
props.onBlur?.();
|
|
7100
|
+
},
|
|
6798
7101
|
setFocused,
|
|
6799
7102
|
containerRef
|
|
6800
7103
|
}
|
|
@@ -6841,20 +7144,16 @@ var ContentEditorComponent = forwardRef(
|
|
|
6841
7144
|
}
|
|
6842
7145
|
),
|
|
6843
7146
|
!isReadOnly && props.showFloatingToolbar && /* @__PURE__ */ jsx(CharacterStylesPopupPlugin, {}),
|
|
6844
|
-
/* @__PURE__ */ jsx(
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
value: props.value,
|
|
6848
|
-
onChange: props.onChange
|
|
6849
|
-
}
|
|
6850
|
-
),
|
|
6851
|
-
props.wordLimit !== void 0 && /* @__PURE__ */ jsx(WordCountPlugin, { onCountChange: handleWordCount }),
|
|
7147
|
+
/* @__PURE__ */ jsx(CustomOnChangePlugin, { value: props.value, onChange: props.onChange }),
|
|
7148
|
+
(props.wordLimit !== void 0 || props.required || props.minWords !== void 0) && /* @__PURE__ */ jsx(WordCountPlugin, { onCountChange: handleWordCount }),
|
|
7149
|
+
(props.maxChars !== void 0 || props.minChars !== void 0) && /* @__PURE__ */ jsx(CharCountPlugin, { onCountChange: handleCharCount }),
|
|
6852
7150
|
/* @__PURE__ */ jsx(
|
|
6853
7151
|
RefApiPlugin,
|
|
6854
7152
|
{
|
|
6855
7153
|
forwardedRef: ref,
|
|
6856
7154
|
contentEditableDomRef,
|
|
6857
|
-
focusedRef
|
|
7155
|
+
focusedRef,
|
|
7156
|
+
setRefErrors
|
|
6858
7157
|
}
|
|
6859
7158
|
)
|
|
6860
7159
|
]
|