@mieweb/ui 0.11.0-dev.23 → 0.11.0-dev.25
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/{chunk-7BA7ENN5.cjs → chunk-3S5LK2EW.cjs} +346 -20
- package/dist/chunk-3S5LK2EW.cjs.map +1 -0
- package/dist/{chunk-ESXTC5GW.cjs → chunk-CY7ZRKLW.cjs} +4 -4
- package/dist/{chunk-ESXTC5GW.cjs.map → chunk-CY7ZRKLW.cjs.map} +1 -1
- package/dist/{chunk-67REGSKI.js → chunk-JTLOCREL.js} +3 -3
- package/dist/{chunk-67REGSKI.js.map → chunk-JTLOCREL.js.map} +1 -1
- package/dist/{chunk-4W3QJWG2.cjs → chunk-OCRUE3HI.cjs} +26 -3
- package/dist/chunk-OCRUE3HI.cjs.map +1 -0
- package/dist/{chunk-5EOW6AP3.js → chunk-UTSRPQ5B.js} +347 -21
- package/dist/chunk-UTSRPQ5B.js.map +1 -0
- package/dist/{chunk-V43ZWRBT.js → chunk-UY3PIO7F.js} +26 -3
- package/dist/chunk-UY3PIO7F.js.map +1 -0
- package/dist/components/EmailEditor/index.cjs +11 -11
- package/dist/components/EmailEditor/index.js +2 -2
- package/dist/components/RichTextEditor/index.cjs +4 -4
- package/dist/components/RichTextEditor/index.d.cts +61 -1
- package/dist/components/RichTextEditor/index.d.ts +61 -1
- package/dist/components/RichTextEditor/index.js +1 -1
- package/dist/index.cjs +18 -18
- package/dist/index.d.cts +61 -1
- package/dist/index.d.ts +61 -1
- package/dist/index.js +3 -3
- package/dist/styles.css +1 -1
- package/dist/tailwind-preset.cjs +4 -4
- package/dist/tailwind-preset.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4W3QJWG2.cjs.map +0 -1
- package/dist/chunk-5EOW6AP3.js.map +0 -1
- package/dist/chunk-7BA7ENN5.cjs.map +0 -1
- package/dist/chunk-V43ZWRBT.js.map +0 -1
|
@@ -6,7 +6,7 @@ import { X, Search, History, BookOpen, ChevronRight, ChevronDown, Plus } from '.
|
|
|
6
6
|
import { Button } from './chunk-WFBUBT54.js';
|
|
7
7
|
import { cn } from './chunk-TQONQSJO.js';
|
|
8
8
|
import * as React2 from 'react';
|
|
9
|
-
import { Bold, Italic, Underline, List, ListOrdered, AlignLeft, AlignCenter, AlignRight, Braces, Replace, MicOff, Mic, BookOpen as BookOpen$1 } from 'lucide-react';
|
|
9
|
+
import { Bold, Italic, Underline, List, ListOrdered, AlignLeft, AlignCenter, AlignRight, Braces, Replace, MicOff, Mic, BookOpen as BookOpen$1, Plus as Plus$1 } from 'lucide-react';
|
|
10
10
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
11
11
|
|
|
12
12
|
var DEFAULT_LABELS = {
|
|
@@ -511,6 +511,26 @@ function getSpeechRecognition() {
|
|
|
511
511
|
return w.SpeechRecognition || w.webkitSpeechRecognition;
|
|
512
512
|
}
|
|
513
513
|
var BLOCK_BOUNDARY = /^(BR|DIV|P|LI|UL|OL|TABLE|TR|TD|TH|H[1-6]|BLOCKQUOTE|PRE|HR)$/;
|
|
514
|
+
var MARKDOWN_BLOCK_RULES = {
|
|
515
|
+
"#": { command: "formatBlock", value: "h1" },
|
|
516
|
+
"##": { command: "formatBlock", value: "h2" },
|
|
517
|
+
"###": { command: "formatBlock", value: "h3" },
|
|
518
|
+
"-": { command: "insertUnorderedList" },
|
|
519
|
+
"*": { command: "insertUnorderedList" },
|
|
520
|
+
"1.": { command: "insertOrderedList" },
|
|
521
|
+
">": { command: "formatBlock", value: "blockquote" }
|
|
522
|
+
};
|
|
523
|
+
function nodeRect(node) {
|
|
524
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
525
|
+
return node.getBoundingClientRect();
|
|
526
|
+
}
|
|
527
|
+
if (node.nodeType === Node.TEXT_NODE && (node.textContent ?? "").length > 0) {
|
|
528
|
+
const range = document.createRange();
|
|
529
|
+
range.selectNodeContents(node);
|
|
530
|
+
return range.getBoundingClientRect();
|
|
531
|
+
}
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
514
534
|
function lastTextWithin(node) {
|
|
515
535
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
516
536
|
return (node.textContent ?? "").length > 0 ? node : null;
|
|
@@ -557,6 +577,12 @@ var RichTextEditor = React2.forwardRef(
|
|
|
557
577
|
defaultMacrosOpen = false,
|
|
558
578
|
macroLabels,
|
|
559
579
|
onCreateMacro,
|
|
580
|
+
toolbar,
|
|
581
|
+
defaultToolbar = "visible",
|
|
582
|
+
onToolbarChange,
|
|
583
|
+
blockMenu = false,
|
|
584
|
+
blockMenuLabels,
|
|
585
|
+
markdownShortcuts = false,
|
|
560
586
|
"aria-label": ariaLabel
|
|
561
587
|
}, ref) => {
|
|
562
588
|
const editorRef = React2.useRef(null);
|
|
@@ -571,6 +597,19 @@ var RichTextEditor = React2.forwardRef(
|
|
|
571
597
|
const hasVariables = Boolean(variableGroups && variableGroups.length > 0);
|
|
572
598
|
const hasMacros = Boolean(macros);
|
|
573
599
|
const isEmpty = isHtmlEmpty(value);
|
|
600
|
+
const [uncontrolledToolbar, setUncontrolledToolbar] = React2.useState(defaultToolbar);
|
|
601
|
+
const toolbarVisible = (toolbar ?? uncontrolledToolbar) !== "hidden";
|
|
602
|
+
const setToolbarVisibility = (next) => {
|
|
603
|
+
if (toolbar === void 0) setUncontrolledToolbar(next);
|
|
604
|
+
onToolbarChange?.(next);
|
|
605
|
+
};
|
|
606
|
+
const toolbarVisibleRef = React2.useRef(toolbarVisible);
|
|
607
|
+
const [blockMenuOpen, setBlockMenuOpen] = React2.useState(false);
|
|
608
|
+
const [gutterTop, setGutterTop] = React2.useState(16);
|
|
609
|
+
const gutterWrapperRef = React2.useRef(null);
|
|
610
|
+
const hoverBlockNodeRef = React2.useRef(null);
|
|
611
|
+
const blockTargetRangeRef = React2.useRef(null);
|
|
612
|
+
const firstBlockItemRef = React2.useRef(null);
|
|
574
613
|
React2.useImperativeHandle(ref, () => editorRef.current);
|
|
575
614
|
React2.useEffect(() => {
|
|
576
615
|
setSpeechSupported(Boolean(getSpeechRecognition()));
|
|
@@ -584,6 +623,16 @@ var RichTextEditor = React2.forwardRef(
|
|
|
584
623
|
}
|
|
585
624
|
};
|
|
586
625
|
}, []);
|
|
626
|
+
React2.useEffect(() => {
|
|
627
|
+
toolbarVisibleRef.current = toolbarVisible;
|
|
628
|
+
if (toolbarVisible) return;
|
|
629
|
+
if (recognitionRef.current && isListeningRef.current) {
|
|
630
|
+
shouldRestartRef.current = false;
|
|
631
|
+
isListeningRef.current = false;
|
|
632
|
+
recognitionRef.current.stop();
|
|
633
|
+
setIsListening(false);
|
|
634
|
+
}
|
|
635
|
+
}, [toolbarVisible]);
|
|
587
636
|
React2.useEffect(() => {
|
|
588
637
|
if (editorRef.current && editorRef.current.innerHTML !== value) {
|
|
589
638
|
editorRef.current.innerHTML = value;
|
|
@@ -722,22 +771,18 @@ var RichTextEditor = React2.forwardRef(
|
|
|
722
771
|
saveSelection();
|
|
723
772
|
updateContent();
|
|
724
773
|
};
|
|
725
|
-
const
|
|
726
|
-
if (disabled || event.key !== " " || // Space during IME composition selects/converts a candidate; never
|
|
727
|
-
// hijack it for macro expansion.
|
|
728
|
-
event.nativeEvent.isComposing || event.ctrlKey || event.metaKey || event.altKey || !macros)
|
|
729
|
-
return;
|
|
774
|
+
const collectTokenBeforeCaret = () => {
|
|
730
775
|
const selection = window.getSelection();
|
|
731
776
|
if (!selection || selection.rangeCount === 0 || !selection.isCollapsed)
|
|
732
|
-
return;
|
|
777
|
+
return null;
|
|
733
778
|
const caret = selection.getRangeAt(0);
|
|
734
779
|
const node = caret.startContainer;
|
|
735
780
|
if (node.nodeType !== Node.TEXT_NODE || !editorRef.current?.contains(node))
|
|
736
|
-
return;
|
|
781
|
+
return null;
|
|
737
782
|
const typed = /(\S+)$/.exec(
|
|
738
783
|
(node.textContent ?? "").slice(0, caret.startOffset)
|
|
739
784
|
);
|
|
740
|
-
if (!typed) return;
|
|
785
|
+
if (!typed) return null;
|
|
741
786
|
let token = typed[1];
|
|
742
787
|
let startNode = node;
|
|
743
788
|
let startOffset = caret.startOffset - typed[1].length;
|
|
@@ -751,17 +796,164 @@ var RichTextEditor = React2.forwardRef(
|
|
|
751
796
|
startNode = prev;
|
|
752
797
|
startOffset = text.length - continued[1].length;
|
|
753
798
|
}
|
|
754
|
-
const
|
|
799
|
+
const atLineStart = startOffset === 0 && !previousVisibleText(startNode, editorRef.current);
|
|
800
|
+
return {
|
|
801
|
+
token,
|
|
802
|
+
startNode,
|
|
803
|
+
startOffset,
|
|
804
|
+
caretNode: node,
|
|
805
|
+
caretOffset: caret.startOffset,
|
|
806
|
+
atLineStart,
|
|
807
|
+
selection
|
|
808
|
+
};
|
|
809
|
+
};
|
|
810
|
+
const selectCollectedToken = (collected) => {
|
|
811
|
+
const replaceRange = document.createRange();
|
|
812
|
+
replaceRange.setStart(collected.startNode, collected.startOffset);
|
|
813
|
+
replaceRange.setEnd(collected.caretNode, collected.caretOffset);
|
|
814
|
+
collected.selection.removeAllRanges();
|
|
815
|
+
collected.selection.addRange(replaceRange);
|
|
816
|
+
return replaceRange;
|
|
817
|
+
};
|
|
818
|
+
const expandTypedShortcut = (event) => {
|
|
819
|
+
if (!macros) return;
|
|
820
|
+
const collected = collectTokenBeforeCaret();
|
|
821
|
+
if (!collected) return;
|
|
822
|
+
const lowered = collected.token.toLowerCase();
|
|
755
823
|
const macro = macros.flatMap((group) => group.macros).find((candidate) => candidate.shortcut?.toLowerCase() === lowered);
|
|
756
824
|
if (!macro) return;
|
|
757
825
|
event.preventDefault();
|
|
758
|
-
|
|
759
|
-
replaceRange.setStart(startNode, startOffset);
|
|
760
|
-
replaceRange.setEnd(node, caret.startOffset);
|
|
761
|
-
selection.removeAllRanges();
|
|
762
|
-
selection.addRange(replaceRange);
|
|
826
|
+
selectCollectedToken(collected);
|
|
763
827
|
insertTextAtSelection(macro.content);
|
|
764
828
|
};
|
|
829
|
+
const applyMarkdownShortcut = (event) => {
|
|
830
|
+
const collected = collectTokenBeforeCaret();
|
|
831
|
+
if (!collected || !collected.atLineStart) return false;
|
|
832
|
+
if (!Object.hasOwn(MARKDOWN_BLOCK_RULES, collected.token)) return false;
|
|
833
|
+
const rule = MARKDOWN_BLOCK_RULES[collected.token];
|
|
834
|
+
event.preventDefault();
|
|
835
|
+
const replaceRange = selectCollectedToken(collected);
|
|
836
|
+
let deleted = false;
|
|
837
|
+
try {
|
|
838
|
+
deleted = document.execCommand("delete", false);
|
|
839
|
+
} catch {
|
|
840
|
+
deleted = false;
|
|
841
|
+
}
|
|
842
|
+
if (!deleted) {
|
|
843
|
+
replaceRange.deleteContents();
|
|
844
|
+
replaceRange.collapse(true);
|
|
845
|
+
collected.selection.removeAllRanges();
|
|
846
|
+
collected.selection.addRange(replaceRange);
|
|
847
|
+
}
|
|
848
|
+
try {
|
|
849
|
+
document.execCommand(rule.command, false, rule.value);
|
|
850
|
+
} catch {
|
|
851
|
+
}
|
|
852
|
+
editorRef.current?.focus();
|
|
853
|
+
saveSelection();
|
|
854
|
+
updateContent();
|
|
855
|
+
return true;
|
|
856
|
+
};
|
|
857
|
+
const handleEditorKeyDown = (event) => {
|
|
858
|
+
if (disabled) return;
|
|
859
|
+
if (blockMenu && event.key === "/" && (event.ctrlKey || event.metaKey) && !event.altKey) {
|
|
860
|
+
event.preventDefault();
|
|
861
|
+
openBlockMenuAtCaret();
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
if (event.key !== " " || // Space during IME composition selects/converts a candidate; never
|
|
865
|
+
// hijack it for shortcut expansion.
|
|
866
|
+
event.nativeEvent.isComposing || event.ctrlKey || event.metaKey || event.altKey)
|
|
867
|
+
return;
|
|
868
|
+
if (markdownShortcuts && applyMarkdownShortcut(event)) return;
|
|
869
|
+
expandTypedShortcut(event);
|
|
870
|
+
};
|
|
871
|
+
const handleGutterMouseMove = (event) => {
|
|
872
|
+
if (blockMenuOpen || !editorRef.current || !gutterWrapperRef.current)
|
|
873
|
+
return;
|
|
874
|
+
let target = null;
|
|
875
|
+
let top = null;
|
|
876
|
+
for (const child of Array.from(editorRef.current.childNodes)) {
|
|
877
|
+
const rect = nodeRect(child);
|
|
878
|
+
if (!rect) continue;
|
|
879
|
+
if (rect.width === 0 && rect.height === 0) continue;
|
|
880
|
+
if (target === null || rect.top <= event.clientY) {
|
|
881
|
+
target = child;
|
|
882
|
+
top = rect.top;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
if (!target || top === null) return;
|
|
886
|
+
hoverBlockNodeRef.current = target;
|
|
887
|
+
const wrapperTop = gutterWrapperRef.current.getBoundingClientRect().top;
|
|
888
|
+
const next = Math.max(Math.round(top - wrapperTop), 4);
|
|
889
|
+
setGutterTop((current) => current === next ? current : next);
|
|
890
|
+
};
|
|
891
|
+
const rangeAtStartOf = (node) => {
|
|
892
|
+
const range = document.createRange();
|
|
893
|
+
range.setStart(node, 0);
|
|
894
|
+
range.collapse(true);
|
|
895
|
+
return range;
|
|
896
|
+
};
|
|
897
|
+
const handleBlockMenuOpenChange = (open) => {
|
|
898
|
+
if (open) {
|
|
899
|
+
const block = hoverBlockNodeRef.current ?? editorRef.current?.firstChild ?? null;
|
|
900
|
+
blockTargetRangeRef.current = block ? rangeAtStartOf(block) : null;
|
|
901
|
+
} else if (editorRef.current && document.activeElement?.closest('[role="menu"]')) {
|
|
902
|
+
const editor = editorRef.current;
|
|
903
|
+
editor.focus();
|
|
904
|
+
const target = blockTargetRangeRef.current;
|
|
905
|
+
const selection = window.getSelection();
|
|
906
|
+
if (target && selection && editor.contains(target.startContainer)) {
|
|
907
|
+
selection.removeAllRanges();
|
|
908
|
+
selection.addRange(target);
|
|
909
|
+
saveSelection();
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
setBlockMenuOpen(open);
|
|
913
|
+
};
|
|
914
|
+
const openBlockMenuAtCaret = () => {
|
|
915
|
+
const selection = window.getSelection();
|
|
916
|
+
if (selection && selection.rangeCount > 0 && editorRef.current?.contains(selection.getRangeAt(0).startContainer)) {
|
|
917
|
+
const caret = selection.getRangeAt(0);
|
|
918
|
+
blockTargetRangeRef.current = caret.cloneRange();
|
|
919
|
+
let node = caret.startContainer;
|
|
920
|
+
while (node.parentNode && node.parentNode !== editorRef.current) {
|
|
921
|
+
node = node.parentNode;
|
|
922
|
+
}
|
|
923
|
+
const rect = nodeRect(node);
|
|
924
|
+
const wrapperRect = gutterWrapperRef.current?.getBoundingClientRect();
|
|
925
|
+
if (rect && wrapperRect) {
|
|
926
|
+
setGutterTop(Math.max(Math.round(rect.top - wrapperRect.top), 4));
|
|
927
|
+
}
|
|
928
|
+
} else {
|
|
929
|
+
blockTargetRangeRef.current = null;
|
|
930
|
+
}
|
|
931
|
+
setBlockMenuOpen(true);
|
|
932
|
+
};
|
|
933
|
+
const applyBlockFormat = (command, value2) => {
|
|
934
|
+
if (disabled || !editorRef.current) return;
|
|
935
|
+
setBlockMenuOpen(false);
|
|
936
|
+
editorRef.current.focus();
|
|
937
|
+
const target = blockTargetRangeRef.current;
|
|
938
|
+
const selection = window.getSelection();
|
|
939
|
+
if (target && selection && editorRef.current.contains(target.startContainer)) {
|
|
940
|
+
selection.removeAllRanges();
|
|
941
|
+
selection.addRange(target);
|
|
942
|
+
}
|
|
943
|
+
try {
|
|
944
|
+
document.execCommand(command, false, value2);
|
|
945
|
+
} catch {
|
|
946
|
+
}
|
|
947
|
+
saveSelection();
|
|
948
|
+
updateContent();
|
|
949
|
+
};
|
|
950
|
+
React2.useEffect(() => {
|
|
951
|
+
if (!blockMenuOpen) return;
|
|
952
|
+
const frame = requestAnimationFrame(
|
|
953
|
+
() => firstBlockItemRef.current?.focus()
|
|
954
|
+
);
|
|
955
|
+
return () => cancelAnimationFrame(frame);
|
|
956
|
+
}, [blockMenuOpen]);
|
|
765
957
|
const toggleDictation = async () => {
|
|
766
958
|
const SpeechRecognition = getSpeechRecognition();
|
|
767
959
|
if (!SpeechRecognition) return;
|
|
@@ -783,6 +975,7 @@ var RichTextEditor = React2.forwardRef(
|
|
|
783
975
|
);
|
|
784
976
|
return;
|
|
785
977
|
}
|
|
978
|
+
if (!toolbarVisibleRef.current) return;
|
|
786
979
|
const recognition = new SpeechRecognition();
|
|
787
980
|
recognition.continuous = true;
|
|
788
981
|
recognition.interimResults = true;
|
|
@@ -859,6 +1052,43 @@ var RichTextEditor = React2.forwardRef(
|
|
|
859
1052
|
}
|
|
860
1053
|
};
|
|
861
1054
|
const iconButtonClass = "h-8 w-8 p-0";
|
|
1055
|
+
const blockFormatItems = [
|
|
1056
|
+
{ key: "text", label: "Text", command: "formatBlock", value: "p" },
|
|
1057
|
+
{
|
|
1058
|
+
key: "heading1",
|
|
1059
|
+
label: "Heading 1",
|
|
1060
|
+
command: "formatBlock",
|
|
1061
|
+
value: "h1"
|
|
1062
|
+
},
|
|
1063
|
+
{
|
|
1064
|
+
key: "heading2",
|
|
1065
|
+
label: "Heading 2",
|
|
1066
|
+
command: "formatBlock",
|
|
1067
|
+
value: "h2"
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
key: "heading3",
|
|
1071
|
+
label: "Heading 3",
|
|
1072
|
+
command: "formatBlock",
|
|
1073
|
+
value: "h3"
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
key: "bulletList",
|
|
1077
|
+
label: "Bullet list",
|
|
1078
|
+
command: "insertUnorderedList"
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
key: "numberedList",
|
|
1082
|
+
label: "Numbered list",
|
|
1083
|
+
command: "insertOrderedList"
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
key: "quote",
|
|
1087
|
+
label: "Quote",
|
|
1088
|
+
command: "formatBlock",
|
|
1089
|
+
value: "blockquote"
|
|
1090
|
+
}
|
|
1091
|
+
];
|
|
862
1092
|
return /* @__PURE__ */ jsxs(
|
|
863
1093
|
"div",
|
|
864
1094
|
{
|
|
@@ -868,7 +1098,7 @@ var RichTextEditor = React2.forwardRef(
|
|
|
868
1098
|
className
|
|
869
1099
|
),
|
|
870
1100
|
children: [
|
|
871
|
-
/* @__PURE__ */ jsxs(
|
|
1101
|
+
toolbarVisible && /* @__PURE__ */ jsxs(
|
|
872
1102
|
"div",
|
|
873
1103
|
{
|
|
874
1104
|
"data-slot": "rich-text-editor-toolbar",
|
|
@@ -1056,7 +1286,10 @@ var RichTextEditor = React2.forwardRef(
|
|
|
1056
1286
|
size: "sm",
|
|
1057
1287
|
onClick: toggleDictation,
|
|
1058
1288
|
disabled: disabled || !speechSupported,
|
|
1059
|
-
className: cn(
|
|
1289
|
+
className: cn(
|
|
1290
|
+
"h-8 gap-1 px-2",
|
|
1291
|
+
isListening && "animate-pulse"
|
|
1292
|
+
),
|
|
1060
1293
|
title: !speechSupported ? "Speech recognition not supported in this browser" : isListening ? "Stop dictation" : "Start dictation",
|
|
1061
1294
|
children: [
|
|
1062
1295
|
isListening ? /* @__PURE__ */ jsx(MicOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" }),
|
|
@@ -1093,16 +1326,98 @@ var RichTextEditor = React2.forwardRef(
|
|
|
1093
1326
|
/* @__PURE__ */ jsxs(
|
|
1094
1327
|
"div",
|
|
1095
1328
|
{
|
|
1329
|
+
ref: gutterWrapperRef,
|
|
1096
1330
|
className: cn(
|
|
1097
1331
|
"relative flex-1",
|
|
1332
|
+
blockMenu && "group/rte-body",
|
|
1098
1333
|
hasMacros && macrosOpen && "md:me-72"
|
|
1099
1334
|
),
|
|
1335
|
+
onMouseMove: blockMenu && !disabled ? handleGutterMouseMove : void 0,
|
|
1100
1336
|
children: [
|
|
1337
|
+
blockMenu && !disabled && /* @__PURE__ */ jsx(
|
|
1338
|
+
"div",
|
|
1339
|
+
{
|
|
1340
|
+
"data-slot": "rich-text-editor-block-gutter",
|
|
1341
|
+
className: "absolute start-1 z-10",
|
|
1342
|
+
style: { top: gutterTop },
|
|
1343
|
+
children: /* @__PURE__ */ jsxs(
|
|
1344
|
+
Dropdown,
|
|
1345
|
+
{
|
|
1346
|
+
open: blockMenuOpen,
|
|
1347
|
+
onOpenChange: handleBlockMenuOpenChange,
|
|
1348
|
+
placement: "bottom-start",
|
|
1349
|
+
trigger: /* @__PURE__ */ jsx(
|
|
1350
|
+
Button,
|
|
1351
|
+
{
|
|
1352
|
+
type: "button",
|
|
1353
|
+
variant: "ghost",
|
|
1354
|
+
size: "sm",
|
|
1355
|
+
className: cn(
|
|
1356
|
+
"h-6 w-6 p-0",
|
|
1357
|
+
// Revealed on hover/focus; always visible on touch,
|
|
1358
|
+
// which has no hover to reveal it with.
|
|
1359
|
+
"opacity-0 transition-opacity",
|
|
1360
|
+
"group-hover/rte-body:opacity-100",
|
|
1361
|
+
"focus-visible:opacity-100",
|
|
1362
|
+
"[@media(hover:none)]:opacity-100",
|
|
1363
|
+
blockMenuOpen && "opacity-100"
|
|
1364
|
+
),
|
|
1365
|
+
"aria-label": blockMenuLabels?.blockMenu ?? "Block menu",
|
|
1366
|
+
title: blockMenuLabels?.blockMenu ?? "Block menu",
|
|
1367
|
+
children: /* @__PURE__ */ jsx(Plus$1, { className: "h-4 w-4" })
|
|
1368
|
+
}
|
|
1369
|
+
),
|
|
1370
|
+
children: [
|
|
1371
|
+
blockFormatItems.map((item, index) => /* @__PURE__ */ jsx(
|
|
1372
|
+
DropdownItem,
|
|
1373
|
+
{
|
|
1374
|
+
ref: index === 0 ? firstBlockItemRef : void 0,
|
|
1375
|
+
onClick: () => applyBlockFormat(item.command, item.value),
|
|
1376
|
+
children: blockMenuLabels?.[item.key] ?? item.label
|
|
1377
|
+
},
|
|
1378
|
+
item.key
|
|
1379
|
+
)),
|
|
1380
|
+
/* @__PURE__ */ jsx(DropdownSeparator, {}),
|
|
1381
|
+
hasMacros && /* @__PURE__ */ jsx(
|
|
1382
|
+
DropdownItem,
|
|
1383
|
+
{
|
|
1384
|
+
onClick: () => {
|
|
1385
|
+
setBlockMenuOpen(false);
|
|
1386
|
+
if (blockTargetRangeRef.current) {
|
|
1387
|
+
savedRangeRef.current = blockTargetRangeRef.current;
|
|
1388
|
+
}
|
|
1389
|
+
setMacrosOpen(true);
|
|
1390
|
+
focusRestoringSelection();
|
|
1391
|
+
},
|
|
1392
|
+
children: blockMenuLabels?.insertMacro ?? "Insert macro\u2026"
|
|
1393
|
+
}
|
|
1394
|
+
),
|
|
1395
|
+
/* @__PURE__ */ jsx(
|
|
1396
|
+
DropdownItem,
|
|
1397
|
+
{
|
|
1398
|
+
onClick: () => {
|
|
1399
|
+
setBlockMenuOpen(false);
|
|
1400
|
+
setToolbarVisibility(
|
|
1401
|
+
toolbarVisible ? "hidden" : "visible"
|
|
1402
|
+
);
|
|
1403
|
+
editorRef.current?.focus();
|
|
1404
|
+
},
|
|
1405
|
+
children: toolbarVisible ? blockMenuLabels?.hideToolbar ?? "Hide toolbar" : blockMenuLabels?.showToolbar ?? "Show toolbar"
|
|
1406
|
+
}
|
|
1407
|
+
)
|
|
1408
|
+
]
|
|
1409
|
+
}
|
|
1410
|
+
)
|
|
1411
|
+
}
|
|
1412
|
+
),
|
|
1101
1413
|
isEmpty && placeholder && /* @__PURE__ */ jsx(
|
|
1102
1414
|
"div",
|
|
1103
1415
|
{
|
|
1104
1416
|
"aria-hidden": "true",
|
|
1105
|
-
className:
|
|
1417
|
+
className: cn(
|
|
1418
|
+
"text-muted-foreground pointer-events-none absolute start-0 top-0 p-4",
|
|
1419
|
+
blockMenu && "ps-10"
|
|
1420
|
+
),
|
|
1106
1421
|
children: placeholder
|
|
1107
1422
|
}
|
|
1108
1423
|
),
|
|
@@ -1119,12 +1434,23 @@ var RichTextEditor = React2.forwardRef(
|
|
|
1119
1434
|
onPaste: handlePaste,
|
|
1120
1435
|
onDrop: handleDrop,
|
|
1121
1436
|
onBlur: hasMacros ? saveSelection : void 0,
|
|
1122
|
-
onKeyDown: hasMacros ?
|
|
1437
|
+
onKeyDown: hasMacros || markdownShortcuts || blockMenu ? handleEditorKeyDown : void 0,
|
|
1123
1438
|
onKeyUp: hasMacros ? saveSelection : void 0,
|
|
1124
1439
|
onMouseUp: hasMacros ? saveSelection : void 0,
|
|
1125
1440
|
className: cn(
|
|
1126
1441
|
"min-h-[250px] overflow-y-auto p-4 focus:outline-none",
|
|
1127
1442
|
"prose prose-sm max-w-none",
|
|
1443
|
+
// Baseline block styles: Tailwind preflight strips heading,
|
|
1444
|
+
// list and quote styling, and the `prose` classes above only
|
|
1445
|
+
// work when the host installs @tailwindcss/typography —
|
|
1446
|
+
// without these, block formats would apply invisibly.
|
|
1447
|
+
"[&_h1]:my-3 [&_h1]:text-2xl [&_h1]:font-bold",
|
|
1448
|
+
"[&_h2]:my-3 [&_h2]:text-xl [&_h2]:font-bold",
|
|
1449
|
+
"[&_h3]:my-2 [&_h3]:text-lg [&_h3]:font-semibold",
|
|
1450
|
+
"[&_ul]:my-2 [&_ul]:list-disc [&_ul]:ps-6",
|
|
1451
|
+
"[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:ps-6",
|
|
1452
|
+
"[&_blockquote]:border-border [&_blockquote]:text-muted-foreground [&_blockquote]:my-2 [&_blockquote]:border-s-4 [&_blockquote]:ps-3",
|
|
1453
|
+
blockMenu && "ps-10",
|
|
1128
1454
|
hasMacros && macrosOpen && "md:min-h-[400px]",
|
|
1129
1455
|
disabled && "bg-muted/20 cursor-not-allowed text-neutral-700 dark:text-neutral-300"
|
|
1130
1456
|
),
|
|
@@ -1159,5 +1485,5 @@ var RichTextEditor = React2.forwardRef(
|
|
|
1159
1485
|
RichTextEditor.displayName = "RichTextEditor";
|
|
1160
1486
|
|
|
1161
1487
|
export { MacroLibrary, RichTextEditor, convertAngleBracketsToMustache, processDictation };
|
|
1162
|
-
//# sourceMappingURL=chunk-
|
|
1163
|
-
//# sourceMappingURL=chunk-
|
|
1488
|
+
//# sourceMappingURL=chunk-UTSRPQ5B.js.map
|
|
1489
|
+
//# sourceMappingURL=chunk-UTSRPQ5B.js.map
|