@mieweb/ui 0.6.1-dev.126 → 0.6.1-dev.131
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/brands/index.cjs +12 -12
- package/dist/brands/index.js +3 -3
- package/dist/{chunk-MPOWJVV4.js → chunk-3OHVUXDG.js} +3 -3
- package/dist/{chunk-MPOWJVV4.js.map → chunk-3OHVUXDG.js.map} +1 -1
- package/dist/chunk-44CK4CT2.cjs +336 -0
- package/dist/chunk-44CK4CT2.cjs.map +1 -0
- package/dist/chunk-4LVPQ44A.js +228 -0
- package/dist/chunk-4LVPQ44A.js.map +1 -0
- package/dist/chunk-7XUN3OQT.js +3 -0
- package/dist/{chunk-V2DF2GUE.js.map → chunk-7XUN3OQT.js.map} +1 -1
- package/dist/chunk-AEGYWRSL.js +513 -0
- package/dist/chunk-AEGYWRSL.js.map +1 -0
- package/dist/chunk-AFKKJEV5.cjs +72 -0
- package/dist/chunk-AFKKJEV5.cjs.map +1 -0
- package/dist/chunk-AT732HC6.cjs +4 -0
- package/dist/{chunk-74K3RRU7.cjs.map → chunk-AT732HC6.cjs.map} +1 -1
- package/dist/chunk-BIT27PPD.js +49 -0
- package/dist/chunk-BIT27PPD.js.map +1 -0
- package/dist/chunk-BT3ZQJGT.cjs +130 -0
- package/dist/chunk-BT3ZQJGT.cjs.map +1 -0
- package/dist/chunk-BX6BTDTR.js +34 -0
- package/dist/chunk-BX6BTDTR.js.map +1 -0
- package/dist/chunk-C2544GKZ.js +313 -0
- package/dist/chunk-C2544GKZ.js.map +1 -0
- package/dist/chunk-C7RVKV25.cjs +25 -0
- package/dist/chunk-C7RVKV25.cjs.map +1 -0
- package/dist/{chunk-CV4CVGLO.cjs → chunk-DFT7TYKL.cjs} +3 -3
- package/dist/{chunk-CV4CVGLO.cjs.map → chunk-DFT7TYKL.cjs.map} +1 -1
- package/dist/chunk-DLNJLCNO.cjs +101 -0
- package/dist/chunk-DLNJLCNO.cjs.map +1 -0
- package/dist/chunk-DUPR6FEL.js +43 -0
- package/dist/chunk-DUPR6FEL.js.map +1 -0
- package/dist/chunk-EJUPJGKA.js +78 -0
- package/dist/chunk-EJUPJGKA.js.map +1 -0
- package/dist/chunk-ERLPVXOV.js +22 -0
- package/dist/chunk-ERLPVXOV.js.map +1 -0
- package/dist/chunk-KJ5BSGEO.cjs +258 -0
- package/dist/chunk-KJ5BSGEO.cjs.map +1 -0
- package/dist/chunk-MARLXJQO.cjs +537 -0
- package/dist/chunk-MARLXJQO.cjs.map +1 -0
- package/dist/{chunk-WFS6R2F5.js → chunk-OVQKCUTZ.js} +3 -3
- package/dist/{chunk-WFS6R2F5.js.map → chunk-OVQKCUTZ.js.map} +1 -1
- package/dist/chunk-OXYFTCRW.cjs +57 -0
- package/dist/chunk-OXYFTCRW.cjs.map +1 -0
- package/dist/chunk-PI3KOYAT.js +192 -0
- package/dist/chunk-PI3KOYAT.js.map +1 -0
- package/dist/chunk-QKAPKIXI.cjs +80 -0
- package/dist/chunk-QKAPKIXI.cjs.map +1 -0
- package/dist/{chunk-MV337VA7.js → chunk-R6PBBPU3.js} +2 -2
- package/dist/{chunk-MV337VA7.js.map → chunk-R6PBBPU3.js.map} +1 -1
- package/dist/chunk-ROXYP3BZ.cjs +214 -0
- package/dist/chunk-ROXYP3BZ.cjs.map +1 -0
- package/dist/chunk-T3C4RNJ4.js +106 -0
- package/dist/chunk-T3C4RNJ4.js.map +1 -0
- package/dist/{chunk-7BARESXI.cjs → chunk-ULF4PWHW.cjs} +3 -3
- package/dist/{chunk-7BARESXI.cjs.map → chunk-ULF4PWHW.cjs.map} +1 -1
- package/dist/chunk-UOOH356R.cjs +66 -0
- package/dist/chunk-UOOH356R.cjs.map +1 -0
- package/dist/chunk-Y2S6QMKU.js +78 -0
- package/dist/chunk-Y2S6QMKU.js.map +1 -0
- package/dist/{chunk-JLQTPLSY.cjs → chunk-Z6NRP4Z5.cjs} +2 -2
- package/dist/{chunk-JLQTPLSY.cjs.map → chunk-Z6NRP4Z5.cjs.map} +1 -1
- package/dist/components/AlertDialog/index.cjs +18 -0
- package/dist/components/AlertDialog/index.cjs.map +1 -0
- package/dist/components/AlertDialog/index.d.cts +56 -0
- package/dist/components/AlertDialog/index.d.ts +56 -0
- package/dist/components/AlertDialog/index.js +9 -0
- package/dist/components/AlertDialog/index.js.map +1 -0
- package/dist/components/Autocomplete/index.cjs +15 -0
- package/dist/components/Autocomplete/index.cjs.map +1 -0
- package/dist/components/Autocomplete/index.d.cts +77 -0
- package/dist/components/Autocomplete/index.d.ts +77 -0
- package/dist/components/Autocomplete/index.js +6 -0
- package/dist/components/Autocomplete/index.js.map +1 -0
- package/dist/components/Collapsible/index.cjs +21 -0
- package/dist/components/Collapsible/index.cjs.map +1 -0
- package/dist/components/Collapsible/index.d.cts +33 -0
- package/dist/components/Collapsible/index.d.ts +33 -0
- package/dist/components/Collapsible/index.js +4 -0
- package/dist/components/Collapsible/index.js.map +1 -0
- package/dist/components/CountryCodeDropdown/index.cjs +5 -5
- package/dist/components/CountryCodeDropdown/index.js +2 -2
- package/dist/components/Dropdown/index.cjs +8 -8
- package/dist/components/Dropdown/index.js +2 -2
- package/dist/components/FloatingWindow/index.cjs +18 -0
- package/dist/components/FloatingWindow/index.cjs.map +1 -0
- package/dist/components/FloatingWindow/index.d.cts +64 -0
- package/dist/components/FloatingWindow/index.d.ts +64 -0
- package/dist/components/FloatingWindow/index.js +5 -0
- package/dist/components/FloatingWindow/index.js.map +1 -0
- package/dist/components/Label/index.cjs +17 -0
- package/dist/components/Label/index.cjs.map +1 -0
- package/dist/components/Label/index.d.cts +23 -0
- package/dist/components/Label/index.d.ts +23 -0
- package/dist/components/Label/index.js +4 -0
- package/dist/components/Label/index.js.map +1 -0
- package/dist/components/RichTextEditor/index.cjs +32 -0
- package/dist/components/RichTextEditor/index.cjs.map +1 -0
- package/dist/components/RichTextEditor/index.d.cts +62 -0
- package/dist/components/RichTextEditor/index.d.ts +62 -0
- package/dist/components/RichTextEditor/index.js +11 -0
- package/dist/components/RichTextEditor/index.js.map +1 -0
- package/dist/components/ScrollArea/index.cjs +17 -0
- package/dist/components/ScrollArea/index.cjs.map +1 -0
- package/dist/components/ScrollArea/index.d.cts +22 -0
- package/dist/components/ScrollArea/index.d.ts +22 -0
- package/dist/components/ScrollArea/index.js +4 -0
- package/dist/components/ScrollArea/index.js.map +1 -0
- package/dist/components/Separator/index.cjs +17 -0
- package/dist/components/Separator/index.cjs.map +1 -0
- package/dist/components/Separator/index.d.cts +27 -0
- package/dist/components/Separator/index.d.ts +27 -0
- package/dist/components/Separator/index.js +4 -0
- package/dist/components/Separator/index.js.map +1 -0
- package/dist/components/Sheet/index.cjs +48 -0
- package/dist/components/Sheet/index.cjs.map +1 -0
- package/dist/components/Sheet/index.d.cts +62 -0
- package/dist/components/Sheet/index.d.ts +62 -0
- package/dist/components/Sheet/index.js +7 -0
- package/dist/components/Sheet/index.js.map +1 -0
- package/dist/components/Toggle/index.cjs +17 -0
- package/dist/components/Toggle/index.cjs.map +1 -0
- package/dist/components/Toggle/index.d.cts +28 -0
- package/dist/components/Toggle/index.d.ts +28 -0
- package/dist/components/Toggle/index.js +4 -0
- package/dist/components/Toggle/index.js.map +1 -0
- package/dist/hooks/index.cjs +5 -5
- package/dist/hooks/index.js +1 -1
- package/dist/html-MdxqSzjD.d.cts +13 -0
- package/dist/html-MdxqSzjD.d.ts +13 -0
- package/dist/index.cjs +352 -225
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +43 -32
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/index.cjs +27 -18
- package/dist/utils/index.d.cts +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +3 -2
- package/package.json +2 -2
- package/dist/chunk-74K3RRU7.cjs +0 -4
- package/dist/chunk-V2DF2GUE.js +0 -3
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
import { Separator } from './chunk-BX6BTDTR.js';
|
|
2
|
+
import { Dropdown, DropdownSeparator, DropdownLabel, DropdownItem } from './chunk-3OHVUXDG.js';
|
|
3
|
+
import { Button } from './chunk-ZVSW2KS6.js';
|
|
4
|
+
import { isHtmlEmpty } from './chunk-ERLPVXOV.js';
|
|
5
|
+
import { cn } from './chunk-F3SOEIN2.js';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import { Bold, Italic, Underline, List, ListOrdered, AlignLeft, AlignCenter, AlignRight, Braces, Replace, MicOff, Mic } from 'lucide-react';
|
|
8
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
9
|
+
|
|
10
|
+
// src/components/RichTextEditor/processDictation.ts
|
|
11
|
+
function processDictation(text) {
|
|
12
|
+
let result = text;
|
|
13
|
+
result = result.replace(
|
|
14
|
+
/\b(the|a|this|that|each|every|same|time|grace|trial|waiting|probationary|pay|billing|accounting)\s+period\b/gi,
|
|
15
|
+
"$1 period"
|
|
16
|
+
);
|
|
17
|
+
result = result.replace(
|
|
18
|
+
/\bperiod\s+(of|in|for|from|to|during|between|after|before|when|where|is|was|will|has|had)\b/gi,
|
|
19
|
+
"period $1"
|
|
20
|
+
);
|
|
21
|
+
result = result.replace(/\s+period(\s*$)/gi, ".$1");
|
|
22
|
+
result = result.replace(/\s+period\s+(?=[A-Z])/g, ". ");
|
|
23
|
+
result = result.replace(/\bcomma\s+(separated|delimited)/gi, "comma $1");
|
|
24
|
+
result = result.replace(/\s+comma\b/gi, ",");
|
|
25
|
+
result = result.replace(
|
|
26
|
+
/\b(the|a|my|your|his|her|their|semicolon|ascending|descending|transverse|sigmoid)\s+colon\b/gi,
|
|
27
|
+
"$1 colon"
|
|
28
|
+
);
|
|
29
|
+
result = result.replace(
|
|
30
|
+
/\bcolon\s+(cancer|surgery|health|polyp|scope|oscopy)/gi,
|
|
31
|
+
"colon $1"
|
|
32
|
+
);
|
|
33
|
+
result = result.replace(/\s+colon\b/gi, ":");
|
|
34
|
+
result = result.replace(
|
|
35
|
+
/\b(yard|meter|hundred|mad|quick|wild)\s+dash\b/gi,
|
|
36
|
+
"$1 dash"
|
|
37
|
+
);
|
|
38
|
+
result = result.replace(/\bdash\s+(to|for|of)\b/gi, "dash $1");
|
|
39
|
+
result = result.replace(/\s+dash\b/gi, " -");
|
|
40
|
+
const simplePunctuation = {
|
|
41
|
+
" full stop": ".",
|
|
42
|
+
" question mark": "?",
|
|
43
|
+
" exclamation point": "!",
|
|
44
|
+
" exclamation mark": "!",
|
|
45
|
+
" semicolon": ";",
|
|
46
|
+
" semi colon": ";",
|
|
47
|
+
" hyphen": "-",
|
|
48
|
+
" open parenthesis": " (",
|
|
49
|
+
" close parenthesis": ")",
|
|
50
|
+
" open bracket": " [",
|
|
51
|
+
" close bracket": "]",
|
|
52
|
+
" open quote": ' "',
|
|
53
|
+
" close quote": '"',
|
|
54
|
+
" quote": '"',
|
|
55
|
+
" apostrophe": "'",
|
|
56
|
+
" new line": "\n",
|
|
57
|
+
" newline": "\n",
|
|
58
|
+
" new paragraph": "\n\n",
|
|
59
|
+
" tab": " "
|
|
60
|
+
};
|
|
61
|
+
for (const [spoken, punctuation] of Object.entries(simplePunctuation)) {
|
|
62
|
+
const regex = new RegExp(spoken, "gi");
|
|
63
|
+
result = result.replace(regex, punctuation);
|
|
64
|
+
}
|
|
65
|
+
result = result.replace(
|
|
66
|
+
/([.!?])\s+([a-z])/g,
|
|
67
|
+
(_match, punct, letter) => `${punct} ${letter.toUpperCase()}`
|
|
68
|
+
);
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
function convertAngleBracketsToMustache(html) {
|
|
72
|
+
return html.replace(
|
|
73
|
+
/<<([^&]*)>>/g,
|
|
74
|
+
(_m, field) => `{{${field.trim()}}}`
|
|
75
|
+
).replace(/<<([^>]*)>>/g, (_m, field) => `{{${field.trim()}}}`);
|
|
76
|
+
}
|
|
77
|
+
function getSpeechRecognition() {
|
|
78
|
+
const w = window;
|
|
79
|
+
return w.SpeechRecognition || w.webkitSpeechRecognition;
|
|
80
|
+
}
|
|
81
|
+
var RichTextEditor = React.forwardRef(
|
|
82
|
+
({
|
|
83
|
+
value,
|
|
84
|
+
onChange,
|
|
85
|
+
placeholder,
|
|
86
|
+
className,
|
|
87
|
+
variableGroups,
|
|
88
|
+
enableDictation = true,
|
|
89
|
+
onDictationError,
|
|
90
|
+
disabled = false,
|
|
91
|
+
"aria-label": ariaLabel
|
|
92
|
+
}, ref) => {
|
|
93
|
+
const editorRef = React.useRef(null);
|
|
94
|
+
const [isListening, setIsListening] = React.useState(false);
|
|
95
|
+
const [speechSupported, setSpeechSupported] = React.useState(false);
|
|
96
|
+
const recognitionRef = React.useRef(null);
|
|
97
|
+
const isListeningRef = React.useRef(false);
|
|
98
|
+
const shouldRestartRef = React.useRef(false);
|
|
99
|
+
const hasVariables = Boolean(variableGroups && variableGroups.length > 0);
|
|
100
|
+
const isEmpty = isHtmlEmpty(value);
|
|
101
|
+
React.useImperativeHandle(ref, () => editorRef.current);
|
|
102
|
+
React.useEffect(() => {
|
|
103
|
+
setSpeechSupported(Boolean(getSpeechRecognition()));
|
|
104
|
+
}, []);
|
|
105
|
+
React.useEffect(() => {
|
|
106
|
+
return () => {
|
|
107
|
+
if (recognitionRef.current) {
|
|
108
|
+
shouldRestartRef.current = false;
|
|
109
|
+
isListeningRef.current = false;
|
|
110
|
+
recognitionRef.current.stop();
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}, []);
|
|
114
|
+
React.useEffect(() => {
|
|
115
|
+
if (editorRef.current && editorRef.current.innerHTML !== value) {
|
|
116
|
+
editorRef.current.innerHTML = value;
|
|
117
|
+
}
|
|
118
|
+
}, [value]);
|
|
119
|
+
const updateContent = () => {
|
|
120
|
+
if (editorRef.current) onChange(editorRef.current.innerHTML);
|
|
121
|
+
};
|
|
122
|
+
const execCommand = (command) => {
|
|
123
|
+
if (disabled) return;
|
|
124
|
+
document.execCommand(command, false);
|
|
125
|
+
editorRef.current?.focus();
|
|
126
|
+
updateContent();
|
|
127
|
+
};
|
|
128
|
+
const handleConvertToMustache = () => {
|
|
129
|
+
if (disabled || !editorRef.current) return;
|
|
130
|
+
editorRef.current.innerHTML = convertAngleBracketsToMustache(
|
|
131
|
+
editorRef.current.innerHTML
|
|
132
|
+
);
|
|
133
|
+
updateContent();
|
|
134
|
+
};
|
|
135
|
+
const insertVariable = (variable) => {
|
|
136
|
+
if (disabled || !editorRef.current) return;
|
|
137
|
+
editorRef.current.focus();
|
|
138
|
+
const textToInsert = variable.insertValue ?? variable.value;
|
|
139
|
+
const selection = window.getSelection();
|
|
140
|
+
if (selection && selection.rangeCount > 0) {
|
|
141
|
+
const range = selection.getRangeAt(0);
|
|
142
|
+
range.deleteContents();
|
|
143
|
+
if (textToInsert.includes("\n")) {
|
|
144
|
+
const fragment = document.createDocumentFragment();
|
|
145
|
+
const lines = textToInsert.split("\n");
|
|
146
|
+
lines.forEach((line, index) => {
|
|
147
|
+
fragment.appendChild(document.createTextNode(line));
|
|
148
|
+
if (index < lines.length - 1) {
|
|
149
|
+
fragment.appendChild(document.createElement("br"));
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
range.insertNode(fragment);
|
|
153
|
+
range.collapse(false);
|
|
154
|
+
} else {
|
|
155
|
+
const textNode = document.createTextNode(textToInsert);
|
|
156
|
+
range.insertNode(textNode);
|
|
157
|
+
range.setStartAfter(textNode);
|
|
158
|
+
range.setEndAfter(textNode);
|
|
159
|
+
}
|
|
160
|
+
selection.removeAllRanges();
|
|
161
|
+
selection.addRange(range);
|
|
162
|
+
} else {
|
|
163
|
+
editorRef.current.innerHTML += textToInsert.replace(/\n/g, "<br>");
|
|
164
|
+
}
|
|
165
|
+
updateContent();
|
|
166
|
+
};
|
|
167
|
+
const reportError = (message) => {
|
|
168
|
+
if (onDictationError) onDictationError(message);
|
|
169
|
+
else if (typeof console !== "undefined") console.warn(message);
|
|
170
|
+
};
|
|
171
|
+
const toggleDictation = async () => {
|
|
172
|
+
const SpeechRecognition = getSpeechRecognition();
|
|
173
|
+
if (!SpeechRecognition) return;
|
|
174
|
+
if (isListening && recognitionRef.current) {
|
|
175
|
+
shouldRestartRef.current = false;
|
|
176
|
+
isListeningRef.current = false;
|
|
177
|
+
recognitionRef.current.stop();
|
|
178
|
+
setIsListening(false);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
183
|
+
audio: true
|
|
184
|
+
});
|
|
185
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
186
|
+
} catch {
|
|
187
|
+
reportError(
|
|
188
|
+
"Microphone access is required for dictation. Please allow microphone access in your browser settings and try again."
|
|
189
|
+
);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const recognition = new SpeechRecognition();
|
|
193
|
+
recognition.continuous = true;
|
|
194
|
+
recognition.interimResults = true;
|
|
195
|
+
recognition.lang = "en-US";
|
|
196
|
+
recognition.maxAlternatives = 1;
|
|
197
|
+
recognition.onstart = () => {
|
|
198
|
+
setIsListening(true);
|
|
199
|
+
isListeningRef.current = true;
|
|
200
|
+
shouldRestartRef.current = true;
|
|
201
|
+
};
|
|
202
|
+
recognition.onresult = (event) => {
|
|
203
|
+
let finalTranscript = "";
|
|
204
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
205
|
+
const result = event.results[i];
|
|
206
|
+
if (result.isFinal) finalTranscript += result[0].transcript;
|
|
207
|
+
}
|
|
208
|
+
if (finalTranscript && editorRef.current) {
|
|
209
|
+
const processedText = processDictation(finalTranscript);
|
|
210
|
+
editorRef.current.focus();
|
|
211
|
+
const selection = window.getSelection();
|
|
212
|
+
if (selection && selection.rangeCount > 0) {
|
|
213
|
+
const range = selection.getRangeAt(0);
|
|
214
|
+
range.deleteContents();
|
|
215
|
+
const textNode = document.createTextNode(processedText + " ");
|
|
216
|
+
range.insertNode(textNode);
|
|
217
|
+
range.setStartAfter(textNode);
|
|
218
|
+
range.setEndAfter(textNode);
|
|
219
|
+
selection.removeAllRanges();
|
|
220
|
+
selection.addRange(range);
|
|
221
|
+
} else {
|
|
222
|
+
editorRef.current.innerHTML += processedText + " ";
|
|
223
|
+
}
|
|
224
|
+
updateContent();
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
recognition.onerror = (event) => {
|
|
228
|
+
if (event.error === "no-speech" || event.error === "aborted") return;
|
|
229
|
+
if (event.error === "not-allowed") {
|
|
230
|
+
reportError(
|
|
231
|
+
"Microphone access was denied. Please allow microphone access in your browser settings and try again."
|
|
232
|
+
);
|
|
233
|
+
shouldRestartRef.current = false;
|
|
234
|
+
isListeningRef.current = false;
|
|
235
|
+
setIsListening(false);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (event.error === "network") return;
|
|
239
|
+
shouldRestartRef.current = false;
|
|
240
|
+
isListeningRef.current = false;
|
|
241
|
+
setIsListening(false);
|
|
242
|
+
};
|
|
243
|
+
recognition.onend = () => {
|
|
244
|
+
if (shouldRestartRef.current && isListeningRef.current) {
|
|
245
|
+
setTimeout(() => {
|
|
246
|
+
if (shouldRestartRef.current && isListeningRef.current) {
|
|
247
|
+
try {
|
|
248
|
+
recognition.start();
|
|
249
|
+
} catch {
|
|
250
|
+
shouldRestartRef.current = false;
|
|
251
|
+
isListeningRef.current = false;
|
|
252
|
+
setIsListening(false);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}, 100);
|
|
256
|
+
} else {
|
|
257
|
+
setIsListening(false);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
recognitionRef.current = recognition;
|
|
261
|
+
try {
|
|
262
|
+
recognition.start();
|
|
263
|
+
} catch {
|
|
264
|
+
reportError("Failed to start speech recognition. Please try again.");
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const iconButtonClass = "h-8 w-8 p-0";
|
|
268
|
+
return /* @__PURE__ */ jsxs(
|
|
269
|
+
"div",
|
|
270
|
+
{
|
|
271
|
+
"data-slot": "rich-text-editor",
|
|
272
|
+
className: cn(
|
|
273
|
+
"border-border bg-background flex flex-col overflow-hidden rounded-lg border",
|
|
274
|
+
className
|
|
275
|
+
),
|
|
276
|
+
children: [
|
|
277
|
+
/* @__PURE__ */ jsxs(
|
|
278
|
+
"div",
|
|
279
|
+
{
|
|
280
|
+
"data-slot": "rich-text-editor-toolbar",
|
|
281
|
+
className: "border-border bg-muted/30 sticky top-0 z-10 flex flex-wrap items-center gap-1 border-b p-2",
|
|
282
|
+
children: [
|
|
283
|
+
/* @__PURE__ */ jsx(
|
|
284
|
+
Button,
|
|
285
|
+
{
|
|
286
|
+
type: "button",
|
|
287
|
+
variant: "ghost",
|
|
288
|
+
size: "sm",
|
|
289
|
+
onClick: () => execCommand("bold"),
|
|
290
|
+
disabled,
|
|
291
|
+
className: iconButtonClass,
|
|
292
|
+
"aria-label": "Bold",
|
|
293
|
+
title: "Bold",
|
|
294
|
+
children: /* @__PURE__ */ jsx(Bold, { className: "h-4 w-4" })
|
|
295
|
+
}
|
|
296
|
+
),
|
|
297
|
+
/* @__PURE__ */ jsx(
|
|
298
|
+
Button,
|
|
299
|
+
{
|
|
300
|
+
type: "button",
|
|
301
|
+
variant: "ghost",
|
|
302
|
+
size: "sm",
|
|
303
|
+
onClick: () => execCommand("italic"),
|
|
304
|
+
disabled,
|
|
305
|
+
className: iconButtonClass,
|
|
306
|
+
"aria-label": "Italic",
|
|
307
|
+
title: "Italic",
|
|
308
|
+
children: /* @__PURE__ */ jsx(Italic, { className: "h-4 w-4" })
|
|
309
|
+
}
|
|
310
|
+
),
|
|
311
|
+
/* @__PURE__ */ jsx(
|
|
312
|
+
Button,
|
|
313
|
+
{
|
|
314
|
+
type: "button",
|
|
315
|
+
variant: "ghost",
|
|
316
|
+
size: "sm",
|
|
317
|
+
onClick: () => execCommand("underline"),
|
|
318
|
+
disabled,
|
|
319
|
+
className: iconButtonClass,
|
|
320
|
+
"aria-label": "Underline",
|
|
321
|
+
title: "Underline",
|
|
322
|
+
children: /* @__PURE__ */ jsx(Underline, { className: "h-4 w-4" })
|
|
323
|
+
}
|
|
324
|
+
),
|
|
325
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mx-1 h-6" }),
|
|
326
|
+
/* @__PURE__ */ jsx(
|
|
327
|
+
Button,
|
|
328
|
+
{
|
|
329
|
+
type: "button",
|
|
330
|
+
variant: "ghost",
|
|
331
|
+
size: "sm",
|
|
332
|
+
onClick: () => execCommand("insertUnorderedList"),
|
|
333
|
+
disabled,
|
|
334
|
+
className: iconButtonClass,
|
|
335
|
+
"aria-label": "Bullet list",
|
|
336
|
+
title: "Bullet list",
|
|
337
|
+
children: /* @__PURE__ */ jsx(List, { className: "h-4 w-4" })
|
|
338
|
+
}
|
|
339
|
+
),
|
|
340
|
+
/* @__PURE__ */ jsx(
|
|
341
|
+
Button,
|
|
342
|
+
{
|
|
343
|
+
type: "button",
|
|
344
|
+
variant: "ghost",
|
|
345
|
+
size: "sm",
|
|
346
|
+
onClick: () => execCommand("insertOrderedList"),
|
|
347
|
+
disabled,
|
|
348
|
+
className: iconButtonClass,
|
|
349
|
+
"aria-label": "Numbered list",
|
|
350
|
+
title: "Numbered list",
|
|
351
|
+
children: /* @__PURE__ */ jsx(ListOrdered, { className: "h-4 w-4" })
|
|
352
|
+
}
|
|
353
|
+
),
|
|
354
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mx-1 h-6" }),
|
|
355
|
+
/* @__PURE__ */ jsx(
|
|
356
|
+
Button,
|
|
357
|
+
{
|
|
358
|
+
type: "button",
|
|
359
|
+
variant: "ghost",
|
|
360
|
+
size: "sm",
|
|
361
|
+
onClick: () => execCommand("justifyLeft"),
|
|
362
|
+
disabled,
|
|
363
|
+
className: iconButtonClass,
|
|
364
|
+
"aria-label": "Align left",
|
|
365
|
+
title: "Align left",
|
|
366
|
+
children: /* @__PURE__ */ jsx(AlignLeft, { className: "h-4 w-4" })
|
|
367
|
+
}
|
|
368
|
+
),
|
|
369
|
+
/* @__PURE__ */ jsx(
|
|
370
|
+
Button,
|
|
371
|
+
{
|
|
372
|
+
type: "button",
|
|
373
|
+
variant: "ghost",
|
|
374
|
+
size: "sm",
|
|
375
|
+
onClick: () => execCommand("justifyCenter"),
|
|
376
|
+
disabled,
|
|
377
|
+
className: iconButtonClass,
|
|
378
|
+
"aria-label": "Align center",
|
|
379
|
+
title: "Align center",
|
|
380
|
+
children: /* @__PURE__ */ jsx(AlignCenter, { className: "h-4 w-4" })
|
|
381
|
+
}
|
|
382
|
+
),
|
|
383
|
+
/* @__PURE__ */ jsx(
|
|
384
|
+
Button,
|
|
385
|
+
{
|
|
386
|
+
type: "button",
|
|
387
|
+
variant: "ghost",
|
|
388
|
+
size: "sm",
|
|
389
|
+
onClick: () => execCommand("justifyRight"),
|
|
390
|
+
disabled,
|
|
391
|
+
className: iconButtonClass,
|
|
392
|
+
"aria-label": "Align right",
|
|
393
|
+
title: "Align right",
|
|
394
|
+
children: /* @__PURE__ */ jsx(AlignRight, { className: "h-4 w-4" })
|
|
395
|
+
}
|
|
396
|
+
),
|
|
397
|
+
hasVariables && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
398
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mx-1 h-6" }),
|
|
399
|
+
/* @__PURE__ */ jsx(
|
|
400
|
+
Dropdown,
|
|
401
|
+
{
|
|
402
|
+
placement: "bottom-start",
|
|
403
|
+
width: 240,
|
|
404
|
+
searchable: true,
|
|
405
|
+
searchPlaceholder: "Search variables\u2026",
|
|
406
|
+
searchAriaLabel: "Search template variables",
|
|
407
|
+
disabled,
|
|
408
|
+
trigger: /* @__PURE__ */ jsxs(
|
|
409
|
+
Button,
|
|
410
|
+
{
|
|
411
|
+
type: "button",
|
|
412
|
+
variant: "ghost",
|
|
413
|
+
size: "sm",
|
|
414
|
+
className: "h-8 gap-1 px-2",
|
|
415
|
+
disabled,
|
|
416
|
+
title: "Insert variable",
|
|
417
|
+
children: [
|
|
418
|
+
/* @__PURE__ */ jsx(Braces, { className: "h-4 w-4" }),
|
|
419
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: "Variables" })
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
),
|
|
423
|
+
children: variableGroups.map((group, groupIndex) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
424
|
+
groupIndex > 0 && /* @__PURE__ */ jsx(DropdownSeparator, {}),
|
|
425
|
+
/* @__PURE__ */ jsx(DropdownLabel, { children: group.label }),
|
|
426
|
+
group.variables.map((variable) => /* @__PURE__ */ jsx(
|
|
427
|
+
DropdownItem,
|
|
428
|
+
{
|
|
429
|
+
onClick: () => insertVariable(variable),
|
|
430
|
+
children: variable.label
|
|
431
|
+
},
|
|
432
|
+
variable.value
|
|
433
|
+
))
|
|
434
|
+
] }, group.label))
|
|
435
|
+
}
|
|
436
|
+
),
|
|
437
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mx-1 h-6" }),
|
|
438
|
+
/* @__PURE__ */ jsxs(
|
|
439
|
+
Button,
|
|
440
|
+
{
|
|
441
|
+
type: "button",
|
|
442
|
+
variant: "ghost",
|
|
443
|
+
size: "sm",
|
|
444
|
+
onClick: handleConvertToMustache,
|
|
445
|
+
disabled,
|
|
446
|
+
className: "h-8 gap-1 px-2",
|
|
447
|
+
title: "Convert <<field>> to {{field}}",
|
|
448
|
+
children: [
|
|
449
|
+
/* @__PURE__ */ jsx(Replace, { className: "h-4 w-4" }),
|
|
450
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: "<< >> to {{ }}" })
|
|
451
|
+
]
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
] }),
|
|
455
|
+
enableDictation && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
456
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mx-1 h-6" }),
|
|
457
|
+
/* @__PURE__ */ jsxs(
|
|
458
|
+
Button,
|
|
459
|
+
{
|
|
460
|
+
type: "button",
|
|
461
|
+
variant: isListening ? "danger" : "ghost",
|
|
462
|
+
size: "sm",
|
|
463
|
+
onClick: toggleDictation,
|
|
464
|
+
disabled: disabled || !speechSupported,
|
|
465
|
+
className: cn("h-8 gap-1 px-2", isListening && "animate-pulse"),
|
|
466
|
+
title: !speechSupported ? "Speech recognition not supported in this browser" : isListening ? "Stop dictation" : "Start dictation",
|
|
467
|
+
children: [
|
|
468
|
+
isListening ? /* @__PURE__ */ jsx(MicOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" }),
|
|
469
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: isListening ? "Stop" : "Dictate" })
|
|
470
|
+
]
|
|
471
|
+
}
|
|
472
|
+
)
|
|
473
|
+
] })
|
|
474
|
+
]
|
|
475
|
+
}
|
|
476
|
+
),
|
|
477
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
478
|
+
isEmpty && placeholder && /* @__PURE__ */ jsx(
|
|
479
|
+
"div",
|
|
480
|
+
{
|
|
481
|
+
"aria-hidden": "true",
|
|
482
|
+
className: "text-muted-foreground pointer-events-none absolute top-0 left-0 p-4",
|
|
483
|
+
children: placeholder
|
|
484
|
+
}
|
|
485
|
+
),
|
|
486
|
+
/* @__PURE__ */ jsx(
|
|
487
|
+
"div",
|
|
488
|
+
{
|
|
489
|
+
ref: editorRef,
|
|
490
|
+
role: "textbox",
|
|
491
|
+
"aria-multiline": "true",
|
|
492
|
+
"aria-label": ariaLabel ?? placeholder,
|
|
493
|
+
contentEditable: !disabled,
|
|
494
|
+
onInput: updateContent,
|
|
495
|
+
className: cn(
|
|
496
|
+
"min-h-[250px] overflow-y-auto p-4 focus:outline-none",
|
|
497
|
+
"prose prose-sm max-w-none",
|
|
498
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
499
|
+
),
|
|
500
|
+
suppressContentEditableWarning: true
|
|
501
|
+
}
|
|
502
|
+
)
|
|
503
|
+
] })
|
|
504
|
+
]
|
|
505
|
+
}
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
RichTextEditor.displayName = "RichTextEditor";
|
|
510
|
+
|
|
511
|
+
export { RichTextEditor, convertAngleBracketsToMustache, processDictation };
|
|
512
|
+
//# sourceMappingURL=chunk-AEGYWRSL.js.map
|
|
513
|
+
//# sourceMappingURL=chunk-AEGYWRSL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/RichTextEditor/processDictation.ts","../src/components/RichTextEditor/RichTextEditor.tsx"],"names":["Fragment"],"mappings":";;;;;;;;;;AAMO,SAAS,iBAAiB,IAAA,EAAsB;AACrD,EAAA,IAAI,MAAA,GAAS,IAAA;AAGb,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,IACd,+GAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,IACd,+FAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,mBAAA,EAAqB,KAAK,CAAA;AAClD,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,wBAAA,EAA0B,IAAI,CAAA;AAGtD,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,mCAAA,EAAqC,UAAU,CAAA;AACvE,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,cAAA,EAAgB,GAAG,CAAA;AAG3C,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,IACd,+FAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,IACd,wDAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,cAAA,EAAgB,GAAG,CAAA;AAG3C,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,IACd,kDAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,0BAAA,EAA4B,SAAS,CAAA;AAC7D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,aAAA,EAAe,IAAI,CAAA;AAE3C,EAAA,MAAM,iBAAA,GAA4C;AAAA,IAChD,YAAA,EAAc,GAAA;AAAA,IACd,gBAAA,EAAkB,GAAA;AAAA,IAClB,oBAAA,EAAsB,GAAA;AAAA,IACtB,mBAAA,EAAqB,GAAA;AAAA,IACrB,YAAA,EAAc,GAAA;AAAA,IACd,aAAA,EAAe,GAAA;AAAA,IACf,SAAA,EAAW,GAAA;AAAA,IACX,mBAAA,EAAqB,IAAA;AAAA,IACrB,oBAAA,EAAsB,GAAA;AAAA,IACtB,eAAA,EAAiB,IAAA;AAAA,IACjB,gBAAA,EAAkB,GAAA;AAAA,IAClB,aAAA,EAAe,IAAA;AAAA,IACf,cAAA,EAAgB,GAAA;AAAA,IAChB,QAAA,EAAU,GAAA;AAAA,IACV,aAAA,EAAe,GAAA;AAAA,IACf,WAAA,EAAa,IAAA;AAAA,IACb,UAAA,EAAY,IAAA;AAAA,IACZ,gBAAA,EAAkB,MAAA;AAAA,IAClB,MAAA,EAAQ;AAAA,GACV;AAEA,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,WAAW,KAAK,MAAA,CAAO,OAAA,CAAQ,iBAAiB,CAAA,EAAG;AACrE,IAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,CAAO,MAAA,EAAQ,IAAI,CAAA;AACrC,IAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,WAAW,CAAA;AAAA,EAC5C;AAGA,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,IACd,oBAAA;AAAA,IACA,CAAC,QAAQ,KAAA,EAAe,MAAA,KACtB,GAAG,KAAK,CAAA,CAAA,EAAI,MAAA,CAAO,WAAA,EAAa,CAAA;AAAA,GACpC;AAEA,EAAA,OAAO,MAAA;AACT;AAMO,SAAS,+BAA+B,IAAA,EAAsB;AACnE,EAAA,OAAO,IAAA,CACJ,OAAA;AAAA,IACC,0BAAA;AAAA,IACA,CAAC,EAAA,EAAI,KAAA,KAAkB,CAAA,EAAA,EAAK,KAAA,CAAM,MAAM,CAAA,EAAA;AAAA,GAC1C,CACC,OAAA,CAAQ,cAAA,EAAgB,CAAC,EAAA,EAAI,UAAkB,CAAA,EAAA,EAAK,KAAA,CAAM,IAAA,EAAM,CAAA,EAAA,CAAI,CAAA;AACzE;ACeA,SAAS,oBAAA,GAA0D;AACjE,EAAA,MAAM,CAAA,GAAI,MAAA;AACV,EAAA,OAAO,CAAA,CAAE,qBAAqB,CAAA,CAAE,uBAAA;AAClC;AAQA,IAAM,cAAA,GAAuB,KAAA,CAAA,UAAA;AAAA,EAC3B,CACE;AAAA,IACE,KAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,cAAA;AAAA,IACA,eAAA,GAAkB,IAAA;AAAA,IAClB,gBAAA;AAAA,IACA,QAAA,GAAW,KAAA;AAAA,IACX,YAAA,EAAc;AAAA,KAEhB,GAAA,KACG;AACH,IAAA,MAAM,SAAA,GAAkB,aAAuB,IAAI,CAAA;AACnD,IAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAU,eAAS,KAAK,CAAA;AAC1D,IAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAU,eAAS,KAAK,CAAA;AAClE,IAAA,MAAM,cAAA,GAAuB,aAAqC,IAAI,CAAA;AACtE,IAAA,MAAM,cAAA,GAAuB,aAAO,KAAK,CAAA;AACzC,IAAA,MAAM,gBAAA,GAAyB,aAAO,KAAK,CAAA;AAE3C,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,cAAA,IAAkB,cAAA,CAAe,SAAS,CAAC,CAAA;AACxE,IAAA,MAAM,OAAA,GAAU,YAAY,KAAK,CAAA;AAEjC,IAAM,KAAA,CAAA,mBAAA,CAAoB,GAAA,EAAK,MAAM,SAAA,CAAU,OAAyB,CAAA;AAExE,IAAM,gBAAU,MAAM;AACpB,MAAA,kBAAA,CAAmB,OAAA,CAAQ,oBAAA,EAAsB,CAAC,CAAA;AAAA,IACpD,CAAA,EAAG,EAAE,CAAA;AAEL,IAAM,gBAAU,MAAM;AACpB,MAAA,OAAO,MAAM;AACX,QAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,UAAA,gBAAA,CAAiB,OAAA,GAAU,KAAA;AAC3B,UAAA,cAAA,CAAe,OAAA,GAAU,KAAA;AACzB,UAAA,cAAA,CAAe,QAAQ,IAAA,EAAK;AAAA,QAC9B;AAAA,MACF,CAAA;AAAA,IACF,CAAA,EAAG,EAAE,CAAA;AAEL,IAAM,gBAAU,MAAM;AACpB,MAAA,IAAI,SAAA,CAAU,OAAA,IAAW,SAAA,CAAU,OAAA,CAAQ,cAAc,KAAA,EAAO;AAC9D,QAAA,SAAA,CAAU,QAAQ,SAAA,GAAY,KAAA;AAAA,MAChC;AAAA,IACF,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,IAAA,MAAM,gBAAgB,MAAM;AAC1B,MAAA,IAAI,SAAA,CAAU,OAAA,EAAS,QAAA,CAAS,SAAA,CAAU,QAAQ,SAAS,CAAA;AAAA,IAC7D,CAAA;AAEA,IAAA,MAAM,WAAA,GAAc,CAAC,OAAA,KAAoB;AACvC,MAAA,IAAI,QAAA,EAAU;AACd,MAAA,QAAA,CAAS,WAAA,CAAY,SAAS,KAAK,CAAA;AACnC,MAAA,SAAA,CAAU,SAAS,KAAA,EAAM;AACzB,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAEA,IAAA,MAAM,0BAA0B,MAAM;AACpC,MAAA,IAAI,QAAA,IAAY,CAAC,SAAA,CAAU,OAAA,EAAS;AACpC,MAAA,SAAA,CAAU,QAAQ,SAAA,GAAY,8BAAA;AAAA,QAC5B,UAAU,OAAA,CAAQ;AAAA,OACpB;AACA,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAEA,IAAA,MAAM,cAAA,GAAiB,CAAC,QAAA,KAA+B;AACrD,MAAA,IAAI,QAAA,IAAY,CAAC,SAAA,CAAU,OAAA,EAAS;AACpC,MAAA,SAAA,CAAU,QAAQ,KAAA,EAAM;AACxB,MAAA,MAAM,YAAA,GAAe,QAAA,CAAS,WAAA,IAAe,QAAA,CAAS,KAAA;AAEtD,MAAA,MAAM,SAAA,GAAY,OAAO,YAAA,EAAa;AACtC,MAAA,IAAI,SAAA,IAAa,SAAA,CAAU,UAAA,GAAa,CAAA,EAAG;AACzC,QAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,UAAA,CAAW,CAAC,CAAA;AACpC,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,IAAI,YAAA,CAAa,QAAA,CAAS,IAAI,CAAA,EAAG;AAC/B,UAAA,MAAM,QAAA,GAAW,SAAS,sBAAA,EAAuB;AACjD,UAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,KAAA,CAAM,IAAI,CAAA;AACrC,UAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AAC7B,YAAA,QAAA,CAAS,WAAA,CAAY,QAAA,CAAS,cAAA,CAAe,IAAI,CAAC,CAAA;AAClD,YAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC5B,cAAA,QAAA,CAAS,WAAA,CAAY,QAAA,CAAS,aAAA,CAAc,IAAI,CAAC,CAAA;AAAA,YACnD;AAAA,UACF,CAAC,CAAA;AACD,UAAA,KAAA,CAAM,WAAW,QAAQ,CAAA;AACzB,UAAA,KAAA,CAAM,SAAS,KAAK,CAAA;AAAA,QACtB,CAAA,MAAO;AACL,UAAA,MAAM,QAAA,GAAW,QAAA,CAAS,cAAA,CAAe,YAAY,CAAA;AACrD,UAAA,KAAA,CAAM,WAAW,QAAQ,CAAA;AACzB,UAAA,KAAA,CAAM,cAAc,QAAQ,CAAA;AAC5B,UAAA,KAAA,CAAM,YAAY,QAAQ,CAAA;AAAA,QAC5B;AACA,QAAA,SAAA,CAAU,eAAA,EAAgB;AAC1B,QAAA,SAAA,CAAU,SAAS,KAAK,CAAA;AAAA,MAC1B,CAAA,MAAO;AACL,QAAA,SAAA,CAAU,OAAA,CAAQ,SAAA,IAAa,YAAA,CAAa,OAAA,CAAQ,OAAO,MAAM,CAAA;AAAA,MACnE;AACA,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAEA,IAAA,MAAM,WAAA,GAAc,CAAC,OAAA,KAAoB;AACvC,MAAA,IAAI,gBAAA,mBAAmC,OAAO,CAAA;AAAA,WAAA,IACrC,OAAO,OAAA,KAAY,WAAA,EAAa,OAAA,CAAQ,KAAK,OAAO,CAAA;AAAA,IAC/D,CAAA;AAEA,IAAA,MAAM,kBAAkB,YAAY;AAClC,MAAA,MAAM,oBAAoB,oBAAA,EAAqB;AAC/C,MAAA,IAAI,CAAC,iBAAA,EAAmB;AAExB,MAAA,IAAI,WAAA,IAAe,eAAe,OAAA,EAAS;AACzC,QAAA,gBAAA,CAAiB,OAAA,GAAU,KAAA;AAC3B,QAAA,cAAA,CAAe,OAAA,GAAU,KAAA;AACzB,QAAA,cAAA,CAAe,QAAQ,IAAA,EAAK;AAC5B,QAAA,cAAA,CAAe,KAAK,CAAA;AACpB,QAAA;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,YAAA,CAAa,YAAA,CAAa;AAAA,UACvD,KAAA,EAAO;AAAA,SACR,CAAA;AACD,QAAA,MAAA,CAAO,WAAU,CAAE,OAAA,CAAQ,CAAC,KAAA,KAAU,KAAA,CAAM,MAAM,CAAA;AAAA,MACpD,CAAA,CAAA,MAAQ;AACN,QAAA,WAAA;AAAA,UACE;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,WAAA,GAAc,IAAI,iBAAA,EAAkB;AAC1C,MAAA,WAAA,CAAY,UAAA,GAAa,IAAA;AACzB,MAAA,WAAA,CAAY,cAAA,GAAiB,IAAA;AAC7B,MAAA,WAAA,CAAY,IAAA,GAAO,OAAA;AACnB,MAAA,WAAA,CAAY,eAAA,GAAkB,CAAA;AAE9B,MAAA,WAAA,CAAY,UAAU,MAAM;AAC1B,QAAA,cAAA,CAAe,IAAI,CAAA;AACnB,QAAA,cAAA,CAAe,OAAA,GAAU,IAAA;AACzB,QAAA,gBAAA,CAAiB,OAAA,GAAU,IAAA;AAAA,MAC7B,CAAA;AAEA,MAAA,WAAA,CAAY,QAAA,GAAW,CAAC,KAAA,KAAU;AAChC,QAAA,IAAI,eAAA,GAAkB,EAAA;AACtB,QAAA,KAAA,IAAS,IAAI,KAAA,CAAM,WAAA,EAAa,IAAI,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AAC7D,UAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAC9B,UAAA,IAAI,MAAA,CAAO,OAAA,EAAS,eAAA,IAAmB,MAAA,CAAO,CAAC,CAAA,CAAE,UAAA;AAAA,QACnD;AAEA,QAAA,IAAI,eAAA,IAAmB,UAAU,OAAA,EAAS;AACxC,UAAA,MAAM,aAAA,GAAgB,iBAAiB,eAAe,CAAA;AACtD,UAAA,SAAA,CAAU,QAAQ,KAAA,EAAM;AACxB,UAAA,MAAM,SAAA,GAAY,OAAO,YAAA,EAAa;AACtC,UAAA,IAAI,SAAA,IAAa,SAAA,CAAU,UAAA,GAAa,CAAA,EAAG;AACzC,YAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,UAAA,CAAW,CAAC,CAAA;AACpC,YAAA,KAAA,CAAM,cAAA,EAAe;AACrB,YAAA,MAAM,QAAA,GAAW,QAAA,CAAS,cAAA,CAAe,aAAA,GAAgB,GAAG,CAAA;AAC5D,YAAA,KAAA,CAAM,WAAW,QAAQ,CAAA;AACzB,YAAA,KAAA,CAAM,cAAc,QAAQ,CAAA;AAC5B,YAAA,KAAA,CAAM,YAAY,QAAQ,CAAA;AAC1B,YAAA,SAAA,CAAU,eAAA,EAAgB;AAC1B,YAAA,SAAA,CAAU,SAAS,KAAK,CAAA;AAAA,UAC1B,CAAA,MAAO;AACL,YAAA,SAAA,CAAU,OAAA,CAAQ,aAAa,aAAA,GAAgB,GAAA;AAAA,UACjD;AACA,UAAA,aAAA,EAAc;AAAA,QAChB;AAAA,MACF,CAAA;AAEA,MAAA,WAAA,CAAY,OAAA,GAAU,CAAC,KAAA,KAAU;AAC/B,QAAA,IAAI,KAAA,CAAM,KAAA,KAAU,WAAA,IAAe,KAAA,CAAM,UAAU,SAAA,EAAW;AAC9D,QAAA,IAAI,KAAA,CAAM,UAAU,aAAA,EAAe;AACjC,UAAA,WAAA;AAAA,YACE;AAAA,WACF;AACA,UAAA,gBAAA,CAAiB,OAAA,GAAU,KAAA;AAC3B,UAAA,cAAA,CAAe,OAAA,GAAU,KAAA;AACzB,UAAA,cAAA,CAAe,KAAK,CAAA;AACpB,UAAA;AAAA,QACF;AACA,QAAA,IAAI,KAAA,CAAM,UAAU,SAAA,EAAW;AAC/B,QAAA,gBAAA,CAAiB,OAAA,GAAU,KAAA;AAC3B,QAAA,cAAA,CAAe,OAAA,GAAU,KAAA;AACzB,QAAA,cAAA,CAAe,KAAK,CAAA;AAAA,MACtB,CAAA;AAEA,MAAA,WAAA,CAAY,QAAQ,MAAM;AACxB,QAAA,IAAI,gBAAA,CAAiB,OAAA,IAAW,cAAA,CAAe,OAAA,EAAS;AACtD,UAAA,UAAA,CAAW,MAAM;AACf,YAAA,IAAI,gBAAA,CAAiB,OAAA,IAAW,cAAA,CAAe,OAAA,EAAS;AACtD,cAAA,IAAI;AACF,gBAAA,WAAA,CAAY,KAAA,EAAM;AAAA,cACpB,CAAA,CAAA,MAAQ;AACN,gBAAA,gBAAA,CAAiB,OAAA,GAAU,KAAA;AAC3B,gBAAA,cAAA,CAAe,OAAA,GAAU,KAAA;AACzB,gBAAA,cAAA,CAAe,KAAK,CAAA;AAAA,cACtB;AAAA,YACF;AAAA,UACF,GAAG,GAAG,CAAA;AAAA,QACR,CAAA,MAAO;AACL,UAAA,cAAA,CAAe,KAAK,CAAA;AAAA,QACtB;AAAA,MACF,CAAA;AAEA,MAAA,cAAA,CAAe,OAAA,GAAU,WAAA;AACzB,MAAA,IAAI;AACF,QAAA,WAAA,CAAY,KAAA,EAAM;AAAA,MACpB,CAAA,CAAA,MAAQ;AACN,QAAA,WAAA,CAAY,uDAAuD,CAAA;AAAA,MACrE;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,eAAA,GAAkB,aAAA;AAExB,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,WAAA,EAAU,kBAAA;AAAA,QACV,SAAA,EAAW,EAAA;AAAA,UACT,6EAAA;AAAA,UACA;AAAA,SACF;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,WAAA,EAAU,0BAAA;AAAA,cACV,SAAA,EAAU,4FAAA;AAAA,cAEV,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,MAAM,CAAA;AAAA,oBACjC,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,MAAA;AAAA,oBACX,KAAA,EAAM,MAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBAC5B;AAAA,gCACA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,QAAQ,CAAA;AAAA,oBACnC,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,QAAA;AAAA,oBACX,KAAA,EAAM,QAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBAC9B;AAAA,gCACA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,WAAW,CAAA;AAAA,oBACtC,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,WAAA;AAAA,oBACX,KAAA,EAAM,WAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBACjC;AAAA,gCAEA,GAAA,CAAC,SAAA,EAAA,EAAU,WAAA,EAAY,UAAA,EAAW,WAAU,UAAA,EAAW,CAAA;AAAA,gCAEvD,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,qBAAqB,CAAA;AAAA,oBAChD,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,aAAA;AAAA,oBACX,KAAA,EAAM,aAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBAC5B;AAAA,gCACA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,mBAAmB,CAAA;AAAA,oBAC9C,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,eAAA;AAAA,oBACX,KAAA,EAAM,eAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBACnC;AAAA,gCAEA,GAAA,CAAC,SAAA,EAAA,EAAU,WAAA,EAAY,UAAA,EAAW,WAAU,UAAA,EAAW,CAAA;AAAA,gCAEvD,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,aAAa,CAAA;AAAA,oBACxC,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,YAAA;AAAA,oBACX,KAAA,EAAM,YAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBACjC;AAAA,gCACA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,eAAe,CAAA;AAAA,oBAC1C,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,cAAA;AAAA,oBACX,KAAA,EAAM,cAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBACnC;AAAA,gCACA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,OAAA,EAAQ,OAAA;AAAA,oBACR,IAAA,EAAK,IAAA;AAAA,oBACL,OAAA,EAAS,MAAM,WAAA,CAAY,cAAc,CAAA;AAAA,oBACzC,QAAA;AAAA,oBACA,SAAA,EAAW,eAAA;AAAA,oBACX,YAAA,EAAW,aAAA;AAAA,oBACX,KAAA,EAAM,aAAA;AAAA,oBAEN,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA,iBAClC;AAAA,gBAEC,YAAA,oBACC,IAAA,CAAAA,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,SAAA,EAAA,EAAU,WAAA,EAAY,UAAA,EAAW,SAAA,EAAU,UAAA,EAAW,CAAA;AAAA,kCACvD,GAAA;AAAA,oBAAC,QAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,cAAA;AAAA,sBACV,KAAA,EAAO,GAAA;AAAA,sBACP,UAAA,EAAU,IAAA;AAAA,sBACV,iBAAA,EAAkB,wBAAA;AAAA,sBAClB,eAAA,EAAgB,2BAAA;AAAA,sBAChB,QAAA;AAAA,sBACA,OAAA,kBACE,IAAA;AAAA,wBAAC,MAAA;AAAA,wBAAA;AAAA,0BACC,IAAA,EAAK,QAAA;AAAA,0BACL,OAAA,EAAQ,OAAA;AAAA,0BACR,IAAA,EAAK,IAAA;AAAA,0BACL,SAAA,EAAU,gBAAA;AAAA,0BACV,QAAA;AAAA,0BACA,KAAA,EAAM,iBAAA;AAAA,0BAEN,QAAA,EAAA;AAAA,4CAAA,GAAA,CAAC,MAAA,EAAA,EAAO,WAAU,SAAA,EAAU,CAAA;AAAA,4CAC5B,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAU,QAAA,EAAA,WAAA,EAAS;AAAA;AAAA;AAAA,uBACrC;AAAA,sBAGD,yBAAgB,GAAA,CAAI,CAAC,OAAO,UAAA,qBAC3B,IAAA,CAAO,gBAAN,EACE,QAAA,EAAA;AAAA,wBAAA,UAAA,GAAa,CAAA,wBAAM,iBAAA,EAAA,EAAkB,CAAA;AAAA,wCACtC,GAAA,CAAC,aAAA,EAAA,EAAe,QAAA,EAAA,KAAA,CAAM,KAAA,EAAM,CAAA;AAAA,wBAC3B,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,CAAC,QAAA,qBACpB,GAAA;AAAA,0BAAC,YAAA;AAAA,0BAAA;AAAA,4BAEC,OAAA,EAAS,MAAM,cAAA,CAAe,QAAQ,CAAA;AAAA,4BAErC,QAAA,EAAA,QAAA,CAAS;AAAA,2BAAA;AAAA,0BAHL,QAAA,CAAS;AAAA,yBAKjB;AAAA,uBAAA,EAAA,EAVkB,KAAA,CAAM,KAW3B,CACD;AAAA;AAAA,mBACH;AAAA,kCAEA,GAAA,CAAC,SAAA,EAAA,EAAU,WAAA,EAAY,UAAA,EAAW,WAAU,UAAA,EAAW,CAAA;AAAA,kCACvD,IAAA;AAAA,oBAAC,MAAA;AAAA,oBAAA;AAAA,sBACC,IAAA,EAAK,QAAA;AAAA,sBACL,OAAA,EAAQ,OAAA;AAAA,sBACR,IAAA,EAAK,IAAA;AAAA,sBACL,OAAA,EAAS,uBAAA;AAAA,sBACT,QAAA;AAAA,sBACA,SAAA,EAAU,gBAAA;AAAA,sBACV,KAAA,EAAM,gCAAA;AAAA,sBAEN,QAAA,EAAA;AAAA,wCAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,WAAU,SAAA,EAAU,CAAA;AAAA,wCAC7B,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,QAAA,EAAA,gBAAA,EAAiB;AAAA;AAAA;AAAA;AAC9C,iBAAA,EACF,CAAA;AAAA,gBAGD,eAAA,oBACC,IAAA,CAAAA,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,SAAA,EAAA,EAAU,WAAA,EAAY,UAAA,EAAW,SAAA,EAAU,UAAA,EAAW,CAAA;AAAA,kCACvD,IAAA;AAAA,oBAAC,MAAA;AAAA,oBAAA;AAAA,sBACC,IAAA,EAAK,QAAA;AAAA,sBACL,OAAA,EAAS,cAAc,QAAA,GAAW,OAAA;AAAA,sBAClC,IAAA,EAAK,IAAA;AAAA,sBACL,OAAA,EAAS,eAAA;AAAA,sBACT,QAAA,EAAU,YAAY,CAAC,eAAA;AAAA,sBACvB,SAAA,EAAW,EAAA,CAAG,gBAAA,EAAkB,WAAA,IAAe,eAAe,CAAA;AAAA,sBAC9D,KAAA,EACE,CAAC,eAAA,GACG,kDAAA,GACA,cACE,gBAAA,GACA,iBAAA;AAAA,sBAGP,QAAA,EAAA;AAAA,wBAAA,WAAA,mBACC,GAAA,CAAC,UAAO,SAAA,EAAU,SAAA,EAAU,oBAE5B,GAAA,CAAC,GAAA,EAAA,EAAI,WAAU,SAAA,EAAU,CAAA;AAAA,4CAE1B,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EACb,QAAA,EAAA,WAAA,GAAc,SAAS,SAAA,EAC1B;AAAA;AAAA;AAAA;AACF,iBAAA,EACF;AAAA;AAAA;AAAA,WAEJ;AAAA,0BAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iBAAA,EACZ,QAAA,EAAA;AAAA,YAAA,OAAA,IAAW,WAAA,oBACV,GAAA;AAAA,cAAC,KAAA;AAAA,cAAA;AAAA,gBACC,aAAA,EAAY,MAAA;AAAA,gBACZ,SAAA,EAAU,qEAAA;AAAA,gBAET,QAAA,EAAA;AAAA;AAAA,aACH;AAAA,4BAEF,GAAA;AAAA,cAAC,KAAA;AAAA,cAAA;AAAA,gBACC,GAAA,EAAK,SAAA;AAAA,gBACL,IAAA,EAAK,SAAA;AAAA,gBACL,gBAAA,EAAe,MAAA;AAAA,gBACf,cAAY,SAAA,IAAa,WAAA;AAAA,gBACzB,iBAAiB,CAAC,QAAA;AAAA,gBAClB,OAAA,EAAS,aAAA;AAAA,gBACT,SAAA,EAAW,EAAA;AAAA,kBACT,sDAAA;AAAA,kBACA,2BAAA;AAAA,kBACA,QAAA,IAAY;AAAA,iBACd;AAAA,gBACA,8BAAA,EAA8B;AAAA;AAAA;AAChC,WAAA,EACF;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;AAEA,cAAA,CAAe,WAAA,GAAc,gBAAA","file":"chunk-AEGYWRSL.js","sourcesContent":["/**\n * Converts spoken punctuation words (e.g. \"period\", \"comma\") into the\n * corresponding characters, using lightweight context heuristics so that words\n * like \"time period\" or \"the colon\" are left intact. Pure and side-effect free\n * so it can be unit tested independently of the editor.\n */\nexport function processDictation(text: string): string {\n let result = text;\n\n // \"period\" as a word vs. as punctuation.\n result = result.replace(\n /\\b(the|a|this|that|each|every|same|time|grace|trial|waiting|probationary|pay|billing|accounting)\\s+period\\b/gi,\n '$1 period'\n );\n result = result.replace(\n /\\bperiod\\s+(of|in|for|from|to|during|between|after|before|when|where|is|was|will|has|had)\\b/gi,\n 'period $1'\n );\n result = result.replace(/\\s+period(\\s*$)/gi, '.$1');\n result = result.replace(/\\s+period\\s+(?=[A-Z])/g, '. ');\n\n // \"comma\"\n result = result.replace(/\\bcomma\\s+(separated|delimited)/gi, 'comma $1');\n result = result.replace(/\\s+comma\\b/gi, ',');\n\n // \"colon\"\n result = result.replace(\n /\\b(the|a|my|your|his|her|their|semicolon|ascending|descending|transverse|sigmoid)\\s+colon\\b/gi,\n '$1 colon'\n );\n result = result.replace(\n /\\bcolon\\s+(cancer|surgery|health|polyp|scope|oscopy)/gi,\n 'colon $1'\n );\n result = result.replace(/\\s+colon\\b/gi, ':');\n\n // \"dash\"\n result = result.replace(\n /\\b(yard|meter|hundred|mad|quick|wild)\\s+dash\\b/gi,\n '$1 dash'\n );\n result = result.replace(/\\bdash\\s+(to|for|of)\\b/gi, 'dash $1');\n result = result.replace(/\\s+dash\\b/gi, ' -');\n\n const simplePunctuation: Record<string, string> = {\n ' full stop': '.',\n ' question mark': '?',\n ' exclamation point': '!',\n ' exclamation mark': '!',\n ' semicolon': ';',\n ' semi colon': ';',\n ' hyphen': '-',\n ' open parenthesis': ' (',\n ' close parenthesis': ')',\n ' open bracket': ' [',\n ' close bracket': ']',\n ' open quote': ' \"',\n ' close quote': '\"',\n ' quote': '\"',\n ' apostrophe': \"'\",\n ' new line': '\\n',\n ' newline': '\\n',\n ' new paragraph': '\\n\\n',\n ' tab': '\\t',\n };\n\n for (const [spoken, punctuation] of Object.entries(simplePunctuation)) {\n const regex = new RegExp(spoken, 'gi');\n result = result.replace(regex, punctuation);\n }\n\n // Capitalize after sentence-ending punctuation.\n result = result.replace(\n /([.!?])\\s+([a-z])/g,\n (_match, punct: string, letter: string) =>\n `${punct} ${letter.toUpperCase()}`\n );\n\n return result;\n}\n\n/**\n * Converts `<<field>>` (and the HTML-encoded `<<field>>`) syntax\n * into mustache `{{field}}` syntax. Pure helper operating on an HTML string.\n */\nexport function convertAngleBracketsToMustache(html: string): string {\n return html\n .replace(\n /<<([^&]*)>>/g,\n (_m, field: string) => `{{${field.trim()}}}`\n )\n .replace(/<<([^>]*)>>/g, (_m, field: string) => `{{${field.trim()}}}`);\n}\n\n/**\n * Returns true when an HTML string has no visible text content.\n * Note: This is a visibility check, not a sanitizer. It strips tags to inspect\n * remaining text — do NOT use this for XSS prevention.\n */\nexport { isHtmlEmpty } from '../../utils/html';\n","import * as React from 'react';\nimport {\n Bold,\n Italic,\n Underline,\n List,\n ListOrdered,\n AlignLeft,\n AlignCenter,\n AlignRight,\n Braces,\n Replace,\n Mic,\n MicOff,\n} from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { Button } from '../Button';\nimport { Separator } from '../Separator';\nimport {\n Dropdown,\n DropdownItem,\n DropdownLabel,\n DropdownSeparator,\n} from '../Dropdown';\nimport {\n processDictation,\n convertAngleBracketsToMustache,\n isHtmlEmpty,\n} from './processDictation';\n\nexport interface RichTextVariable {\n /** Human-readable label shown in the variable menu. */\n label: string;\n /** The token displayed for the variable (e.g. `{{employee.name}}`). */\n value: string;\n /** Optional text inserted instead of `value` (e.g. an expanded group). */\n insertValue?: string;\n}\n\nexport interface RichTextVariableGroup {\n /** Group heading shown in the variable menu. */\n label: string;\n /** Variables belonging to the group. */\n variables: RichTextVariable[];\n}\n\nexport interface RichTextEditorProps {\n /** Current HTML value of the editor. */\n value: string;\n /** Called with the updated HTML whenever the content changes. */\n onChange: (value: string) => void;\n /** Placeholder shown when the editor is empty. */\n placeholder?: string;\n /** Additional class for the editor wrapper. */\n className?: string;\n /**\n * Variable groups for the \"Insert variable\" menu. When omitted the variable\n * menu and the `<< >>` → `{{ }}` convert button are hidden.\n */\n variableGroups?: RichTextVariableGroup[];\n /** Enable the speech-to-text dictation button. Defaults to true. */\n enableDictation?: boolean;\n /** Called when dictation cannot start (replaces native alerts). */\n onDictationError?: (message: string) => void;\n /** Disable editing and toolbar actions. */\n disabled?: boolean;\n /** Accessible label for the editable region. */\n 'aria-label'?: string;\n}\n\n// --- Minimal Web Speech API typings (absent from the standard DOM lib) ---\ninterface SpeechRecognitionAlternativeLike {\n transcript: string;\n}\ninterface SpeechRecognitionResultLike {\n isFinal: boolean;\n [index: number]: SpeechRecognitionAlternativeLike;\n}\ninterface SpeechRecognitionResultListLike {\n length: number;\n [index: number]: SpeechRecognitionResultLike;\n}\ninterface SpeechRecognitionEventLike {\n resultIndex: number;\n results: SpeechRecognitionResultListLike;\n}\ninterface SpeechRecognitionErrorEventLike {\n error: string;\n}\ninterface SpeechRecognitionLike {\n continuous: boolean;\n interimResults: boolean;\n lang: string;\n maxAlternatives: number;\n onstart: (() => void) | null;\n onresult: ((event: SpeechRecognitionEventLike) => void) | null;\n onerror: ((event: SpeechRecognitionErrorEventLike) => void) | null;\n onend: (() => void) | null;\n start: () => void;\n stop: () => void;\n}\ntype SpeechRecognitionCtor = new () => SpeechRecognitionLike;\ninterface SpeechWindow {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n}\n\nfunction getSpeechRecognition(): SpeechRecognitionCtor | undefined {\n const w = window as unknown as SpeechWindow;\n return w.SpeechRecognition || w.webkitSpeechRecognition;\n}\n\n/**\n * A presentational rich-text editor with formatting, template-variable\n * insertion and optional speech-to-text dictation. Content is supplied and\n * surfaced via `value`/`onChange` so it can be wired to any store. The variable\n * menu is data-agnostic — pass `variableGroups` to populate it.\n */\nconst RichTextEditor = React.forwardRef<HTMLDivElement, RichTextEditorProps>(\n (\n {\n value,\n onChange,\n placeholder,\n className,\n variableGroups,\n enableDictation = true,\n onDictationError,\n disabled = false,\n 'aria-label': ariaLabel,\n },\n ref\n ) => {\n const editorRef = React.useRef<HTMLDivElement>(null);\n const [isListening, setIsListening] = React.useState(false);\n const [speechSupported, setSpeechSupported] = React.useState(false);\n const recognitionRef = React.useRef<SpeechRecognitionLike | null>(null);\n const isListeningRef = React.useRef(false);\n const shouldRestartRef = React.useRef(false);\n\n const hasVariables = Boolean(variableGroups && variableGroups.length > 0);\n const isEmpty = isHtmlEmpty(value);\n\n React.useImperativeHandle(ref, () => editorRef.current as HTMLDivElement);\n\n React.useEffect(() => {\n setSpeechSupported(Boolean(getSpeechRecognition()));\n }, []);\n\n React.useEffect(() => {\n return () => {\n if (recognitionRef.current) {\n shouldRestartRef.current = false;\n isListeningRef.current = false;\n recognitionRef.current.stop();\n }\n };\n }, []);\n\n React.useEffect(() => {\n if (editorRef.current && editorRef.current.innerHTML !== value) {\n editorRef.current.innerHTML = value;\n }\n }, [value]);\n\n const updateContent = () => {\n if (editorRef.current) onChange(editorRef.current.innerHTML);\n };\n\n const execCommand = (command: string) => {\n if (disabled) return;\n document.execCommand(command, false);\n editorRef.current?.focus();\n updateContent();\n };\n\n const handleConvertToMustache = () => {\n if (disabled || !editorRef.current) return;\n editorRef.current.innerHTML = convertAngleBracketsToMustache(\n editorRef.current.innerHTML\n );\n updateContent();\n };\n\n const insertVariable = (variable: RichTextVariable) => {\n if (disabled || !editorRef.current) return;\n editorRef.current.focus();\n const textToInsert = variable.insertValue ?? variable.value;\n\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0) {\n const range = selection.getRangeAt(0);\n range.deleteContents();\n if (textToInsert.includes('\\n')) {\n const fragment = document.createDocumentFragment();\n const lines = textToInsert.split('\\n');\n lines.forEach((line, index) => {\n fragment.appendChild(document.createTextNode(line));\n if (index < lines.length - 1) {\n fragment.appendChild(document.createElement('br'));\n }\n });\n range.insertNode(fragment);\n range.collapse(false);\n } else {\n const textNode = document.createTextNode(textToInsert);\n range.insertNode(textNode);\n range.setStartAfter(textNode);\n range.setEndAfter(textNode);\n }\n selection.removeAllRanges();\n selection.addRange(range);\n } else {\n editorRef.current.innerHTML += textToInsert.replace(/\\n/g, '<br>');\n }\n updateContent();\n };\n\n const reportError = (message: string) => {\n if (onDictationError) onDictationError(message);\n else if (typeof console !== 'undefined') console.warn(message);\n };\n\n const toggleDictation = async () => {\n const SpeechRecognition = getSpeechRecognition();\n if (!SpeechRecognition) return;\n\n if (isListening && recognitionRef.current) {\n shouldRestartRef.current = false;\n isListeningRef.current = false;\n recognitionRef.current.stop();\n setIsListening(false);\n return;\n }\n\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n });\n stream.getTracks().forEach((track) => track.stop());\n } catch {\n reportError(\n 'Microphone access is required for dictation. Please allow microphone access in your browser settings and try again.'\n );\n return;\n }\n\n const recognition = new SpeechRecognition();\n recognition.continuous = true;\n recognition.interimResults = true;\n recognition.lang = 'en-US';\n recognition.maxAlternatives = 1;\n\n recognition.onstart = () => {\n setIsListening(true);\n isListeningRef.current = true;\n shouldRestartRef.current = true;\n };\n\n recognition.onresult = (event) => {\n let finalTranscript = '';\n for (let i = event.resultIndex; i < event.results.length; i++) {\n const result = event.results[i];\n if (result.isFinal) finalTranscript += result[0].transcript;\n }\n\n if (finalTranscript && editorRef.current) {\n const processedText = processDictation(finalTranscript);\n editorRef.current.focus();\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0) {\n const range = selection.getRangeAt(0);\n range.deleteContents();\n const textNode = document.createTextNode(processedText + ' ');\n range.insertNode(textNode);\n range.setStartAfter(textNode);\n range.setEndAfter(textNode);\n selection.removeAllRanges();\n selection.addRange(range);\n } else {\n editorRef.current.innerHTML += processedText + ' ';\n }\n updateContent();\n }\n };\n\n recognition.onerror = (event) => {\n if (event.error === 'no-speech' || event.error === 'aborted') return;\n if (event.error === 'not-allowed') {\n reportError(\n 'Microphone access was denied. Please allow microphone access in your browser settings and try again.'\n );\n shouldRestartRef.current = false;\n isListeningRef.current = false;\n setIsListening(false);\n return;\n }\n if (event.error === 'network') return;\n shouldRestartRef.current = false;\n isListeningRef.current = false;\n setIsListening(false);\n };\n\n recognition.onend = () => {\n if (shouldRestartRef.current && isListeningRef.current) {\n setTimeout(() => {\n if (shouldRestartRef.current && isListeningRef.current) {\n try {\n recognition.start();\n } catch {\n shouldRestartRef.current = false;\n isListeningRef.current = false;\n setIsListening(false);\n }\n }\n }, 100);\n } else {\n setIsListening(false);\n }\n };\n\n recognitionRef.current = recognition;\n try {\n recognition.start();\n } catch {\n reportError('Failed to start speech recognition. Please try again.');\n }\n };\n\n const iconButtonClass = 'h-8 w-8 p-0';\n\n return (\n <div\n data-slot=\"rich-text-editor\"\n className={cn(\n 'border-border bg-background flex flex-col overflow-hidden rounded-lg border',\n className\n )}\n >\n <div\n data-slot=\"rich-text-editor-toolbar\"\n className=\"border-border bg-muted/30 sticky top-0 z-10 flex flex-wrap items-center gap-1 border-b p-2\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('bold')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Bold\"\n title=\"Bold\"\n >\n <Bold className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('italic')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Italic\"\n title=\"Italic\"\n >\n <Italic className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('underline')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Underline\"\n title=\"Underline\"\n >\n <Underline className=\"h-4 w-4\" />\n </Button>\n\n <Separator orientation=\"vertical\" className=\"mx-1 h-6\" />\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('insertUnorderedList')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Bullet list\"\n title=\"Bullet list\"\n >\n <List className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('insertOrderedList')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Numbered list\"\n title=\"Numbered list\"\n >\n <ListOrdered className=\"h-4 w-4\" />\n </Button>\n\n <Separator orientation=\"vertical\" className=\"mx-1 h-6\" />\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('justifyLeft')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Align left\"\n title=\"Align left\"\n >\n <AlignLeft className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('justifyCenter')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Align center\"\n title=\"Align center\"\n >\n <AlignCenter className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => execCommand('justifyRight')}\n disabled={disabled}\n className={iconButtonClass}\n aria-label=\"Align right\"\n title=\"Align right\"\n >\n <AlignRight className=\"h-4 w-4\" />\n </Button>\n\n {hasVariables && (\n <>\n <Separator orientation=\"vertical\" className=\"mx-1 h-6\" />\n <Dropdown\n placement=\"bottom-start\"\n width={240}\n searchable\n searchPlaceholder=\"Search variables…\"\n searchAriaLabel=\"Search template variables\"\n disabled={disabled}\n trigger={\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 gap-1 px-2\"\n disabled={disabled}\n title=\"Insert variable\"\n >\n <Braces className=\"h-4 w-4\" />\n <span className=\"text-xs\">Variables</span>\n </Button>\n }\n >\n {variableGroups!.map((group, groupIndex) => (\n <React.Fragment key={group.label}>\n {groupIndex > 0 && <DropdownSeparator />}\n <DropdownLabel>{group.label}</DropdownLabel>\n {group.variables.map((variable) => (\n <DropdownItem\n key={variable.value}\n onClick={() => insertVariable(variable)}\n >\n {variable.label}\n </DropdownItem>\n ))}\n </React.Fragment>\n ))}\n </Dropdown>\n\n <Separator orientation=\"vertical\" className=\"mx-1 h-6\" />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleConvertToMustache}\n disabled={disabled}\n className=\"h-8 gap-1 px-2\"\n title=\"Convert <<field>> to {{field}}\"\n >\n <Replace className=\"h-4 w-4\" />\n <span className=\"text-xs\">{'<< >> to {{ }}'}</span>\n </Button>\n </>\n )}\n\n {enableDictation && (\n <>\n <Separator orientation=\"vertical\" className=\"mx-1 h-6\" />\n <Button\n type=\"button\"\n variant={isListening ? 'danger' : 'ghost'}\n size=\"sm\"\n onClick={toggleDictation}\n disabled={disabled || !speechSupported}\n className={cn('h-8 gap-1 px-2', isListening && 'animate-pulse')}\n title={\n !speechSupported\n ? 'Speech recognition not supported in this browser'\n : isListening\n ? 'Stop dictation'\n : 'Start dictation'\n }\n >\n {isListening ? (\n <MicOff className=\"h-4 w-4\" />\n ) : (\n <Mic className=\"h-4 w-4\" />\n )}\n <span className=\"text-xs\">\n {isListening ? 'Stop' : 'Dictate'}\n </span>\n </Button>\n </>\n )}\n </div>\n\n <div className=\"relative flex-1\">\n {isEmpty && placeholder && (\n <div\n aria-hidden=\"true\"\n className=\"text-muted-foreground pointer-events-none absolute top-0 left-0 p-4\"\n >\n {placeholder}\n </div>\n )}\n <div\n ref={editorRef}\n role=\"textbox\"\n aria-multiline=\"true\"\n aria-label={ariaLabel ?? placeholder}\n contentEditable={!disabled}\n onInput={updateContent}\n className={cn(\n 'min-h-[250px] overflow-y-auto p-4 focus:outline-none',\n 'prose prose-sm max-w-none',\n disabled && 'cursor-not-allowed opacity-50'\n )}\n suppressContentEditableWarning\n />\n </div>\n </div>\n );\n }\n);\n\nRichTextEditor.displayName = 'RichTextEditor';\n\nexport { RichTextEditor };\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkOR5DRJCW_cjs = require('./chunk-OR5DRJCW.cjs');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
27
|
+
|
|
28
|
+
var scrollAreaVariants = classVarianceAuthority.cva(
|
|
29
|
+
[
|
|
30
|
+
"relative overflow-auto",
|
|
31
|
+
// Thin, theme-aware scrollbars
|
|
32
|
+
"[scrollbar-width:thin]",
|
|
33
|
+
"[scrollbar-color:hsl(var(--border))_transparent]",
|
|
34
|
+
"[&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar]:h-2",
|
|
35
|
+
"[&::-webkit-scrollbar-track]:bg-transparent",
|
|
36
|
+
"[&::-webkit-scrollbar-thumb]:rounded-full",
|
|
37
|
+
"[&::-webkit-scrollbar-thumb]:bg-border",
|
|
38
|
+
"hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/40"
|
|
39
|
+
],
|
|
40
|
+
{
|
|
41
|
+
variants: {
|
|
42
|
+
orientation: {
|
|
43
|
+
vertical: "overflow-x-hidden overflow-y-auto",
|
|
44
|
+
horizontal: "overflow-x-auto overflow-y-hidden",
|
|
45
|
+
both: "overflow-auto"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
defaultVariants: {
|
|
49
|
+
orientation: "vertical"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
var ScrollArea = React__namespace.forwardRef(
|
|
54
|
+
({ className, orientation, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
55
|
+
"div",
|
|
56
|
+
{
|
|
57
|
+
ref,
|
|
58
|
+
"data-slot": "scroll-area",
|
|
59
|
+
role: "region",
|
|
60
|
+
tabIndex: 0,
|
|
61
|
+
className: chunkOR5DRJCW_cjs.cn(scrollAreaVariants({ orientation }), className),
|
|
62
|
+
...props,
|
|
63
|
+
children
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
ScrollArea.displayName = "ScrollArea";
|
|
68
|
+
|
|
69
|
+
exports.ScrollArea = ScrollArea;
|
|
70
|
+
exports.scrollAreaVariants = scrollAreaVariants;
|
|
71
|
+
//# sourceMappingURL=chunk-AFKKJEV5.cjs.map
|
|
72
|
+
//# sourceMappingURL=chunk-AFKKJEV5.cjs.map
|