eddyter 1.3.36 → 1.3.38

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.
@@ -4,10 +4,12 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { jsx, Fragment, jsxs } from "react/jsx-runtime";
7
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
8
8
  import * as React$1 from "react";
9
- import React__default, { createContext, useContext, useState as useState$1, useRef, useCallback, useEffect as useEffect$1, Suspense, forwardRef, createElement, useImperativeHandle, useMemo, useLayoutEffect as useLayoutEffect$1, Component } from "react";
9
+ import React__default, { createContext, useContext, useState as useState$1, useRef, useEffect as useEffect$1, useCallback, Suspense, forwardRef, createElement, useImperativeHandle, useMemo, useLayoutEffect as useLayoutEffect$1, Component } from "react";
10
10
  import axios from "axios";
11
+ import * as ReactDOM from "react-dom";
12
+ import ReactDOM__default, { createPortal } from "react-dom";
11
13
  import styled from "@emotion/styled";
12
14
  import { $generateNodesFromDOM, $generateHtmlFromNodes } from "@lexical/html";
13
15
  import { CheckListPlugin } from "@lexical/react/LexicalCheckListPlugin";
@@ -23,9 +25,7 @@ import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
23
25
  import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
24
26
  import { TableNode, TableCellNode, TableRowNode, $createTableNodeWithDimensions, $isTableRowNode, $isTableCellNode, TableCellHeaderStates, $isTableNode, $isTableSelection, $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, getTableElement, getTableObserverFromTableElement, $getTableRowIndexFromTableCellNode, $getNodeTriplet, $insertTableRow__EXPERIMENTAL, $getTableColumnIndexFromTableCellNode, $insertTableColumn__EXPERIMENTAL, $deleteTableRow__EXPERIMENTAL, $deleteTableColumn__EXPERIMENTAL, $unmergeCell, $computeTableMapSkipCellCheck, getDOMCellFromTarget, $getTableAndElementByKey } from "@lexical/table";
25
27
  import { mergeRegister, $wrapNodeInElement, $findMatchingParent, $getNearestNodeOfType, $getNearestBlockElementAncestorOrThrow, $insertNodeToNearestRoot, $isEditorIsNestedEditor, mediaFileReader, isMimeType, calculateZoomLevel, CAN_USE_DOM } from "@lexical/utils";
26
- import { createCommand, DecoratorNode, createEditor, $applyNodeReplacement, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $getNearestNodeFromDOMNode, isHTMLElement as isHTMLElement$1, TextNode, $getRoot, $createTextNode, $getNodeByKey, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, KEY_DOWN_COMMAND, COMMAND_PRIORITY_CRITICAL, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_SPACE_COMMAND, $isLineBreakNode, $createRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, PASTE_COMMAND, getDOMSelection, CLICK_COMMAND, KEY_BACKSPACE_COMMAND, ParagraphNode, $createLineBreakNode, isDOMNode } from "lexical";
27
- import * as ReactDOM from "react-dom";
28
- import ReactDOM__default, { createPortal } from "react-dom";
28
+ import { createCommand, DecoratorNode, createEditor, $applyNodeReplacement, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $getNearestNodeFromDOMNode, isHTMLElement as isHTMLElement$1, TextNode, $getRoot, $createTextNode, $getNodeByKey, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, KEY_DOWN_COMMAND, COMMAND_PRIORITY_CRITICAL, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_SPACE_COMMAND, $isLineBreakNode, $createRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, PASTE_COMMAND, CLICK_COMMAND, getDOMSelection, KEY_BACKSPACE_COMMAND, ParagraphNode, $createLineBreakNode, isDOMNode } from "lexical";
29
29
  import { $isCodeNode, CodeNode, normalizeCodeLang, getLanguageFriendlyName, CodeHighlightNode, CODE_LANGUAGE_MAP, $createCodeNode, registerCodeHighlighting, $isCodeHighlightNode } from "@lexical/code";
30
30
  import { LinkNode, $isLinkNode, TOGGLE_LINK_COMMAND, $isAutoLinkNode, $createLinkNode } from "@lexical/link";
31
31
  import { ListNode, ListItemNode, $isListNode, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, $isListItemNode, $createListNode, $createListItemNode } from "@lexical/list";
@@ -104,6 +104,566 @@ const verifyApiKey = async (apiKey) => {
104
104
  throw new Error("Failed to verify API key");
105
105
  }
106
106
  };
107
+ const backendInstance = axios.create({
108
+ baseURL: "https://api.cteditor.com/",
109
+ headers: {
110
+ "Content-Type": "application/json"
111
+ }
112
+ });
113
+ const backendAPI = backendInstance;
114
+ const apiEndpoints = {
115
+ // School management endpoints
116
+ chat: {
117
+ stream: "/api/chat/stream",
118
+ json: "/api/chat/json",
119
+ textEnhance: "/api/chat/text-enhance",
120
+ textTransform: "/api/chat/text-transform",
121
+ imageCreation: "/api/chat/image-creation",
122
+ editorAction: "/api/chat/chat-action",
123
+ credits: "/api/chat/credits",
124
+ userInfo: "/api/chat/user-info"
125
+ },
126
+ project: {
127
+ fileUpload: "/api/files/upload"
128
+ },
129
+ transcript: {
130
+ voiceTranscript: "/api/transcript/get-assemblyai-token",
131
+ endSession: "/api/transcript/end-session"
132
+ },
133
+ linkPreview: {
134
+ getPreview: "/api/link-preview"
135
+ }
136
+ };
137
+ const cache = /* @__PURE__ */ new Map();
138
+ const CACHE_TTL = 30 * 60 * 1e3;
139
+ const MAX_CACHE_SIZE$1 = 100;
140
+ function getCached(url) {
141
+ const entry = cache.get(url);
142
+ if (!entry)
143
+ return null;
144
+ if (Date.now() - entry.timestamp > CACHE_TTL) {
145
+ cache.delete(url);
146
+ return null;
147
+ }
148
+ return entry.data;
149
+ }
150
+ function setCache(url, data) {
151
+ if (cache.size >= MAX_CACHE_SIZE$1) {
152
+ const oldestKey = cache.keys().next().value;
153
+ if (oldestKey)
154
+ cache.delete(oldestKey);
155
+ }
156
+ cache.set(url, { data, timestamp: Date.now() });
157
+ }
158
+ async function fetchLinkPreview({
159
+ url,
160
+ apiKey
161
+ }) {
162
+ const cached = getCached(url);
163
+ if (cached)
164
+ return cached;
165
+ try {
166
+ const response = await backendAPI.post(
167
+ apiEndpoints.linkPreview.getPreview,
168
+ { url },
169
+ apiKey ? { headers: { "X-API-Key": apiKey } } : void 0
170
+ );
171
+ if (response.data.success && response.data.data) {
172
+ setCache(url, response.data.data);
173
+ return response.data.data;
174
+ }
175
+ return null;
176
+ } catch (error) {
177
+ console.error("Error fetching link preview:", error);
178
+ return null;
179
+ }
180
+ }
181
+ function LinkPreviewHover({
182
+ containerRef,
183
+ children,
184
+ apiKey,
185
+ showDelay = 500,
186
+ hideDelay = 300,
187
+ enabled = true
188
+ }) {
189
+ const internalRef = useRef(null);
190
+ const [hoveredLink, setHoveredLink] = useState$1(null);
191
+ const effectiveRef = containerRef || internalRef;
192
+ useEffect$1(() => {
193
+ if (!enabled)
194
+ return;
195
+ const container = effectiveRef.current;
196
+ if (!container)
197
+ return;
198
+ let showTimeout = null;
199
+ let hideTimeout = null;
200
+ let isOverPreview = false;
201
+ const handleMouseOver = (event) => {
202
+ const target = event.target;
203
+ if (target.closest(".link-preview-card")) {
204
+ isOverPreview = true;
205
+ if (hideTimeout) {
206
+ clearTimeout(hideTimeout);
207
+ hideTimeout = null;
208
+ }
209
+ return;
210
+ }
211
+ const linkElement = target.closest("a");
212
+ if (linkElement && container.contains(linkElement)) {
213
+ const href = linkElement.getAttribute("href");
214
+ if (href && href !== "https://" && href !== "http://" && href !== "#" && !href.startsWith("javascript:")) {
215
+ if (showTimeout)
216
+ clearTimeout(showTimeout);
217
+ if (hideTimeout) {
218
+ clearTimeout(hideTimeout);
219
+ hideTimeout = null;
220
+ }
221
+ showTimeout = window.setTimeout(() => {
222
+ setHoveredLink({ url: href, rect: linkElement.getBoundingClientRect() });
223
+ }, showDelay);
224
+ }
225
+ }
226
+ };
227
+ const handleMouseOut = (event) => {
228
+ const target = event.target;
229
+ const relatedTarget = event.relatedTarget;
230
+ if (target.closest(".link-preview-card")) {
231
+ isOverPreview = false;
232
+ if (!(relatedTarget == null ? void 0 : relatedTarget.closest("a"))) {
233
+ hideTimeout = window.setTimeout(() => {
234
+ if (!isOverPreview)
235
+ setHoveredLink(null);
236
+ }, hideDelay);
237
+ }
238
+ return;
239
+ }
240
+ const linkElement = target.closest("a");
241
+ if (linkElement && container.contains(linkElement)) {
242
+ if (showTimeout) {
243
+ clearTimeout(showTimeout);
244
+ showTimeout = null;
245
+ }
246
+ if (!(relatedTarget == null ? void 0 : relatedTarget.closest(".link-preview-card"))) {
247
+ hideTimeout = window.setTimeout(() => {
248
+ if (!isOverPreview)
249
+ setHoveredLink(null);
250
+ }, hideDelay);
251
+ }
252
+ }
253
+ };
254
+ const handlePreviewMouseOver = (event) => {
255
+ if (event.target.closest(".link-preview-card")) {
256
+ isOverPreview = true;
257
+ if (hideTimeout) {
258
+ clearTimeout(hideTimeout);
259
+ hideTimeout = null;
260
+ }
261
+ }
262
+ };
263
+ const handlePreviewMouseOut = (event) => {
264
+ const target = event.target;
265
+ const relatedTarget = event.relatedTarget;
266
+ if (target.closest(".link-preview-card")) {
267
+ isOverPreview = false;
268
+ if (!(relatedTarget == null ? void 0 : relatedTarget.closest("a")) || !container.contains(relatedTarget)) {
269
+ hideTimeout = window.setTimeout(() => {
270
+ if (!isOverPreview)
271
+ setHoveredLink(null);
272
+ }, hideDelay);
273
+ }
274
+ }
275
+ };
276
+ container.addEventListener("mouseover", handleMouseOver);
277
+ container.addEventListener("mouseout", handleMouseOut);
278
+ document.body.addEventListener("mouseover", handlePreviewMouseOver);
279
+ document.body.addEventListener("mouseout", handlePreviewMouseOut);
280
+ return () => {
281
+ if (showTimeout)
282
+ clearTimeout(showTimeout);
283
+ if (hideTimeout)
284
+ clearTimeout(hideTimeout);
285
+ container.removeEventListener("mouseover", handleMouseOver);
286
+ container.removeEventListener("mouseout", handleMouseOut);
287
+ document.body.removeEventListener("mouseover", handlePreviewMouseOver);
288
+ document.body.removeEventListener("mouseout", handlePreviewMouseOut);
289
+ };
290
+ }, [effectiveRef, showDelay, hideDelay, enabled]);
291
+ if (children) {
292
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
293
+ /* @__PURE__ */ jsx("div", { ref: internalRef, children }),
294
+ hoveredLink && createPortal(
295
+ /* @__PURE__ */ jsx(
296
+ LinkPreviewCard,
297
+ {
298
+ url: hoveredLink.url,
299
+ rect: hoveredLink.rect,
300
+ apiKey,
301
+ onClose: () => setHoveredLink(null)
302
+ }
303
+ ),
304
+ document.body
305
+ )
306
+ ] });
307
+ }
308
+ return /* @__PURE__ */ jsx(Fragment, { children: hoveredLink && createPortal(
309
+ /* @__PURE__ */ jsx(
310
+ LinkPreviewCard,
311
+ {
312
+ url: hoveredLink.url,
313
+ rect: hoveredLink.rect,
314
+ apiKey,
315
+ onClose: () => setHoveredLink(null)
316
+ }
317
+ ),
318
+ document.body
319
+ ) });
320
+ }
321
+ const PREVIEW_WIDTH$1 = 320;
322
+ function LinkPreviewCard({ url, rect, apiKey, onClose }) {
323
+ const [position, setPosition] = useState$1({ top: 0, left: 0 });
324
+ const [previewData, setPreviewData] = useState$1(null);
325
+ const [isLoading, setIsLoading] = useState$1(true);
326
+ const [hasError, setHasError] = useState$1(false);
327
+ const fetchedRef = useRef(false);
328
+ useEffect$1(() => {
329
+ if (fetchedRef.current)
330
+ return;
331
+ fetchedRef.current = true;
332
+ setIsLoading(true);
333
+ setHasError(false);
334
+ fetchLinkPreview({ url, apiKey }).then((data) => {
335
+ if (data)
336
+ setPreviewData(data);
337
+ else
338
+ setHasError(true);
339
+ }).catch(() => setHasError(true)).finally(() => setIsLoading(false));
340
+ }, [url, apiKey]);
341
+ useEffect$1(() => {
342
+ const previewHeight = (previewData == null ? void 0 : previewData.image) ? 280 : 160;
343
+ let top = rect.top + window.scrollY - previewHeight - 10;
344
+ if (rect.top - previewHeight - 10 < 0) {
345
+ top = rect.bottom + window.scrollY + 10;
346
+ }
347
+ let left = rect.left + window.scrollX + rect.width / 2 - PREVIEW_WIDTH$1 / 2;
348
+ const viewportWidth = window.innerWidth;
349
+ if (left < 10)
350
+ left = 10;
351
+ else if (left + PREVIEW_WIDTH$1 > viewportWidth - 10)
352
+ left = viewportWidth - PREVIEW_WIDTH$1 - 10;
353
+ setPosition({ top, left });
354
+ }, [rect, previewData]);
355
+ const getDomain = useCallback((urlString) => {
356
+ try {
357
+ return new URL(urlString).hostname.replace("www.", "");
358
+ } catch {
359
+ return urlString;
360
+ }
361
+ }, []);
362
+ const domain = getDomain(url);
363
+ const cardStyle = {
364
+ position: "absolute",
365
+ top: `${position.top}px`,
366
+ left: `${position.left}px`,
367
+ zIndex: 1e4,
368
+ pointerEvents: "auto",
369
+ animation: "linkPreviewFadeIn 0.2s ease-out"
370
+ };
371
+ const containerStyle = {
372
+ width: `${PREVIEW_WIDTH$1}px`,
373
+ backgroundColor: "#1e1e1e",
374
+ borderRadius: "12px",
375
+ boxShadow: "0 10px 40px rgba(0, 0, 0, 0.4)",
376
+ overflow: "hidden",
377
+ position: "relative",
378
+ border: "1px solid #333"
379
+ };
380
+ const closeButtonStyle = {
381
+ position: "absolute",
382
+ top: "8px",
383
+ right: "8px",
384
+ width: "24px",
385
+ height: "24px",
386
+ borderRadius: "6px",
387
+ backgroundColor: "rgba(0,0,0,0.5)",
388
+ border: "none",
389
+ cursor: "pointer",
390
+ display: "flex",
391
+ alignItems: "center",
392
+ justifyContent: "center",
393
+ zIndex: 10
394
+ };
395
+ return /* @__PURE__ */ jsxs("div", { className: "link-preview-card", style: cardStyle, children: [
396
+ /* @__PURE__ */ jsxs("div", { style: containerStyle, children: [
397
+ /* @__PURE__ */ jsx(
398
+ "button",
399
+ {
400
+ onClick: (e) => {
401
+ e.preventDefault();
402
+ e.stopPropagation();
403
+ onClose();
404
+ },
405
+ style: closeButtonStyle,
406
+ onMouseEnter: (e) => {
407
+ e.currentTarget.style.backgroundColor = "rgba(0,0,0,0.7)";
408
+ },
409
+ onMouseLeave: (e) => {
410
+ e.currentTarget.style.backgroundColor = "rgba(0,0,0,0.5)";
411
+ },
412
+ title: "Close preview",
413
+ children: /* @__PURE__ */ jsx(
414
+ "svg",
415
+ {
416
+ style: { width: "14px", height: "14px", color: "#fff" },
417
+ fill: "none",
418
+ stroke: "currentColor",
419
+ viewBox: "0 0 24 24",
420
+ children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })
421
+ }
422
+ )
423
+ }
424
+ ),
425
+ isLoading && /* @__PURE__ */ jsxs("div", { style: { padding: "40px", textAlign: "center" }, children: [
426
+ /* @__PURE__ */ jsx(
427
+ "div",
428
+ {
429
+ style: {
430
+ width: "24px",
431
+ height: "24px",
432
+ border: "2px solid #444",
433
+ borderTopColor: "#fff",
434
+ borderRadius: "50%",
435
+ animation: "linkPreviewSpin 1s linear infinite",
436
+ margin: "0 auto 12px"
437
+ }
438
+ }
439
+ ),
440
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "#888" }, children: "Loading preview..." })
441
+ ] }),
442
+ !isLoading && hasError && /* @__PURE__ */ jsxs("div", { style: { padding: "16px" }, children: [
443
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "12px" }, children: [
444
+ /* @__PURE__ */ jsx(
445
+ "svg",
446
+ {
447
+ style: { width: "16px", height: "16px", color: "#fff" },
448
+ fill: "none",
449
+ stroke: "currentColor",
450
+ viewBox: "0 0 24 24",
451
+ children: /* @__PURE__ */ jsx(
452
+ "path",
453
+ {
454
+ strokeLinecap: "round",
455
+ strokeLinejoin: "round",
456
+ strokeWidth: 2,
457
+ d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
458
+ }
459
+ )
460
+ }
461
+ ),
462
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "14px", fontWeight: "600", color: "#fff" }, children: domain })
463
+ ] }),
464
+ /* @__PURE__ */ jsx("div", { style: { backgroundColor: "#2a2a2a", padding: "10px", borderRadius: "6px" }, children: /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "#ccc", wordBreak: "break-all", lineHeight: "1.5" }, children: url }) })
465
+ ] }),
466
+ !isLoading && !hasError && previewData && /* @__PURE__ */ jsxs(Fragment, { children: [
467
+ previewData.image && /* @__PURE__ */ jsx(
468
+ "div",
469
+ {
470
+ style: {
471
+ width: "100%",
472
+ height: "140px",
473
+ backgroundColor: "#2a2a2a",
474
+ backgroundImage: `url(${previewData.image})`,
475
+ backgroundSize: "cover",
476
+ backgroundPosition: "center"
477
+ }
478
+ }
479
+ ),
480
+ /* @__PURE__ */ jsxs("div", { style: { padding: "14px" }, children: [
481
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "10px" }, children: [
482
+ previewData.favicon ? /* @__PURE__ */ jsx(
483
+ "img",
484
+ {
485
+ src: previewData.favicon,
486
+ alt: "",
487
+ style: { width: "16px", height: "16px", borderRadius: "2px", objectFit: "contain" },
488
+ onError: (e) => {
489
+ e.currentTarget.style.display = "none";
490
+ }
491
+ }
492
+ ) : /* @__PURE__ */ jsx("span", { style: { color: "#888" }, children: /* @__PURE__ */ jsx(TypeIcon, { type: previewData.type }) }),
493
+ /* @__PURE__ */ jsx(
494
+ "span",
495
+ {
496
+ style: {
497
+ fontSize: "12px",
498
+ color: "#888",
499
+ flex: 1,
500
+ overflow: "hidden",
501
+ textOverflow: "ellipsis",
502
+ whiteSpace: "nowrap"
503
+ },
504
+ children: previewData.siteName || domain
505
+ }
506
+ ),
507
+ /* @__PURE__ */ jsx(
508
+ "span",
509
+ {
510
+ style: {
511
+ fontSize: "10px",
512
+ color: "#666",
513
+ padding: "2px 6px",
514
+ backgroundColor: "#333",
515
+ borderRadius: "4px",
516
+ textTransform: "uppercase"
517
+ },
518
+ children: previewData.type
519
+ }
520
+ )
521
+ ] }),
522
+ previewData.title && /* @__PURE__ */ jsx(
523
+ "h4",
524
+ {
525
+ style: {
526
+ fontSize: "14px",
527
+ fontWeight: "600",
528
+ color: "#fff",
529
+ marginBottom: "6px",
530
+ lineHeight: "1.4",
531
+ display: "-webkit-box",
532
+ WebkitLineClamp: 2,
533
+ WebkitBoxOrient: "vertical",
534
+ overflow: "hidden"
535
+ },
536
+ children: previewData.title
537
+ }
538
+ ),
539
+ previewData.description && /* @__PURE__ */ jsx(
540
+ "p",
541
+ {
542
+ style: {
543
+ fontSize: "12px",
544
+ color: "#999",
545
+ lineHeight: "1.5",
546
+ display: "-webkit-box",
547
+ WebkitLineClamp: 2,
548
+ WebkitBoxOrient: "vertical",
549
+ overflow: "hidden",
550
+ marginBottom: "10px"
551
+ },
552
+ children: previewData.description
553
+ }
554
+ ),
555
+ /* @__PURE__ */ jsxs(
556
+ "div",
557
+ {
558
+ style: {
559
+ display: "flex",
560
+ alignItems: "center",
561
+ gap: "6px",
562
+ padding: "8px 10px",
563
+ backgroundColor: "#252525",
564
+ borderRadius: "6px",
565
+ marginTop: "8px"
566
+ },
567
+ children: [
568
+ /* @__PURE__ */ jsx(
569
+ "svg",
570
+ {
571
+ style: { width: "12px", height: "12px", color: "#666", flexShrink: 0 },
572
+ fill: "none",
573
+ stroke: "currentColor",
574
+ viewBox: "0 0 24 24",
575
+ children: /* @__PURE__ */ jsx(
576
+ "path",
577
+ {
578
+ strokeLinecap: "round",
579
+ strokeLinejoin: "round",
580
+ strokeWidth: 2,
581
+ d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
582
+ }
583
+ )
584
+ }
585
+ ),
586
+ /* @__PURE__ */ jsx(
587
+ "span",
588
+ {
589
+ style: {
590
+ fontSize: "11px",
591
+ color: "#888",
592
+ overflow: "hidden",
593
+ textOverflow: "ellipsis",
594
+ whiteSpace: "nowrap"
595
+ },
596
+ children: url
597
+ }
598
+ )
599
+ ]
600
+ }
601
+ )
602
+ ] })
603
+ ] })
604
+ ] }),
605
+ /* @__PURE__ */ jsx("style", { children: `
606
+ @keyframes linkPreviewFadeIn {
607
+ from { opacity: 0; transform: translateY(5px); }
608
+ to { opacity: 1; transform: translateY(0); }
609
+ }
610
+ @keyframes linkPreviewSpin {
611
+ from { transform: rotate(0deg); }
612
+ to { transform: rotate(360deg); }
613
+ }
614
+ ` })
615
+ ] });
616
+ }
617
+ function TypeIcon({ type }) {
618
+ const iconProps = {
619
+ style: { width: "14px", height: "14px" },
620
+ fill: "none",
621
+ stroke: "currentColor",
622
+ viewBox: "0 0 24 24"
623
+ };
624
+ const pathProps = {
625
+ strokeLinecap: "round",
626
+ strokeLinejoin: "round",
627
+ strokeWidth: 2
628
+ };
629
+ switch (type) {
630
+ case "image":
631
+ return /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx(
632
+ "path",
633
+ {
634
+ ...pathProps,
635
+ d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
636
+ }
637
+ ) });
638
+ case "video":
639
+ return /* @__PURE__ */ jsxs("svg", { ...iconProps, children: [
640
+ /* @__PURE__ */ jsx(
641
+ "path",
642
+ {
643
+ ...pathProps,
644
+ d: "M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"
645
+ }
646
+ ),
647
+ /* @__PURE__ */ jsx("path", { ...pathProps, d: "M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })
648
+ ] });
649
+ case "pdf":
650
+ return /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx(
651
+ "path",
652
+ {
653
+ ...pathProps,
654
+ d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
655
+ }
656
+ ) });
657
+ default:
658
+ return /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx(
659
+ "path",
660
+ {
661
+ ...pathProps,
662
+ d: "M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"
663
+ }
664
+ ) });
665
+ }
666
+ }
107
667
  const convertToEditorConfigTypes = (config) => {
108
668
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
109
669
  return {
@@ -137,7 +697,9 @@ const EditorProvider = ({
137
697
  children,
138
698
  defaultFontFamilies = [],
139
699
  mentionUserList = [],
140
- currentUser
700
+ currentUser,
701
+ enableLinkPreview = true,
702
+ apiKey: initialApiKey
141
703
  }) => {
142
704
  const [isAuthenticated, setIsAuthenticated] = useState$1(false);
143
705
  const [isLoading, setIsLoading] = useState$1(false);
@@ -148,7 +710,14 @@ const EditorProvider = ({
148
710
  const [projectName, setProjectName] = useState$1(null);
149
711
  const [isPaidPlan, setIsPaidPlan] = useState$1(false);
150
712
  const [apiKey, setApiKey] = useState$1(null);
151
- const verifyKey = async (apiKey2) => {
713
+ const hasAutoAuthenticatedRef = useRef(false);
714
+ useEffect$1(() => {
715
+ if (initialApiKey && !isAuthenticated && !isLoading && !hasAutoAuthenticatedRef.current) {
716
+ hasAutoAuthenticatedRef.current = true;
717
+ verifyKeyInternal(initialApiKey);
718
+ }
719
+ }, [initialApiKey, isAuthenticated, isLoading]);
720
+ const verifyKeyInternal = async (key) => {
152
721
  var _a, _b;
153
722
  if (isAuthenticated || isLoading)
154
723
  return;
@@ -156,14 +725,14 @@ const EditorProvider = ({
156
725
  setIsLoading(true);
157
726
  setError(null);
158
727
  try {
159
- const response = await verifyApiKey(apiKey2);
728
+ const response = await verifyApiKey(key);
160
729
  console.log(response, "response form verifyKey");
161
730
  if (response.success) {
162
731
  setIsAuthenticated(true);
163
732
  setEditorConfig(convertToEditorConfigTypes(response.data));
164
733
  setProjectName(response.data.name);
165
734
  setIsPaidPlan(response.data.paidPlan);
166
- setApiKey(apiKey2);
735
+ setApiKey(key);
167
736
  } else {
168
737
  console.log(response.message, "response.message form verifyKey");
169
738
  setError(response.message);
@@ -176,6 +745,9 @@ const EditorProvider = ({
176
745
  setIsLoading(false);
177
746
  }
178
747
  };
748
+ const verifyKey = (key) => verifyKeyInternal(key);
749
+ const effectiveApiKey = apiKey || initialApiKey;
750
+ const wrappedChildren = enableLinkPreview && effectiveApiKey ? /* @__PURE__ */ jsx(LinkPreviewHover, { apiKey: effectiveApiKey, enabled: enableLinkPreview, children }) : children;
179
751
  return /* @__PURE__ */ jsx(
180
752
  EditorContext.Provider,
181
753
  {
@@ -190,7 +762,7 @@ const EditorProvider = ({
190
762
  currentUser: currentUser || null,
191
763
  verifyKey
192
764
  },
193
- children
765
+ children: wrappedChildren
194
766
  }
195
767
  );
196
768
  };
@@ -198,13 +770,6 @@ const globals = "";
198
770
  const EditorTheme = "";
199
771
  const PlaygroundEditorTheme = "";
200
772
  const AIChatPlugin$1 = "";
201
- const backendInstance = axios.create({
202
- baseURL: "https://api.cteditor.com/",
203
- headers: {
204
- "Content-Type": "application/json"
205
- }
206
- });
207
- const backendAPI = backendInstance;
208
773
  const editorConfig = {
209
774
  enableToolbar: true,
210
775
  toolbarOptions: {
@@ -1500,34 +2065,13 @@ const Toaster = /* @__PURE__ */ React__default.forwardRef(function Toaster2(prop
1500
2065
  }))
1501
2066
  );
1502
2067
  });
1503
- const apiEndpoints = {
1504
- // School management endpoints
1505
- chat: {
1506
- stream: "/api/chat/stream",
1507
- json: "/api/chat/json",
1508
- textEnhance: "/api/chat/text-enhance",
1509
- textTransform: "/api/chat/text-transform",
1510
- imageCreation: "/api/chat/image-creation",
1511
- editorAction: "/api/chat/chat-action",
1512
- credits: "/api/chat/credits",
1513
- userInfo: "/api/chat/user-info"
1514
- },
1515
- project: {
1516
- fileUpload: "/api/files/upload"
1517
- },
1518
- transcript: {
1519
- voiceTranscript: "/api/transcript/get-assemblyai-token",
1520
- endSession: "/api/transcript/end-session"
1521
- },
1522
- linkPreview: {
1523
- getPreview: "/api/link-preview"
1524
- }
1525
- };
1526
- const AiJsonResponse = async ({ content }) => {
2068
+ const AiJsonResponse = async ({ content, apiKey }) => {
1527
2069
  try {
1528
- const res = await backendAPI.post(apiEndpoints.chat.json, {
1529
- content
1530
- });
2070
+ const res = await backendAPI.post(
2071
+ apiEndpoints.chat.json,
2072
+ { content },
2073
+ apiKey ? { headers: { "X-API-Key": apiKey } } : void 0
2074
+ );
1531
2075
  return res.data;
1532
2076
  } catch (error) {
1533
2077
  console.error("Error in AiJsonResponse:", error);
@@ -1604,7 +2148,7 @@ const AiTextTransform = async ({ content, apiKey }) => {
1604
2148
  const AI_ACTION_COMMAND = createCommand(
1605
2149
  "AI_ACTION_COMMAND"
1606
2150
  );
1607
- const ImageView = React__default.lazy(() => import("./index-acc78985.js"));
2151
+ const ImageView = React__default.lazy(() => import("./index-f51de846.js"));
1608
2152
  function isGoogleDocCheckboxImg(img) {
1609
2153
  return img.parentElement != null && img.parentElement.tagName === "LI" && img.previousSibling === null && img.getAttribute("aria-roledescription") === "checkbox";
1610
2154
  }
@@ -7264,6 +7808,18 @@ const ArrowRight = createLucideIcon("ArrowRight", [
7264
7808
  ["path", { d: "M5 12h14", key: "1ays0h" }],
7265
7809
  ["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
7266
7810
  ]);
7811
+ /**
7812
+ * @license lucide-react v0.344.0 - ISC
7813
+ *
7814
+ * This source code is licensed under the ISC license.
7815
+ * See the LICENSE file in the root directory of this source tree.
7816
+ */
7817
+ const BarChart3 = createLucideIcon("BarChart3", [
7818
+ ["path", { d: "M3 3v18h18", key: "1s2lah" }],
7819
+ ["path", { d: "M18 17V9", key: "2bz60n" }],
7820
+ ["path", { d: "M13 17V5", key: "1frdt8" }],
7821
+ ["path", { d: "M8 17v-3", key: "17ska0" }]
7822
+ ]);
7267
7823
  /**
7268
7824
  * @license lucide-react v0.344.0 - ISC
7269
7825
  *
@@ -7397,23 +7953,6 @@ const Download = createLucideIcon("Download", [
7397
7953
  ["polyline", { points: "7 10 12 15 17 10", key: "2ggqvy" }],
7398
7954
  ["line", { x1: "12", x2: "12", y1: "15", y2: "3", key: "1vk2je" }]
7399
7955
  ]);
7400
- /**
7401
- * @license lucide-react v0.344.0 - ISC
7402
- *
7403
- * This source code is licensed under the ISC license.
7404
- * See the LICENSE file in the root directory of this source tree.
7405
- */
7406
- const Eraser = createLucideIcon("Eraser", [
7407
- [
7408
- "path",
7409
- {
7410
- d: "m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21",
7411
- key: "182aya"
7412
- }
7413
- ],
7414
- ["path", { d: "M22 21H7", key: "t4ddhn" }],
7415
- ["path", { d: "m5 11 9 9", key: "1mo9qw" }]
7416
- ]);
7417
7956
  /**
7418
7957
  * @license lucide-react v0.344.0 - ISC
7419
7958
  *
@@ -7791,6 +8330,18 @@ const PenLine = createLucideIcon("PenLine", [
7791
8330
  ["path", { d: "M12 20h9", key: "t2du7b" }],
7792
8331
  ["path", { d: "M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z", key: "ymcmye" }]
7793
8332
  ]);
8333
+ /**
8334
+ * @license lucide-react v0.344.0 - ISC
8335
+ *
8336
+ * This source code is licensed under the ISC license.
8337
+ * See the LICENSE file in the root directory of this source tree.
8338
+ */
8339
+ const PenTool = createLucideIcon("PenTool", [
8340
+ ["path", { d: "m12 19 7-7 3 3-7 7-3-3z", key: "rklqx2" }],
8341
+ ["path", { d: "m18 13-1.5-7.5L2 2l3.5 14.5L13 18l5-5z", key: "1et58u" }],
8342
+ ["path", { d: "m2 2 7.586 7.586", key: "etlp93" }],
8343
+ ["circle", { cx: "11", cy: "11", r: "2", key: "xmgehs" }]
8344
+ ]);
7794
8345
  /**
7795
8346
  * @license lucide-react v0.344.0 - ISC
7796
8347
  *
@@ -7904,6 +8455,17 @@ const Sparkles = createLucideIcon("Sparkles", [
7904
8455
  ["path", { d: "M3 5h4", key: "nem4j1" }],
7905
8456
  ["path", { d: "M17 19h4", key: "lbex7p" }]
7906
8457
  ]);
8458
+ /**
8459
+ * @license lucide-react v0.344.0 - ISC
8460
+ *
8461
+ * This source code is licensed under the ISC license.
8462
+ * See the LICENSE file in the root directory of this source tree.
8463
+ */
8464
+ const SpellCheck = createLucideIcon("SpellCheck", [
8465
+ ["path", { d: "m6 16 6-12 6 12", key: "1b4byz" }],
8466
+ ["path", { d: "M8 12h8", key: "1wcyev" }],
8467
+ ["path", { d: "m16 20 2 2 4-4", key: "13tcca" }]
8468
+ ]);
7907
8469
  /**
7908
8470
  * @license lucide-react v0.344.0 - ISC
7909
8471
  *
@@ -8697,7 +9259,7 @@ const AIRephrasePlugin = () => {
8697
9259
  duration: Infinity
8698
9260
  });
8699
9261
  try {
8700
- const response = type === "MAKE_LONGER" || type === "MAKE_SHORTER" ? await AiTextTransform({ content: prompt, apiKey: apiKey || void 0 }) : await AiJsonResponse({ content: prompt });
9262
+ const response = type === "MAKE_LONGER" || type === "MAKE_SHORTER" ? await AiTextTransform({ content: prompt, apiKey: apiKey || void 0 }) : await AiJsonResponse({ content: prompt, apiKey: apiKey || void 0 });
8701
9263
  if (!response.data) {
8702
9264
  console.warn("Empty response received");
8703
9265
  toast.dismiss(loadingToastId);
@@ -8739,7 +9301,7 @@ const AIRephrasePlugin = () => {
8739
9301
  const prompt = `Translate this text to ${targetLanguage}. Return ONLY the translated text without any markdown formatting, headers, or special symbols. Just the plain translated text:
8740
9302
 
8741
9303
  "${selectedTextForTranslation}"`;
8742
- const response = await AiJsonResponse({ content: prompt });
9304
+ const response = await AiJsonResponse({ content: prompt, apiKey: apiKey || void 0 });
8743
9305
  if (!response.data) {
8744
9306
  console.warn("Empty response received");
8745
9307
  toast.dismiss(loadingToastId);
@@ -8867,7 +9429,7 @@ const AIRephrasePlugin = () => {
8867
9429
  };
8868
9430
  const generateImageFromPrompt = async (promptText) => {
8869
9431
  try {
8870
- const response = await AiJsonResponse({ content: `Generate Image: ${promptText}` });
9432
+ const response = await AiJsonResponse({ content: `Generate Image: ${promptText}`, apiKey: apiKey || void 0 });
8871
9433
  const htmlString = response == null ? void 0 : response.data;
8872
9434
  if (!htmlString) {
8873
9435
  console.warn("No HTML returned from agent for image generation");
@@ -9022,7 +9584,7 @@ const AIRephrasePlugin = () => {
9022
9584
  )
9023
9585
  ] });
9024
9586
  };
9025
- const index$8 = "";
9587
+ const index$7 = "";
9026
9588
  var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
9027
9589
  const freeGlobal$1 = freeGlobal;
9028
9590
  var freeSelf = typeof self == "object" && self && self.Object === Object && self;
@@ -9250,7 +9812,7 @@ function CopyButton({ editor, getCodeDOMNode }) {
9250
9812
  }
9251
9813
  );
9252
9814
  }
9253
- const index$7 = "";
9815
+ const index$6 = "";
9254
9816
  const PRETTIER_PARSER_MODULES = {
9255
9817
  css: [() => import("./postcss-c2592f3f.js")],
9256
9818
  html: [() => import("./html-f95ee5dc.js")],
@@ -12712,7 +13274,7 @@ const computePosition = (reference, floating, options) => {
12712
13274
  var isClient = typeof document !== "undefined";
12713
13275
  var noop = function noop2() {
12714
13276
  };
12715
- var index$6 = isClient ? useLayoutEffect$1 : noop;
13277
+ var index$5 = isClient ? useLayoutEffect$1 : noop;
12716
13278
  function deepEqual(a, b2) {
12717
13279
  if (a === b2) {
12718
13280
  return true;
@@ -12774,7 +13336,7 @@ function roundByDPR(element, value) {
12774
13336
  }
12775
13337
  function useLatestRef(value) {
12776
13338
  const ref = React$1.useRef(value);
12777
- index$6(() => {
13339
+ index$5(() => {
12778
13340
  ref.current = value;
12779
13341
  });
12780
13342
  return ref;
@@ -12860,7 +13422,7 @@ function useFloating(options) {
12860
13422
  }
12861
13423
  });
12862
13424
  }, [latestMiddleware, placement, strategy, platformRef, openRef]);
12863
- index$6(() => {
13425
+ index$5(() => {
12864
13426
  if (open === false && dataRef.current.isPositioned) {
12865
13427
  dataRef.current.isPositioned = false;
12866
13428
  setData((data2) => ({
@@ -12870,13 +13432,13 @@ function useFloating(options) {
12870
13432
  }
12871
13433
  }, [open]);
12872
13434
  const isMountedRef = React$1.useRef(false);
12873
- index$6(() => {
13435
+ index$5(() => {
12874
13436
  isMountedRef.current = true;
12875
13437
  return () => {
12876
13438
  isMountedRef.current = false;
12877
13439
  };
12878
13440
  }, []);
12879
- index$6(() => {
13441
+ index$5(() => {
12880
13442
  if (referenceEl)
12881
13443
  referenceRef.current = referenceEl;
12882
13444
  if (floatingEl)
@@ -15333,7 +15895,7 @@ const EmbedComponent = ({ url, displayType, alignment, width: initialWidth, heig
15333
15895
  }
15334
15896
  );
15335
15897
  };
15336
- const FileComponent = React$1.lazy(() => import("./index-08c4c610.js"));
15898
+ const FileComponent = React$1.lazy(() => import("./index-39c10e00.js"));
15337
15899
  function convertFileElement(domNode) {
15338
15900
  if (domNode instanceof HTMLDivElement) {
15339
15901
  const dataUrl = domNode.getAttribute("data-lexical-file-src");
@@ -19529,7 +20091,7 @@ function AIChatDialog({
19529
20091
  return imageKeywords.some((keyword) => lowerPrompt.includes(keyword));
19530
20092
  };
19531
20093
  const handleSubmit = async () => {
19532
- var _a, _b;
20094
+ var _a, _b, _c, _d;
19533
20095
  if (!inputValue.trim() || isLoading)
19534
20096
  return;
19535
20097
  setIsLoading(true);
@@ -19579,7 +20141,11 @@ Text to transform:
19579
20141
  setIsLoading(false);
19580
20142
  } catch (error) {
19581
20143
  console.error("Error processing AI action:", error);
19582
- const apiMessage = ((_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message) ?? (error instanceof Error ? error.message : null);
20144
+ const errorCode = (_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.code;
20145
+ const errorCodeMessages = {
20146
+ "INSUFFICIENT_CREDITS": "You have insufficient credits. Please purchase more credits to continue using AI features."
20147
+ };
20148
+ const apiMessage = errorCodeMessages[errorCode] ?? ((_d = (_c = error == null ? void 0 : error.response) == null ? void 0 : _c.data) == null ? void 0 : _d.message) ?? (error instanceof Error ? error.message : null);
19583
20149
  const safeMessage = apiMessage && !/^Request failed with status code \d+/.test(apiMessage) ? apiMessage : "Error processing your request. Please try again.";
19584
20150
  setErrorMessage(safeMessage);
19585
20151
  toast.error(safeMessage);
@@ -19891,29 +20457,28 @@ function InlineAIPrompt({
19891
20457
  return imageKeywords.some((keyword) => lowerPrompt.includes(keyword));
19892
20458
  };
19893
20459
  const handleSubmit = async () => {
19894
- var _a, _b;
20460
+ var _a, _b, _c, _d;
19895
20461
  if (!inputValue.trim() || isLoading)
19896
20462
  return;
19897
- const isImageRequest = isImageGenerationRequest(inputValue) || selectedText && isImageGenerationRequest(selectedText);
19898
- if (!isImageRequest && (!selectedText || selectedText.trim() === "")) {
19899
- toast.error("Please select some text first");
19900
- return;
19901
- }
19902
20463
  setIsLoading(true);
20464
+ const isImageRequest = isImageGenerationRequest(inputValue) || selectedText && isImageGenerationRequest(selectedText);
20465
+ const hasSelectedText2 = selectedText && selectedText.trim() !== "";
19903
20466
  let finalPrompt;
19904
20467
  if (isImageRequest) {
19905
- if (selectedText && selectedText.trim()) {
20468
+ if (hasSelectedText2) {
19906
20469
  finalPrompt = `${inputValue}: ${selectedText}`;
19907
20470
  } else {
19908
20471
  finalPrompt = inputValue;
19909
20472
  }
19910
- } else {
20473
+ } else if (hasSelectedText2) {
19911
20474
  finalPrompt = `${inputValue}
19912
20475
 
19913
20476
  IMPORTANT: Return ONLY the modified/transformed text. Do NOT include any labels, prefixes, explanations, or formatting like "Simplified:", "Result:", "Here is", etc. Just return the pure result text.
19914
20477
 
19915
20478
  Text to transform:
19916
20479
  "${selectedText}"`;
20480
+ } else {
20481
+ finalPrompt = inputValue;
19917
20482
  }
19918
20483
  try {
19919
20484
  const response = await AiEditorAction({ content: finalPrompt, provider, apiKey });
@@ -19949,7 +20514,11 @@ Text to transform:
19949
20514
  setShowMessage(true);
19950
20515
  } catch (error) {
19951
20516
  console.error("Error processing AI action:", error);
19952
- const apiMessage = ((_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message) ?? (error instanceof Error ? error.message : null);
20517
+ const errorCode = (_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.code;
20518
+ const errorCodeMessages = {
20519
+ "INSUFFICIENT_CREDITS": "You have insufficient credits. Please purchase more credits to continue using AI features."
20520
+ };
20521
+ const apiMessage = errorCodeMessages[errorCode] ?? ((_d = (_c = error == null ? void 0 : error.response) == null ? void 0 : _c.data) == null ? void 0 : _d.message) ?? (error instanceof Error ? error.message : null);
19953
20522
  const safeMessage = apiMessage && !/^Request failed with status code \d+/.test(apiMessage) ? apiMessage : "Error processing your request. Please try again.";
19954
20523
  toast.error(safeMessage);
19955
20524
  setStatus("error");
@@ -19968,10 +20537,9 @@ Text to transform:
19968
20537
  }
19969
20538
  };
19970
20539
  const hasSelectedText = selectedText && selectedText.trim() !== "";
19971
- const isCurrentInputImageRequest = isImageGenerationRequest(inputValue);
19972
20540
  const displayText = hasSelectedText ? selectedText.length > 50 ? selectedText.substring(0, 50) + "..." : selectedText : "";
19973
20541
  return /* @__PURE__ */ jsxs("div", { className: "cteditor-absolute cteditor-bottom-1 cteditor-left-1/2 cteditor--translate-x-1/2 cteditor-flex cteditor-flex-col cteditor-gap-2 cteditor-bg-[#1a1a1a] cteditor-px-2 cteditor-py-2 cteditor-rounded-md cteditor-border cteditor-border-[#333] cteditor-shadow-[0_8px_24px_rgba(0,0,0,0.4)] cteditor-z-10 cteditor-max-w-[435px] cteditor-w-full", children: [
19974
- showMessage && /* @__PURE__ */ jsxs("div", { className: `cteditor-relative cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-pl-2.5 cteditor-pr-6 cteditor-py-1.5 cteditor-rounded-md cteditor-text-xs cteditor-text-[#999] ${status === "success" ? "cteditor-bg-[#1a2e1a] cteditor-border cteditor-border-[#3a5a3a]" : status === "error" ? "cteditor-bg-[#2e1a1a] cteditor-border cteditor-border-[#5a3a3a]" : hasSelectedText ? "cteditor-bg-[#2a2a2a]" : isCurrentInputImageRequest ? "cteditor-bg-[#2a3a2a] cteditor-border cteditor-border-[#3a5a3a]" : "cteditor-bg-[#3a2a2a] cteditor-border cteditor-border-[#5a3a3a]"}`, children: [
20542
+ showMessage && /* @__PURE__ */ jsxs("div", { className: `cteditor-relative cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-pl-2.5 cteditor-pr-6 cteditor-py-1.5 cteditor-rounded-md cteditor-text-xs cteditor-text-[#999] ${status === "success" ? "cteditor-bg-[#1a2e1a] cteditor-border cteditor-border-[#3a5a3a]" : status === "error" ? "cteditor-bg-[#2e1a1a] cteditor-border cteditor-border-[#5a3a3a]" : "cteditor-bg-[#2a2a2a]"}`, children: [
19975
20543
  status === "success" ? /* @__PURE__ */ jsx("span", { className: "cteditor-text-[#4ade80]", children: "✓ Content inserted! Select new text or enter another prompt" }) : status === "error" ? /* @__PURE__ */ jsx("span", { className: "cteditor-text-[#f87171]", children: "✗ Request failed. Try again or select different text" }) : hasSelectedText ? /* @__PURE__ */ jsxs(Fragment, { children: [
19976
20544
  /* @__PURE__ */ jsx("span", { className: "cteditor-text-[#666]", children: "Selected:" }),
19977
20545
  /* @__PURE__ */ jsxs("span", { className: "cteditor-text-[#ccc] cteditor-italic", children: [
@@ -19979,7 +20547,7 @@ Text to transform:
19979
20547
  displayText,
19980
20548
  '"'
19981
20549
  ] })
19982
- ] }) : isCurrentInputImageRequest ? /* @__PURE__ */ jsx("span", { className: "cteditor-text-[#4ade80]", children: "🖼️ Image generation mode - no text selection required" }) : /* @__PURE__ */ jsx("span", { className: "cteditor-text-[#f87171]", children: "⚠ Please select some text or enter an image generation prompt" }),
20550
+ ] }) : /* @__PURE__ */ jsx("span", { className: "cteditor-text-[#ccc]", children: "Ask AI anything or select text to transform" }),
19983
20551
  /* @__PURE__ */ jsx(
19984
20552
  "button",
19985
20553
  {
@@ -20013,7 +20581,7 @@ Text to transform:
20013
20581
  setShowMessage(true);
20014
20582
  },
20015
20583
  onKeyDown: handleKeyDown,
20016
- placeholder: hasSelectedText ? "What do you want to do with this text?" : "Generate image of... or select text",
20584
+ placeholder: hasSelectedText ? "What do you want to do with this text?" : "Ask AI anything...",
20017
20585
  disabled: isLoading,
20018
20586
  className: " cteditor-h-8 cteditor-px-2 cteditor-text-xs cteditor-w-full cteditor-border cteditor-border-[#444] cteditor-rounded-md cteditor-outline-none cteditor-bg-[#2a2a2a] cteditor-text-white md:cteditor-w-60"
20019
20587
  }
@@ -20132,6 +20700,47 @@ function AIChatPlugin({
20132
20700
  const [editor] = useLexicalComposerContext();
20133
20701
  return useAIChatToolbar(editor, apiKey);
20134
20702
  }
20703
+ const BACKEND_URL = "https://api.cteditor.com/";
20704
+ async function generateChart(metadata, apiKey) {
20705
+ try {
20706
+ const response = await fetch(`${BACKEND_URL}api/chat/regenerate`, {
20707
+ method: "POST",
20708
+ headers: {
20709
+ "Content-Type": "application/json",
20710
+ "x-api-key": apiKey || ""
20711
+ },
20712
+ body: JSON.stringify(metadata)
20713
+ });
20714
+ if (!response.ok) {
20715
+ const errorData = await response.json().catch(() => ({}));
20716
+ throw new Error(errorData.message || `Server error: ${response.status}`);
20717
+ }
20718
+ const data = await response.json();
20719
+ if (!data.success || !data.html) {
20720
+ throw new Error(data.message || "Failed to generate chart");
20721
+ }
20722
+ return {
20723
+ success: true,
20724
+ html: data.html
20725
+ };
20726
+ } catch (error) {
20727
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
20728
+ return {
20729
+ success: false,
20730
+ error: errorMessage
20731
+ };
20732
+ }
20733
+ }
20734
+ async function generateChartWithToast(metadata, apiKey) {
20735
+ const toastId = toast.loading("Generating chart...");
20736
+ const result = await generateChart(metadata, apiKey);
20737
+ if (result.success) {
20738
+ toast.success("Chart inserted successfully!", { id: toastId });
20739
+ } else {
20740
+ toast.error(`Failed to insert chart: ${result.error}`, { id: toastId });
20741
+ }
20742
+ return result;
20743
+ }
20135
20744
  const CREATE_TABLE_COMMAND = createCommand();
20136
20745
  function TableOptionPlugin({ isActive }) {
20137
20746
  const [editor] = useLexicalComposerContext();
@@ -20866,10 +21475,10 @@ const PDF_CONFIG = {
20866
21475
  };
20867
21476
  const loadHtml2Pdf = async () => {
20868
21477
  try {
20869
- const mod = await import("./html2pdf.bundle.min-e3118523.js").then((n) => n.h);
21478
+ const mod = await import("./html2pdf.bundle.min-d6fba18e.js").then((n) => n.h);
20870
21479
  return (mod == null ? void 0 : mod.default) || mod;
20871
21480
  } catch {
20872
- const mod2 = await import("./html2pdf.bundle-2195a04c.js").then((n) => n.h);
21481
+ const mod2 = await import("./html2pdf.bundle-d21122e4.js").then((n) => n.h);
20873
21482
  return (mod2 == null ? void 0 : mod2.default) || mod2;
20874
21483
  }
20875
21484
  };
@@ -26874,29 +27483,10 @@ const Toolbar = ({
26874
27483
  }, []);
26875
27484
  const handleChartInsert = useCallback(
26876
27485
  async (metadata) => {
26877
- const toastId = toast.loading("Generating chart...");
26878
- try {
26879
- const backendUrl = "https://api.cteditor.com/".replace(/\/$/, "");
26880
- const response = await fetch(`${backendUrl}/api/chat/regenerate`, {
26881
- method: "POST",
26882
- headers: {
26883
- "Content-Type": "application/json",
26884
- "x-api-key": apiKey || ""
26885
- },
26886
- body: JSON.stringify(metadata)
26887
- });
26888
- if (!response.ok) {
26889
- const errorData = await response.json().catch(() => ({}));
26890
- throw new Error(
26891
- errorData.message || `Server error: ${response.status}`
26892
- );
26893
- }
26894
- const data = await response.json();
26895
- if (!data.success || !data.html) {
26896
- throw new Error(data.message || "Failed to generate chart");
26897
- }
27486
+ const result = await generateChartWithToast(metadata, apiKey);
27487
+ if (result.success) {
26898
27488
  editor.update(() => {
26899
- const chartNode = $createChartNode(data.html, metadata);
27489
+ const chartNode = $createChartNode(result.html, metadata);
26900
27490
  const selection = $getSelection();
26901
27491
  if (!selection) {
26902
27492
  const root2 = $getRoot();
@@ -26907,10 +27497,6 @@ const Toolbar = ({
26907
27497
  const paragraphNode = $createParagraphNode();
26908
27498
  chartNode.insertAfter(paragraphNode);
26909
27499
  });
26910
- toast.success("Chart inserted successfully!", { id: toastId });
26911
- } catch (error) {
26912
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
26913
- toast.error(`Failed to insert chart: ${errorMessage}`, { id: toastId });
26914
27500
  }
26915
27501
  },
26916
27502
  [editor, apiKey]
@@ -28334,7 +28920,7 @@ const STATIC_SUGGESTIONS = [
28334
28920
  "programming"
28335
28921
  ];
28336
28922
  const CACHE_MAX_AGE = 5 * 60 * 1e3;
28337
- const MAX_CACHE_SIZE$1 = 200;
28923
+ const MAX_CACHE_SIZE = 200;
28338
28924
  const REQUEST_TIMEOUT = 3e4;
28339
28925
  const MENU_CONFIG = { width: 320, height: 200, padding: 8 };
28340
28926
  const TOOLTIP_CONFIG = {
@@ -28506,7 +29092,7 @@ class GrammarAIService {
28506
29092
  errors,
28507
29093
  checkedAt: Date.now()
28508
29094
  });
28509
- if (this.sentenceCache.size > MAX_CACHE_SIZE$1) {
29095
+ if (this.sentenceCache.size > MAX_CACHE_SIZE) {
28510
29096
  const oldestKey = this.sentenceCache.keys().next().value;
28511
29097
  if (oldestKey)
28512
29098
  this.sentenceCache.delete(oldestKey);
@@ -30471,416 +31057,6 @@ const EmbedPreviewPlugin = ({
30471
31057
  }, [editor]);
30472
31058
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(FloatingEmbedMenuPlugin, { anchorElem: floatingAnchorElem }) });
30473
31059
  };
30474
- const index$5 = "";
30475
- function getDOMRangeRect(nativeSelection, rootElement) {
30476
- const domRange = nativeSelection.getRangeAt(0);
30477
- let rect;
30478
- if (nativeSelection.anchorNode === rootElement) {
30479
- let inner = rootElement;
30480
- while (inner.firstElementChild != null) {
30481
- inner = inner.firstElementChild;
30482
- }
30483
- rect = inner.getBoundingClientRect();
30484
- } else {
30485
- rect = domRange.getBoundingClientRect();
30486
- }
30487
- return rect;
30488
- }
30489
- const TextEnhanceDialog = forwardRef(
30490
- ({ onEnhance }, ref) => {
30491
- const [isOpen, setIsOpen] = useState$1(false);
30492
- const [selectedText, setSelectedText] = useState$1("");
30493
- const [userPrompt, setUserPrompt] = useState$1("");
30494
- const [enhancedText, setEnhancedText] = useState$1("");
30495
- const [isLoading, setIsLoading] = useState$1(false);
30496
- const [showResult, setShowResult] = useState$1(false);
30497
- const [onInsertCallback, setOnInsertCallback] = useState$1(null);
30498
- useImperativeHandle(ref, () => ({
30499
- openDialog: (text, insertCallback) => {
30500
- setSelectedText(text);
30501
- setUserPrompt("");
30502
- setEnhancedText("");
30503
- setShowResult(false);
30504
- setOnInsertCallback(() => insertCallback);
30505
- setIsOpen(true);
30506
- },
30507
- closeDialog: () => {
30508
- setIsOpen(false);
30509
- setTimeout(() => {
30510
- setSelectedText("");
30511
- setUserPrompt("");
30512
- setEnhancedText("");
30513
- setShowResult(false);
30514
- setOnInsertCallback(null);
30515
- }, 300);
30516
- }
30517
- }));
30518
- const handleClose = () => {
30519
- setIsOpen(false);
30520
- setTimeout(() => {
30521
- setSelectedText("");
30522
- setUserPrompt("");
30523
- setEnhancedText("");
30524
- setShowResult(false);
30525
- setOnInsertCallback(null);
30526
- }, 300);
30527
- };
30528
- const handleEnhance = async () => {
30529
- if (!userPrompt.trim())
30530
- return;
30531
- setIsLoading(true);
30532
- try {
30533
- const result = await onEnhance(selectedText, userPrompt);
30534
- setEnhancedText(result);
30535
- setShowResult(true);
30536
- } catch (error) {
30537
- console.error("Enhancement error:", error);
30538
- } finally {
30539
- setIsLoading(false);
30540
- }
30541
- };
30542
- const handleInsert = () => {
30543
- if (onInsertCallback && enhancedText) {
30544
- onInsertCallback(enhancedText);
30545
- }
30546
- handleClose();
30547
- };
30548
- return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:cteditor-max-w-[500px] cteditor-max-h-[650px]", children: [
30549
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
30550
- /* @__PURE__ */ jsxs(DialogTitle, { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: [
30551
- /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-size-5" }),
30552
- "Enhance Text"
30553
- ] }),
30554
- /* @__PURE__ */ jsx(DialogDescription, { children: "Enhance your selected text with AI assistance." })
30555
- ] }),
30556
- /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-4 cteditor-overflow-y-auto cteditor-max-h-[400px] cteditor-pr-2", children: [
30557
- /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-1.5", children: [
30558
- /* @__PURE__ */ jsx("label", { className: "cteditor-text-xs cteditor-font-medium cteditor-text-foreground", children: "Selected Text" }),
30559
- /* @__PURE__ */ jsx("div", { className: "cteditor-p-3 cteditor-bg-accent/50 cteditor-rounded-lg cteditor-border cteditor-border-border cteditor-max-h-24 cteditor-overflow-y-auto", children: /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-text-foreground cteditor-leading-relaxed", children: selectedText }) })
30560
- ] }),
30561
- !showResult && /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-1.5", children: [
30562
- /* @__PURE__ */ jsx("label", { className: "cteditor-text-xs cteditor-font-medium cteditor-text-foreground", children: "How to enhance?" }),
30563
- /* @__PURE__ */ jsx(
30564
- "textarea",
30565
- {
30566
- value: userPrompt,
30567
- onChange: (e) => setUserPrompt(e.target.value),
30568
- placeholder: "E.g., Make it professional, Add details, Simplify...",
30569
- className: "cteditor-w-full cteditor-h-20 cteditor-p-3 cteditor-bg-background cteditor-rounded-lg cteditor-border cteditor-border-border focus:cteditor-border-foreground cteditor-outline-none cteditor-text-sm cteditor-text-foreground cteditor-placeholder-muted-foreground cteditor-resize-none",
30570
- disabled: isLoading,
30571
- onKeyDown: (e) => {
30572
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
30573
- handleEnhance();
30574
- }
30575
- }
30576
- }
30577
- ),
30578
- /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-text-muted-foreground", children: "Ctrl+Enter to enhance" })
30579
- ] }),
30580
- isLoading && /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-flex-col cteditor-items-center cteditor-justify-center cteditor-py-0 cteditor-space-y-3", children: [
30581
- /* @__PURE__ */ jsxs("div", { className: "cteditor-relative cteditor-w-14 cteditor-h-14", children: [
30582
- /* @__PURE__ */ jsx(
30583
- "div",
30584
- {
30585
- className: "cteditor-absolute cteditor-inset-0 cteditor-rounded-full cteditor-opacity-75",
30586
- style: {
30587
- background: "linear-gradient(to right, #a855f7, #ec4899, #a855f7)",
30588
- animation: "spin 2s linear infinite",
30589
- padding: "2px",
30590
- WebkitMask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
30591
- WebkitMaskComposite: "xor",
30592
- maskComposite: "exclude"
30593
- }
30594
- }
30595
- ),
30596
- /* @__PURE__ */ jsx("div", { className: "cteditor-absolute cteditor-inset-0 cteditor-rounded-full cteditor-bg-background cteditor-flex cteditor-items-center cteditor-justify-center cteditor-m-[2px]", children: /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-w-6 cteditor-h-6 cteditor-text-purple-500 cteditor-animate-pulse" }) })
30597
- ] }),
30598
- /* @__PURE__ */ jsx("div", { className: "cteditor-text-center", children: /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-font-medium cteditor-text-foreground", children: "Enhancing text..." }) })
30599
- ] }),
30600
- showResult && !isLoading && /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-1.5 cteditor-animate-in cteditor-fade-in cteditor-slide-in-from-bottom-4", children: [
30601
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-1.5", children: [
30602
- /* @__PURE__ */ jsx(Check, { className: "cteditor-w-3.5 cteditor-h-3.5 cteditor-text-green-500" }),
30603
- /* @__PURE__ */ jsx("label", { className: "cteditor-text-xs cteditor-font-medium cteditor-text-foreground", children: "Enhanced Text" })
30604
- ] }),
30605
- /* @__PURE__ */ jsx("div", { className: "cteditor-p-3 cteditor-bg-gradient-to-br cteditor-from-purple-500/5 cteditor-to-pink-500/5 cteditor-rounded-lg cteditor-border cteditor-border-purple-500/20 cteditor-max-h-48 cteditor-overflow-y-auto", children: /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-text-foreground cteditor-leading-relaxed", children: enhancedText }) })
30606
- ] })
30607
- ] }),
30608
- /* @__PURE__ */ jsxs(DialogFooter, { children: [
30609
- /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClose, children: "Cancel" }),
30610
- !showResult && /* @__PURE__ */ jsxs(
30611
- Button,
30612
- {
30613
- onClick: handleEnhance,
30614
- disabled: !userPrompt.trim() || isLoading,
30615
- className: "cteditor-gap-2",
30616
- children: [
30617
- /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-size-5" }),
30618
- "Enhance"
30619
- ]
30620
- }
30621
- ),
30622
- showResult && /* @__PURE__ */ jsxs(
30623
- Button,
30624
- {
30625
- onClick: handleInsert,
30626
- className: "cteditor-gap-2",
30627
- children: [
30628
- "Insert",
30629
- /* @__PURE__ */ jsx(ArrowRight, { className: "cteditor-size-5" })
30630
- ]
30631
- }
30632
- )
30633
- ] })
30634
- ] }) });
30635
- }
30636
- );
30637
- TextEnhanceDialog.displayName = "TextEnhanceDialog";
30638
- const TEXT_ENHANCE_COMMAND = createCommand("TEXT_ENHANCE_COMMAND");
30639
- const TextEnhancePlugin = ({ apiKey }) => {
30640
- const [editor] = useLexicalComposerContext();
30641
- const enhanceDialogRef = useRef(null);
30642
- const handleTextEnhancement = async (selectedText, userPrompt) => {
30643
- try {
30644
- const prompt = `Enhance the following text based on this instruction: "${userPrompt}"
30645
-
30646
- Original text:
30647
- "${selectedText}"
30648
-
30649
- Provide only the enhanced text without any additional explanation.`;
30650
- const response = await AiTextEnhance({ content: prompt, apiKey });
30651
- if (!response.data) {
30652
- throw new Error("No response received from AI");
30653
- }
30654
- return response.data;
30655
- } catch (error) {
30656
- console.error("Error enhancing text:", error);
30657
- toast.error("Enhancement failed", {
30658
- description: error instanceof Error ? error.message : "An error occurred"
30659
- });
30660
- throw error;
30661
- }
30662
- };
30663
- const handleOpenDialog = (selectedText) => {
30664
- editor.getEditorState().read(() => {
30665
- var _a;
30666
- const selection = $getSelection();
30667
- if (!$isRangeSelection(selection))
30668
- return;
30669
- const text = selectedText || selection.getTextContent().trim();
30670
- if (!text) {
30671
- toast.error("No text selected", {
30672
- description: "Please select some text to enhance"
30673
- });
30674
- return;
30675
- }
30676
- (_a = enhanceDialogRef.current) == null ? void 0 : _a.openDialog(text, (enhancedText) => {
30677
- editor.update(() => {
30678
- const currentSelection = $getSelection();
30679
- if (!currentSelection || !$isRangeSelection(currentSelection))
30680
- return;
30681
- const parser = new DOMParser();
30682
- const dom = parser.parseFromString(enhancedText, "text/html");
30683
- const nodes = $generateNodesFromDOM(editor, dom);
30684
- currentSelection.insertText("");
30685
- $insertNodes(nodes);
30686
- });
30687
- toast.success("Text inserted successfully!");
30688
- });
30689
- });
30690
- return true;
30691
- };
30692
- useEffect$1(() => {
30693
- return editor.registerCommand(
30694
- TEXT_ENHANCE_COMMAND,
30695
- (selectedText) => {
30696
- handleOpenDialog(selectedText);
30697
- return true;
30698
- },
30699
- COMMAND_PRIORITY_LOW
30700
- );
30701
- }, [editor]);
30702
- return /* @__PURE__ */ jsx(
30703
- TextEnhanceDialog,
30704
- {
30705
- ref: enhanceDialogRef,
30706
- onEnhance: handleTextEnhancement
30707
- }
30708
- );
30709
- };
30710
- function FloatingEnhanceButton({
30711
- anchorElem
30712
- }) {
30713
- const [editor] = useLexicalComposerContext();
30714
- const enhanceButtonRef = useRef(null);
30715
- const [isVisible, setIsVisible] = useState$1(false);
30716
- const updateButtonPosition = useCallback(() => {
30717
- const selection = $getSelection();
30718
- const buttonElem = enhanceButtonRef.current;
30719
- const nativeSelection = getDOMSelection(editor._window);
30720
- if (buttonElem === null) {
30721
- return;
30722
- }
30723
- const rootElement = editor.getRootElement();
30724
- if (selection !== null && nativeSelection !== null && !nativeSelection.isCollapsed && rootElement !== null && rootElement.contains(nativeSelection.anchorNode)) {
30725
- const rangeRect = getDOMRangeRect(nativeSelection, rootElement);
30726
- if (rangeRect) {
30727
- const BUTTON_WIDTH = 32;
30728
- const BUTTON_HEIGHT = 32;
30729
- const SPACING = 8;
30730
- const TOOLBAR_HEIGHT = 40;
30731
- const viewportWidth = window.innerWidth;
30732
- const rightPosition = rangeRect.right + anchorElem.offsetLeft + SPACING;
30733
- const hasSpaceOnRight = rightPosition + BUTTON_WIDTH + 20 < viewportWidth;
30734
- let top;
30735
- let left;
30736
- if (hasSpaceOnRight) {
30737
- top = rangeRect.top + anchorElem.offsetTop + rangeRect.height / 2 - BUTTON_HEIGHT / 2;
30738
- left = rightPosition;
30739
- } else {
30740
- top = rangeRect.top + anchorElem.offsetTop - BUTTON_HEIGHT - SPACING - TOOLBAR_HEIGHT;
30741
- left = rangeRect.left + anchorElem.offsetLeft + rangeRect.width / 2 - BUTTON_WIDTH / 2;
30742
- if (left < 10) {
30743
- left = 10;
30744
- }
30745
- if (left + BUTTON_WIDTH > viewportWidth - 10) {
30746
- left = viewportWidth - BUTTON_WIDTH - 10;
30747
- }
30748
- if (top < 10) {
30749
- top = rangeRect.bottom + anchorElem.offsetTop + SPACING;
30750
- }
30751
- }
30752
- buttonElem.style.opacity = "1";
30753
- buttonElem.style.top = `${top}px`;
30754
- buttonElem.style.left = `${left}px`;
30755
- setIsVisible(true);
30756
- }
30757
- } else {
30758
- buttonElem.style.opacity = "0";
30759
- buttonElem.style.top = "-10000px";
30760
- buttonElem.style.left = "-10000px";
30761
- setIsVisible(false);
30762
- }
30763
- }, [editor, anchorElem]);
30764
- useEffect$1(() => {
30765
- const scrollerElem = anchorElem.parentElement;
30766
- const update = () => {
30767
- editor.getEditorState().read(() => {
30768
- updateButtonPosition();
30769
- });
30770
- };
30771
- window.addEventListener("resize", update);
30772
- if (scrollerElem) {
30773
- scrollerElem.addEventListener("scroll", update);
30774
- }
30775
- return () => {
30776
- window.removeEventListener("resize", update);
30777
- if (scrollerElem) {
30778
- scrollerElem.removeEventListener("scroll", update);
30779
- }
30780
- };
30781
- }, [editor, updateButtonPosition, anchorElem]);
30782
- useEffect$1(() => {
30783
- editor.getEditorState().read(() => {
30784
- updateButtonPosition();
30785
- });
30786
- return mergeRegister(
30787
- editor.registerUpdateListener(({ editorState }) => {
30788
- editorState.read(() => {
30789
- updateButtonPosition();
30790
- });
30791
- }),
30792
- editor.registerCommand(
30793
- SELECTION_CHANGE_COMMAND,
30794
- () => {
30795
- updateButtonPosition();
30796
- return false;
30797
- },
30798
- COMMAND_PRIORITY_LOW
30799
- )
30800
- );
30801
- }, [editor, updateButtonPosition]);
30802
- const handleClick = () => {
30803
- editor.dispatchCommand(TEXT_ENHANCE_COMMAND, void 0);
30804
- };
30805
- return /* @__PURE__ */ jsxs(
30806
- "button",
30807
- {
30808
- ref: enhanceButtonRef,
30809
- className: "floating-enhance-button",
30810
- onClick: handleClick,
30811
- title: "Enhance Text with AI",
30812
- "aria-label": "Enhance Text with AI",
30813
- children: [
30814
- /* @__PURE__ */ jsx(SparkleIcon, {}),
30815
- /* @__PURE__ */ jsx("span", { className: "floating-enhance-button-tooltip", children: "Enhance with AI" })
30816
- ]
30817
- }
30818
- );
30819
- }
30820
- function FloatingEnhanceButtonPlugin({
30821
- anchorElem = document.body
30822
- }) {
30823
- const [editor] = useLexicalComposerContext();
30824
- const [isText, setIsText] = useState$1(false);
30825
- useEffect$1(() => {
30826
- const updateTextSelection = () => {
30827
- editor.getEditorState().read(() => {
30828
- if (editor.isComposing()) {
30829
- return;
30830
- }
30831
- const selection = $getSelection();
30832
- const nativeSelection = getDOMSelection(editor._window);
30833
- const rootElement = editor.getRootElement();
30834
- if (nativeSelection !== null && (!$isRangeSelection(selection) || rootElement === null || !rootElement.contains(nativeSelection.anchorNode))) {
30835
- setIsText(false);
30836
- return;
30837
- }
30838
- if (!$isRangeSelection(selection)) {
30839
- return;
30840
- }
30841
- const textContent = selection.getTextContent();
30842
- if (!selection.isCollapsed() && textContent.trim() !== "") {
30843
- setIsText(true);
30844
- } else {
30845
- setIsText(false);
30846
- }
30847
- });
30848
- };
30849
- document.addEventListener("selectionchange", updateTextSelection);
30850
- return () => {
30851
- document.removeEventListener("selectionchange", updateTextSelection);
30852
- };
30853
- }, [editor]);
30854
- useEffect$1(() => {
30855
- return mergeRegister(
30856
- editor.registerUpdateListener(() => {
30857
- editor.getEditorState().read(() => {
30858
- const selection = $getSelection();
30859
- const nativeSelection = getDOMSelection(editor._window);
30860
- const rootElement = editor.getRootElement();
30861
- if (nativeSelection !== null && $isRangeSelection(selection) && rootElement !== null && rootElement.contains(nativeSelection.anchorNode)) {
30862
- const textContent = selection.getTextContent();
30863
- setIsText(!selection.isCollapsed() && textContent.trim() !== "");
30864
- } else {
30865
- setIsText(false);
30866
- }
30867
- });
30868
- }),
30869
- editor.registerRootListener(() => {
30870
- if (editor.getRootElement() === null) {
30871
- setIsText(false);
30872
- }
30873
- })
30874
- );
30875
- }, [editor]);
30876
- if (!isText) {
30877
- return null;
30878
- }
30879
- return createPortal(
30880
- /* @__PURE__ */ jsx(FloatingEnhanceButton, { anchorElem }),
30881
- anchorElem
30882
- );
30883
- }
30884
31060
  const index$4 = "";
30885
31061
  const VERTICAL_GAP$1 = 10;
30886
31062
  const HORIZONTAL_OFFSET$1 = 5;
@@ -31328,6 +31504,20 @@ function FloatingLinkEditorPlugin({
31328
31504
  );
31329
31505
  }
31330
31506
  const index$3 = "";
31507
+ function getDOMRangeRect(nativeSelection, rootElement) {
31508
+ const domRange = nativeSelection.getRangeAt(0);
31509
+ let rect;
31510
+ if (nativeSelection.anchorNode === rootElement) {
31511
+ let inner = rootElement;
31512
+ while (inner.firstElementChild != null) {
31513
+ inner = inner.firstElementChild;
31514
+ }
31515
+ rect = inner.getBoundingClientRect();
31516
+ } else {
31517
+ rect = domRange.getBoundingClientRect();
31518
+ }
31519
+ return rect;
31520
+ }
31331
31521
  const VERTICAL_GAP = 10;
31332
31522
  const HORIZONTAL_OFFSET = 5;
31333
31523
  function setFloatingElemPosition(targetRect, floatingElem, anchorElem, isLink = false, verticalGap = VERTICAL_GAP, horizontalOffset = HORIZONTAL_OFFSET, isEmbed = false) {
@@ -31386,6 +31576,227 @@ function setFloatingElemPosition(targetRect, floatingElem, anchorElem, isLink =
31386
31576
  floatingElem.style.opacity = "1";
31387
31577
  floatingElem.style.transform = `translate(${left}px, ${top}px)`;
31388
31578
  }
31579
+ const TextEnhanceDialog = forwardRef(
31580
+ ({ onEnhance }, ref) => {
31581
+ const [isOpen, setIsOpen] = useState$1(false);
31582
+ const [selectedText, setSelectedText] = useState$1("");
31583
+ const [userPrompt, setUserPrompt] = useState$1("");
31584
+ const [enhancedText, setEnhancedText] = useState$1("");
31585
+ const [isLoading, setIsLoading] = useState$1(false);
31586
+ const [showResult, setShowResult] = useState$1(false);
31587
+ const [onInsertCallback, setOnInsertCallback] = useState$1(null);
31588
+ useImperativeHandle(ref, () => ({
31589
+ openDialog: (text, insertCallback) => {
31590
+ setSelectedText(text);
31591
+ setUserPrompt("");
31592
+ setEnhancedText("");
31593
+ setShowResult(false);
31594
+ setOnInsertCallback(() => insertCallback);
31595
+ setIsOpen(true);
31596
+ },
31597
+ closeDialog: () => {
31598
+ setIsOpen(false);
31599
+ setTimeout(() => {
31600
+ setSelectedText("");
31601
+ setUserPrompt("");
31602
+ setEnhancedText("");
31603
+ setShowResult(false);
31604
+ setOnInsertCallback(null);
31605
+ }, 300);
31606
+ }
31607
+ }));
31608
+ const handleClose = () => {
31609
+ setIsOpen(false);
31610
+ setTimeout(() => {
31611
+ setSelectedText("");
31612
+ setUserPrompt("");
31613
+ setEnhancedText("");
31614
+ setShowResult(false);
31615
+ setOnInsertCallback(null);
31616
+ }, 300);
31617
+ };
31618
+ const handleEnhance = async () => {
31619
+ if (!userPrompt.trim())
31620
+ return;
31621
+ setIsLoading(true);
31622
+ try {
31623
+ const result = await onEnhance(selectedText, userPrompt);
31624
+ setEnhancedText(result);
31625
+ setShowResult(true);
31626
+ } catch (error) {
31627
+ console.error("Enhancement error:", error);
31628
+ } finally {
31629
+ setIsLoading(false);
31630
+ }
31631
+ };
31632
+ const handleInsert = () => {
31633
+ if (onInsertCallback && enhancedText) {
31634
+ onInsertCallback(enhancedText);
31635
+ }
31636
+ handleClose();
31637
+ };
31638
+ return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:cteditor-max-w-[500px] cteditor-max-h-[650px]", children: [
31639
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
31640
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: [
31641
+ /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-size-5" }),
31642
+ "Enhance Text"
31643
+ ] }),
31644
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Enhance your selected text with AI assistance." })
31645
+ ] }),
31646
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-4 cteditor-overflow-y-auto cteditor-max-h-[400px] cteditor-pr-2", children: [
31647
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-1.5", children: [
31648
+ /* @__PURE__ */ jsx("label", { className: "cteditor-text-xs cteditor-font-medium cteditor-text-foreground", children: "Selected Text" }),
31649
+ /* @__PURE__ */ jsx("div", { className: "cteditor-p-3 cteditor-bg-accent/50 cteditor-rounded-lg cteditor-border cteditor-border-border cteditor-max-h-24 cteditor-overflow-y-auto", children: /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-text-foreground cteditor-leading-relaxed", children: selectedText }) })
31650
+ ] }),
31651
+ !showResult && /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-1.5", children: [
31652
+ /* @__PURE__ */ jsx("label", { className: "cteditor-text-xs cteditor-font-medium cteditor-text-foreground", children: "How to enhance?" }),
31653
+ /* @__PURE__ */ jsx(
31654
+ "textarea",
31655
+ {
31656
+ value: userPrompt,
31657
+ onChange: (e) => setUserPrompt(e.target.value),
31658
+ placeholder: "E.g., Make it professional, Add details, Simplify...",
31659
+ className: "cteditor-w-full cteditor-h-20 cteditor-p-3 cteditor-bg-background cteditor-rounded-lg cteditor-border cteditor-border-border focus:cteditor-border-foreground cteditor-outline-none cteditor-text-sm cteditor-text-foreground cteditor-placeholder-muted-foreground cteditor-resize-none",
31660
+ disabled: isLoading,
31661
+ onKeyDown: (e) => {
31662
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
31663
+ handleEnhance();
31664
+ }
31665
+ }
31666
+ }
31667
+ ),
31668
+ /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-text-muted-foreground", children: "Ctrl+Enter to enhance" })
31669
+ ] }),
31670
+ isLoading && /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-flex-col cteditor-items-center cteditor-justify-center cteditor-py-0 cteditor-space-y-3", children: [
31671
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-relative cteditor-w-14 cteditor-h-14", children: [
31672
+ /* @__PURE__ */ jsx(
31673
+ "div",
31674
+ {
31675
+ className: "cteditor-absolute cteditor-inset-0 cteditor-rounded-full cteditor-opacity-75",
31676
+ style: {
31677
+ background: "linear-gradient(to right, #a855f7, #ec4899, #a855f7)",
31678
+ animation: "spin 2s linear infinite",
31679
+ padding: "2px",
31680
+ WebkitMask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
31681
+ WebkitMaskComposite: "xor",
31682
+ maskComposite: "exclude"
31683
+ }
31684
+ }
31685
+ ),
31686
+ /* @__PURE__ */ jsx("div", { className: "cteditor-absolute cteditor-inset-0 cteditor-rounded-full cteditor-bg-background cteditor-flex cteditor-items-center cteditor-justify-center cteditor-m-[2px]", children: /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-w-6 cteditor-h-6 cteditor-text-purple-500 cteditor-animate-pulse" }) })
31687
+ ] }),
31688
+ /* @__PURE__ */ jsx("div", { className: "cteditor-text-center", children: /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-font-medium cteditor-text-foreground", children: "Enhancing text..." }) })
31689
+ ] }),
31690
+ showResult && !isLoading && /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-1.5 cteditor-animate-in cteditor-fade-in cteditor-slide-in-from-bottom-4", children: [
31691
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-1.5", children: [
31692
+ /* @__PURE__ */ jsx(Check, { className: "cteditor-w-3.5 cteditor-h-3.5 cteditor-text-green-500" }),
31693
+ /* @__PURE__ */ jsx("label", { className: "cteditor-text-xs cteditor-font-medium cteditor-text-foreground", children: "Enhanced Text" })
31694
+ ] }),
31695
+ /* @__PURE__ */ jsx("div", { className: "cteditor-p-3 cteditor-bg-gradient-to-br cteditor-from-purple-500/5 cteditor-to-pink-500/5 cteditor-rounded-lg cteditor-border cteditor-border-purple-500/20 cteditor-max-h-48 cteditor-overflow-y-auto", children: /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-text-foreground cteditor-leading-relaxed", children: enhancedText }) })
31696
+ ] })
31697
+ ] }),
31698
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
31699
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClose, children: "Cancel" }),
31700
+ !showResult && /* @__PURE__ */ jsxs(
31701
+ Button,
31702
+ {
31703
+ onClick: handleEnhance,
31704
+ disabled: !userPrompt.trim() || isLoading,
31705
+ className: "cteditor-gap-2",
31706
+ children: [
31707
+ /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-size-5" }),
31708
+ "Enhance"
31709
+ ]
31710
+ }
31711
+ ),
31712
+ showResult && /* @__PURE__ */ jsxs(
31713
+ Button,
31714
+ {
31715
+ onClick: handleInsert,
31716
+ className: "cteditor-gap-2",
31717
+ children: [
31718
+ "Insert",
31719
+ /* @__PURE__ */ jsx(ArrowRight, { className: "cteditor-size-5" })
31720
+ ]
31721
+ }
31722
+ )
31723
+ ] })
31724
+ ] }) });
31725
+ }
31726
+ );
31727
+ TextEnhanceDialog.displayName = "TextEnhanceDialog";
31728
+ const TEXT_ENHANCE_COMMAND = createCommand("TEXT_ENHANCE_COMMAND");
31729
+ const TextEnhancePlugin = ({ apiKey }) => {
31730
+ const [editor] = useLexicalComposerContext();
31731
+ const enhanceDialogRef = useRef(null);
31732
+ const handleTextEnhancement = async (selectedText, userPrompt) => {
31733
+ try {
31734
+ const prompt = `Enhance the following text based on this instruction: "${userPrompt}"
31735
+
31736
+ Original text:
31737
+ "${selectedText}"
31738
+
31739
+ Provide only the enhanced text without any additional explanation.`;
31740
+ const response = await AiTextEnhance({ content: prompt, apiKey });
31741
+ if (!response.data) {
31742
+ throw new Error("No response received from AI");
31743
+ }
31744
+ return response.data;
31745
+ } catch (error) {
31746
+ console.error("Error enhancing text:", error);
31747
+ toast.error("Enhancement failed", {
31748
+ description: error instanceof Error ? error.message : "An error occurred"
31749
+ });
31750
+ throw error;
31751
+ }
31752
+ };
31753
+ const handleOpenDialog = (selectedText) => {
31754
+ editor.getEditorState().read(() => {
31755
+ var _a;
31756
+ const selection = $getSelection();
31757
+ if (!$isRangeSelection(selection))
31758
+ return;
31759
+ const text = selectedText || selection.getTextContent().trim();
31760
+ if (!text) {
31761
+ toast.error("No text selected", {
31762
+ description: "Please select some text to enhance"
31763
+ });
31764
+ return;
31765
+ }
31766
+ (_a = enhanceDialogRef.current) == null ? void 0 : _a.openDialog(text, (enhancedText) => {
31767
+ editor.update(() => {
31768
+ const currentSelection = $getSelection();
31769
+ if (!currentSelection || !$isRangeSelection(currentSelection))
31770
+ return;
31771
+ const parser = new DOMParser();
31772
+ const dom = parser.parseFromString(enhancedText, "text/html");
31773
+ const nodes = $generateNodesFromDOM(editor, dom);
31774
+ currentSelection.insertText("");
31775
+ $insertNodes(nodes);
31776
+ });
31777
+ toast.success("Text inserted successfully!");
31778
+ });
31779
+ });
31780
+ return true;
31781
+ };
31782
+ useEffect$1(() => {
31783
+ return editor.registerCommand(
31784
+ TEXT_ENHANCE_COMMAND,
31785
+ (selectedText) => {
31786
+ handleOpenDialog(selectedText);
31787
+ return true;
31788
+ },
31789
+ COMMAND_PRIORITY_LOW
31790
+ );
31791
+ }, [editor]);
31792
+ return /* @__PURE__ */ jsx(
31793
+ TextEnhanceDialog,
31794
+ {
31795
+ ref: enhanceDialogRef,
31796
+ onEnhance: handleTextEnhancement
31797
+ }
31798
+ );
31799
+ };
31389
31800
  const DropdownMenu = ({ children, trigger }) => {
31390
31801
  const [isOpen, setIsOpen] = useState$1(false);
31391
31802
  const dropdownRef = useRef(null);
@@ -31655,6 +32066,26 @@ function TextFormatFloatingToolbar({
31655
32066
  ]
31656
32067
  }
31657
32068
  ),
32069
+ /* @__PURE__ */ jsxs(
32070
+ DropdownMenuItem,
32071
+ {
32072
+ onClick: () => {
32073
+ editor.getEditorState().read(() => {
32074
+ const selection = $getSelection();
32075
+ if ($isRangeSelection(selection)) {
32076
+ const selectedText = selection.getTextContent();
32077
+ editor.dispatchCommand(TEXT_ENHANCE_COMMAND, selectedText || void 0);
32078
+ } else {
32079
+ editor.dispatchCommand(TEXT_ENHANCE_COMMAND, void 0);
32080
+ }
32081
+ });
32082
+ },
32083
+ children: [
32084
+ /* @__PURE__ */ jsx("div", { className: "cteditor-w-5 cteditor-h-5 cteditor-flex cteditor-items-center cteditor-justify-center", children: /* @__PURE__ */ jsx(SparkleIcon, {}) }),
32085
+ /* @__PURE__ */ jsx("span", { children: "Enhance with AI" })
32086
+ ]
32087
+ }
32088
+ ),
31658
32089
  /* @__PURE__ */ jsxs(
31659
32090
  DropdownMenuItem,
31660
32091
  {
@@ -32081,50 +32512,6 @@ function LinkPlugin({
32081
32512
  }
32082
32513
  );
32083
32514
  }
32084
- const cache = /* @__PURE__ */ new Map();
32085
- const CACHE_TTL = 30 * 60 * 1e3;
32086
- const MAX_CACHE_SIZE = 100;
32087
- function getCached(url) {
32088
- const entry = cache.get(url);
32089
- if (!entry)
32090
- return null;
32091
- if (Date.now() - entry.timestamp > CACHE_TTL) {
32092
- cache.delete(url);
32093
- return null;
32094
- }
32095
- return entry.data;
32096
- }
32097
- function setCache(url, data) {
32098
- if (cache.size >= MAX_CACHE_SIZE) {
32099
- const oldestKey = cache.keys().next().value;
32100
- if (oldestKey)
32101
- cache.delete(oldestKey);
32102
- }
32103
- cache.set(url, { data, timestamp: Date.now() });
32104
- }
32105
- async function fetchLinkPreview({
32106
- url,
32107
- apiKey
32108
- }) {
32109
- const cached = getCached(url);
32110
- if (cached)
32111
- return cached;
32112
- try {
32113
- const response = await backendAPI.post(
32114
- apiEndpoints.linkPreview.getPreview,
32115
- { url },
32116
- apiKey ? { headers: { "X-API-Key": apiKey } } : void 0
32117
- );
32118
- if (response.data.success && response.data.data) {
32119
- setCache(url, response.data.data);
32120
- return response.data.data;
32121
- }
32122
- return null;
32123
- } catch (error) {
32124
- console.error("Error fetching link preview:", error);
32125
- return null;
32126
- }
32127
- }
32128
32515
  function LinkPreviewPlugin({ apiKey }) {
32129
32516
  const [editor] = useLexicalComposerContext();
32130
32517
  const [hoveredLink, setHoveredLink] = useState$1(null);
@@ -32282,7 +32669,7 @@ function LinkPreview({ url, rect, apiKey, onClose }) {
32282
32669
  }
32283
32670
  };
32284
32671
  const domain = getDomain(url);
32285
- const TypeIcon = ({ type }) => {
32672
+ const TypeIcon2 = ({ type }) => {
32286
32673
  const iconProps = { style: { width: "14px", height: "14px" }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" };
32287
32674
  const pathProps = { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2 };
32288
32675
  switch (type) {
@@ -32392,7 +32779,7 @@ function LinkPreview({ url, rect, apiKey, onClose }) {
32392
32779
  e.currentTarget.style.display = "none";
32393
32780
  }
32394
32781
  }
32395
- ) : /* @__PURE__ */ jsx("span", { style: { color: "#888" }, children: /* @__PURE__ */ jsx(TypeIcon, { type: previewData.type }) }),
32782
+ ) : /* @__PURE__ */ jsx("span", { style: { color: "#888" }, children: /* @__PURE__ */ jsx(TypeIcon2, { type: previewData.type }) }),
32396
32783
  /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#888", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: previewData.siteName || domain }),
32397
32784
  /* @__PURE__ */ jsx("span", { style: {
32398
32785
  fontSize: "10px",
@@ -35271,6 +35658,8 @@ function getOptionMeta(label) {
35271
35658
  return { icon: /* @__PURE__ */ jsx(Quote, { className: "cteditor-size-4" }), description: "Insert a quote block" };
35272
35659
  if (lower.includes("code block"))
35273
35660
  return { icon: /* @__PURE__ */ jsx(Code, { className: "cteditor-size-4" }), description: "Insert a code block" };
35661
+ if (lower.includes("horizontal") || lower.includes("divider"))
35662
+ return { icon: /* @__PURE__ */ jsx(Minus, { className: "cteditor-size-4" }), description: "Insert horizontal line" };
35274
35663
  if (lower.includes("bullet"))
35275
35664
  return { icon: /* @__PURE__ */ jsx(List$1, { className: "cteditor-size-4" }), description: "Create a bulleted list", shortcut: "•" };
35276
35665
  if (lower.includes("numbered"))
@@ -35283,6 +35672,8 @@ function getOptionMeta(label) {
35283
35672
  return { icon: /* @__PURE__ */ jsx(Video, { className: "cteditor-size-4" }), description: "Embed a video", shortcut: "Vid" };
35284
35673
  if (lower.includes("table"))
35285
35674
  return { icon: /* @__PURE__ */ jsx(Table, { className: "cteditor-size-4" }), description: "Insert a table" };
35675
+ if (lower.includes("chart"))
35676
+ return { icon: /* @__PURE__ */ jsx(BarChart3, { className: "cteditor-size-4" }), description: "Insert a chart" };
35286
35677
  if (lower.includes("bold"))
35287
35678
  return { icon: /* @__PURE__ */ jsx(Bold, { className: "cteditor-size-4" }), description: "Make text bold" };
35288
35679
  if (lower.includes("italic"))
@@ -35295,6 +35686,8 @@ function getOptionMeta(label) {
35295
35686
  return { icon: /* @__PURE__ */ jsx(Subscript, { className: "cteditor-size-4" }), description: "Format as subscript" };
35296
35687
  if (lower.includes("superscript"))
35297
35688
  return { icon: /* @__PURE__ */ jsx(Superscript, { className: "cteditor-size-4" }), description: "Format as superscript" };
35689
+ if (lower.includes("signature"))
35690
+ return { icon: /* @__PURE__ */ jsx(PenTool, { className: "cteditor-size-4" }), description: "Add your signature" };
35298
35691
  if (lower.includes("align left"))
35299
35692
  return { icon: /* @__PURE__ */ jsx(AlignLeft, { className: "cteditor-size-4" }), description: "Align text left" };
35300
35693
  if (lower.includes("align center"))
@@ -35303,30 +35696,26 @@ function getOptionMeta(label) {
35303
35696
  return { icon: /* @__PURE__ */ jsx(AlignRight, { className: "cteditor-size-4" }), description: "Align text right" };
35304
35697
  if (lower.includes("justify"))
35305
35698
  return { icon: /* @__PURE__ */ jsx(AlignJustify, { className: "cteditor-size-4" }), description: "Justify text" };
35306
- if (lower.includes("info"))
35699
+ if (lower.includes("info panel"))
35307
35700
  return { icon: /* @__PURE__ */ jsx(Info, { className: "cteditor-size-4" }), description: "Insert info panel" };
35308
- if (lower.includes("warning"))
35701
+ if (lower.includes("warning panel"))
35309
35702
  return { icon: /* @__PURE__ */ jsx(AlertTriangle, { className: "cteditor-size-4" }), description: "Insert warning panel" };
35310
- if (lower.includes("error"))
35703
+ if (lower.includes("error panel"))
35311
35704
  return { icon: /* @__PURE__ */ jsx(XCircle, { className: "cteditor-size-4" }), description: "Insert error panel" };
35312
- if (lower.includes("success"))
35705
+ if (lower.includes("success panel"))
35313
35706
  return { icon: /* @__PURE__ */ jsx(CheckCircle, { className: "cteditor-size-4" }), description: "Insert success panel" };
35314
35707
  if (lower.includes("undo"))
35315
35708
  return { icon: /* @__PURE__ */ jsx(Undo, { className: "cteditor-size-4" }), description: "Undo last action" };
35316
35709
  if (lower.includes("redo"))
35317
35710
  return { icon: /* @__PURE__ */ jsx(Redo, { className: "cteditor-size-4" }), description: "Redo last action" };
35318
- if (lower.includes("clear"))
35319
- return { icon: /* @__PURE__ */ jsx(Eraser, { className: "cteditor-size-4" }), description: "Clear formatting" };
35320
- if (lower.includes("comment"))
35321
- return { icon: /* @__PURE__ */ jsx(MessageSquare, { className: "cteditor-size-4" }), description: "Add a comment" };
35322
35711
  if (lower.includes("ai chat"))
35323
35712
  return { icon: /* @__PURE__ */ jsx(MessageCircle, { className: "cteditor-size-4" }), description: "Open AI chat" };
35324
35713
  if (lower.includes("ai") || lower.includes("improve"))
35325
35714
  return { icon: /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-size-4" }), description: "AI improvements" };
35326
- if (lower.includes("html"))
35327
- return { icon: /* @__PURE__ */ jsx(FileCode2, { className: "cteditor-size-4" }), description: "Toggle HTML view" };
35328
- if (lower.includes("pdf") || lower.includes("export"))
35329
- return { icon: /* @__PURE__ */ jsx(Download, { className: "cteditor-size-4" }), description: "Export to PDF" };
35715
+ if (lower.includes("autocomplete") || lower.includes("grammar"))
35716
+ return { icon: /* @__PURE__ */ jsx(SpellCheck, { className: "cteditor-size-4" }), description: "Toggle grammar & autocomplete" };
35717
+ if (lower.includes("html") || lower.includes("source"))
35718
+ return { icon: /* @__PURE__ */ jsx(FileCode2, { className: "cteditor-size-4" }), description: "Switch to HTML view" };
35330
35719
  return { icon: /* @__PURE__ */ jsx(ParagraphIcon, {}) };
35331
35720
  }
35332
35721
  class SlashMenuOption extends MenuOption {
@@ -35372,6 +35761,9 @@ function SlashMenuItem({
35372
35761
  }
35373
35762
  function SlashCommandPlugin() {
35374
35763
  const [editor] = useLexicalComposerContext();
35764
+ const { toolbarState, updateToolbarState } = useToolbarState();
35765
+ const { isHtmlView, setIsHtmlView } = useHtmlView();
35766
+ const { apiKey } = useEditor();
35375
35767
  const [queryString, setQueryString] = useState$1(null);
35376
35768
  const [searchQuery, setSearchQuery] = useState$1("");
35377
35769
  const searchInputRef = useRef(null);
@@ -35380,6 +35772,8 @@ function SlashCommandPlugin() {
35380
35772
  const anchorRef = useRef(null);
35381
35773
  const [isMenuOpen, setIsMenuOpen] = useState$1(false);
35382
35774
  const [showImageDialog, setShowImageDialog] = useState$1(false);
35775
+ const [showSignatureDialog, setShowSignatureDialog] = useState$1(false);
35776
+ const [showChartDialog, setShowChartDialog] = useState$1(false);
35383
35777
  const triggerFn = useBasicTypeaheadTriggerMatch("/", { minLength: 0 });
35384
35778
  useEffect$1(() => {
35385
35779
  if (!isMenuOpen) {
@@ -35456,6 +35850,30 @@ function SlashCommandPlugin() {
35456
35850
  const insertTable = useCallback(() => {
35457
35851
  editor.dispatchCommand(CREATE_TABLE_COMMAND, void 0);
35458
35852
  }, [editor]);
35853
+ const insertHorizontalRule = useCallback(() => {
35854
+ editor.dispatchCommand(INSERT_CUSTOM_HORIZONTAL_RULE_COMMAND, {
35855
+ color: "#e5e7eb",
35856
+ strokeWidth: 1
35857
+ });
35858
+ }, [editor]);
35859
+ const insertSignature = useCallback(() => {
35860
+ setShowSignatureDialog(true);
35861
+ }, []);
35862
+ const insertInfoPanel = useCallback(() => {
35863
+ editor.dispatchCommand(INSERT_NOTE_PANEL_COMMAND, { type: "info" });
35864
+ }, [editor]);
35865
+ const insertWarningPanel = useCallback(() => {
35866
+ editor.dispatchCommand(INSERT_NOTE_PANEL_COMMAND, { type: "warning" });
35867
+ }, [editor]);
35868
+ const insertErrorPanel = useCallback(() => {
35869
+ editor.dispatchCommand(INSERT_NOTE_PANEL_COMMAND, { type: "error" });
35870
+ }, [editor]);
35871
+ const insertSuccessPanel = useCallback(() => {
35872
+ editor.dispatchCommand(INSERT_NOTE_PANEL_COMMAND, { type: "success" });
35873
+ }, [editor]);
35874
+ const alignJustify = useCallback(() => {
35875
+ editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, "justify");
35876
+ }, [editor]);
35459
35877
  const formatBold = useCallback(() => {
35460
35878
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
35461
35879
  }, [editor]);
@@ -35474,40 +35892,47 @@ function SlashCommandPlugin() {
35474
35892
  const formatSuperscript = useCallback(() => {
35475
35893
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "superscript");
35476
35894
  }, [editor]);
35477
- const alignJustify = useCallback(() => {
35478
- editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, "justify");
35479
- }, [editor]);
35480
35895
  const undo = useCallback(() => {
35481
35896
  editor.dispatchCommand(UNDO_COMMAND, void 0);
35482
35897
  }, [editor]);
35483
35898
  const redo = useCallback(() => {
35484
35899
  editor.dispatchCommand(REDO_COMMAND, void 0);
35485
35900
  }, [editor]);
35486
- const { clearFormatting } = useEditorToolbar();
35487
- const { clearEditorContent } = useCustomCommands();
35488
- const handleClearFormatting = useCallback(() => {
35489
- clearFormatting();
35490
- toast.success("Formatting cleared");
35491
- }, [clearFormatting]);
35492
- const handleClearContent = useCallback(() => {
35493
- toast.warning("Clear editor content?", {
35494
- description: "This will remove all content.",
35495
- action: {
35496
- label: "OK",
35497
- onClick: () => {
35498
- clearEditorContent();
35499
- toast.success("Editor cleared");
35500
- }
35501
- },
35502
- duration: 8e3
35503
- });
35504
- }, [clearEditorContent]);
35505
- const addComment = useCallback(() => {
35506
- editor.dispatchCommand(OPEN_COMMENT_MODAL_COMMAND, void 0);
35507
- }, [editor]);
35508
35901
  const openAIChat = useCallback(() => {
35509
35902
  editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, void 0);
35510
35903
  }, [editor]);
35904
+ const insertChart = useCallback(() => {
35905
+ setShowChartDialog(true);
35906
+ }, []);
35907
+ const handleChartInsert = useCallback(
35908
+ async (metadata) => {
35909
+ const result = await generateChartWithToast(metadata, apiKey);
35910
+ if (result.success) {
35911
+ editor.update(() => {
35912
+ const chartNode = $createChartNode(result.html, metadata);
35913
+ const selection = $getSelection();
35914
+ if (!selection) {
35915
+ const root2 = $getRoot();
35916
+ root2.append(chartNode);
35917
+ } else {
35918
+ $insertNodes([chartNode]);
35919
+ }
35920
+ const paragraphNode = $createParagraphNode();
35921
+ chartNode.insertAfter(paragraphNode);
35922
+ });
35923
+ }
35924
+ },
35925
+ [editor, apiKey]
35926
+ );
35927
+ const toggleAutocomplete = useCallback(() => {
35928
+ updateToolbarState("isAutocompleteEnabled", !toolbarState.isAutocompleteEnabled);
35929
+ toast.success(
35930
+ toolbarState.isAutocompleteEnabled ? "Autocomplete & Grammar disabled" : "Autocomplete & Grammar enabled"
35931
+ );
35932
+ }, [toolbarState.isAutocompleteEnabled, updateToolbarState]);
35933
+ const switchToHtmlView = useCallback(() => {
35934
+ setIsHtmlView(!isHtmlView);
35935
+ }, [isHtmlView, setIsHtmlView]);
35511
35936
  const baseOptions = useMemo(() => {
35512
35937
  return [
35513
35938
  // Block types
@@ -35522,6 +35947,7 @@ function SlashCommandPlugin() {
35522
35947
  new SlashMenuOption("Heading 6", () => insertHeading("h6")),
35523
35948
  new SlashMenuOption("Quote", insertQuote),
35524
35949
  new SlashMenuOption("Code block", insertCodeBlock),
35950
+ new SlashMenuOption("Horizontal line", insertHorizontalRule),
35525
35951
  // Lists
35526
35952
  new SlashMenuOption("__label__LISTS", () => {
35527
35953
  }),
@@ -35534,6 +35960,22 @@ function SlashCommandPlugin() {
35534
35960
  new SlashMenuOption("Image", insertImage),
35535
35961
  new SlashMenuOption("Video", insertVideo),
35536
35962
  new SlashMenuOption("Table", insertTable),
35963
+ new SlashMenuOption("Chart", insertChart),
35964
+ new SlashMenuOption("Signature", insertSignature),
35965
+ // Note Panels
35966
+ new SlashMenuOption("__label__PANELS", () => {
35967
+ }),
35968
+ new SlashMenuOption("Info panel", insertInfoPanel),
35969
+ new SlashMenuOption("Warning panel", insertWarningPanel),
35970
+ new SlashMenuOption("Error panel", insertErrorPanel),
35971
+ new SlashMenuOption("Success panel", insertSuccessPanel),
35972
+ // Alignment
35973
+ new SlashMenuOption("__label__ALIGN", () => {
35974
+ }),
35975
+ new SlashMenuOption("Align left", () => align("left")),
35976
+ new SlashMenuOption("Align center", () => align("center")),
35977
+ new SlashMenuOption("Align right", () => align("right")),
35978
+ new SlashMenuOption("Justify", alignJustify),
35537
35979
  // Text formatting
35538
35980
  new SlashMenuOption("__label__FORMAT", () => {
35539
35981
  }),
@@ -35543,52 +35985,52 @@ function SlashCommandPlugin() {
35543
35985
  new SlashMenuOption("Strikethrough", formatStrikethrough),
35544
35986
  new SlashMenuOption("Subscript", formatSubscript),
35545
35987
  new SlashMenuOption("Superscript", formatSuperscript),
35546
- // Alignment
35547
- new SlashMenuOption("__label__ALIGN", () => {
35548
- }),
35549
- new SlashMenuOption("Align left", () => align("left")),
35550
- new SlashMenuOption("Align center", () => align("center")),
35551
- new SlashMenuOption("Align right", () => align("right")),
35552
- new SlashMenuOption("Justify", alignJustify),
35553
35988
  // Actions
35554
35989
  new SlashMenuOption("__label__ACTIONS", () => {
35555
35990
  }),
35556
35991
  new SlashMenuOption("Undo", undo),
35557
35992
  new SlashMenuOption("Redo", redo),
35558
- new SlashMenuOption("Clear formatting", handleClearFormatting),
35559
- new SlashMenuOption("Clear content", handleClearContent),
35560
- new SlashMenuOption("Add comment", addComment),
35561
35993
  // AI features
35562
35994
  new SlashMenuOption("__label__AI", () => {
35563
35995
  }),
35564
- new SlashMenuOption("AI Chat", openAIChat)
35565
- // new SlashMenuOption("AI Generate image", aiGenerateImage),
35996
+ new SlashMenuOption("AI Chat", openAIChat),
35997
+ // Tools
35998
+ new SlashMenuOption("__label__TOOLS", () => {
35999
+ }),
36000
+ new SlashMenuOption("Toggle Autocomplete", toggleAutocomplete),
36001
+ new SlashMenuOption("Switch to HTML View", switchToHtmlView)
35566
36002
  ];
35567
36003
  }, [
35568
36004
  insertParagraph,
35569
36005
  insertHeading,
35570
36006
  insertQuote,
35571
36007
  insertCodeBlock,
36008
+ insertHorizontalRule,
35572
36009
  toggleBullet,
35573
36010
  toggleNumber,
35574
36011
  toggleTodo,
35575
36012
  insertImage,
35576
36013
  insertVideo,
35577
36014
  insertTable,
36015
+ insertChart,
36016
+ insertSignature,
36017
+ insertInfoPanel,
36018
+ insertWarningPanel,
36019
+ insertErrorPanel,
36020
+ insertSuccessPanel,
36021
+ align,
36022
+ alignJustify,
35578
36023
  formatBold,
35579
36024
  formatItalic,
35580
36025
  formatUnderline,
35581
36026
  formatStrikethrough,
35582
36027
  formatSubscript,
35583
36028
  formatSuperscript,
35584
- align,
35585
- alignJustify,
35586
36029
  undo,
35587
36030
  redo,
35588
- handleClearFormatting,
35589
- handleClearContent,
35590
- addComment,
35591
- openAIChat
36031
+ openAIChat,
36032
+ toggleAutocomplete,
36033
+ switchToHtmlView
35592
36034
  ]);
35593
36035
  const options = useMemo(() => {
35594
36036
  const query = searchQuery || queryString || "";
@@ -35751,6 +36193,20 @@ function SlashCommandPlugin() {
35751
36193
  activeEditor: editor,
35752
36194
  onClose: () => setShowImageDialog(false)
35753
36195
  }
36196
+ ),
36197
+ showSignatureDialog && /* @__PURE__ */ jsx(
36198
+ SignatureCanvasDialog,
36199
+ {
36200
+ onClose: () => setShowSignatureDialog(false)
36201
+ }
36202
+ ),
36203
+ /* @__PURE__ */ jsx(
36204
+ ChartInsertDialog,
36205
+ {
36206
+ open: showChartDialog,
36207
+ onOpenChange: setShowChartDialog,
36208
+ onInsert: handleChartInsert
36209
+ }
35754
36210
  )
35755
36211
  ] });
35756
36212
  }
@@ -40809,7 +41265,7 @@ const ConfigurableEditor = ({
40809
41265
  /* @__PURE__ */ jsx(LocalStoragePlugin$1, { namespace: initialConfig.namespace }),
40810
41266
  /* @__PURE__ */ jsx(ListPlugin, {}),
40811
41267
  /* @__PURE__ */ jsx(LinkPlugin, { hasLinkAttributes: false }),
40812
- /* @__PURE__ */ jsx(LinkPreviewPlugin, {}),
41268
+ /* @__PURE__ */ jsx(LinkPreviewPlugin, { apiKey }),
40813
41269
  /* @__PURE__ */ jsx(DragDropPaste, {}),
40814
41270
  /* @__PURE__ */ jsx(RichTextPastePlugin, {}),
40815
41271
  /* @__PURE__ */ jsx(PasteOptionsPlugin, {}),
@@ -40857,12 +41313,6 @@ const ConfigurableEditor = ({
40857
41313
  setIsLinkEditMode,
40858
41314
  features: config.floatingMenuOptions
40859
41315
  }
40860
- ),
40861
- /* @__PURE__ */ jsx(
40862
- FloatingEnhanceButtonPlugin,
40863
- {
40864
- anchorElem: floatingAnchorElem
40865
- }
40866
41316
  )
40867
41317
  ] })
40868
41318
  ] }) }),
@@ -40928,7 +41378,11 @@ const ConfigurableEditorWithAuth = ({
40928
41378
  onEditorReady,
40929
41379
  onFocus,
40930
41380
  onBlur,
40931
- onHeightChange
41381
+ onHeightChange,
41382
+ mode = "edit",
41383
+ previewClassName = "",
41384
+ previewStyle,
41385
+ onPreviewClick
40932
41386
  }) => {
40933
41387
  const { isAuthenticated, isLoading, error, editorConfig: editorConfig2, currentUser, verifyKey } = useEditor();
40934
41388
  const successRef = useRef(onAuthSuccess);
@@ -41010,6 +41464,19 @@ const ConfigurableEditorWithAuth = ({
41010
41464
  if (!isAuthenticated || !editorConfig2) {
41011
41465
  return /* @__PURE__ */ jsx(ScopedEditorWrapper, { children: /* @__PURE__ */ jsx(AuthMessage, { children: /* @__PURE__ */ jsx("span", { children: "Please provide a valid API key to access the editor" }) }) });
41012
41466
  }
41467
+ if (mode === "preview") {
41468
+ return /* @__PURE__ */ jsx(ScopedEditorWrapper, { children: /* @__PURE__ */ jsx(
41469
+ "div",
41470
+ {
41471
+ className: previewClassName,
41472
+ style: previewStyle,
41473
+ onClick: onPreviewClick,
41474
+ dangerouslySetInnerHTML: {
41475
+ __html: initialContent || ""
41476
+ }
41477
+ }
41478
+ ) });
41479
+ }
41013
41480
  return /* @__PURE__ */ jsx(ScopedEditorWrapper, { children: /* @__PURE__ */ jsx(
41014
41481
  ConfigurableEditor,
41015
41482
  {
@@ -41026,6 +41493,25 @@ const ConfigurableEditorWithAuth = ({
41026
41493
  }
41027
41494
  ) });
41028
41495
  };
41496
+ function ContentPreview({
41497
+ content,
41498
+ className = "",
41499
+ style,
41500
+ onClick
41501
+ }) {
41502
+ const defaultContent = "<p class='text-muted-foreground italic'>No content</p>";
41503
+ return /* @__PURE__ */ jsx(
41504
+ "div",
41505
+ {
41506
+ className,
41507
+ style,
41508
+ onClick,
41509
+ dangerouslySetInnerHTML: {
41510
+ __html: content || defaultContent
41511
+ }
41512
+ }
41513
+ );
41514
+ }
41029
41515
  export {
41030
41516
  $isFileNode as $,
41031
41517
  AlignLeft as A,
@@ -41056,11 +41542,13 @@ export {
41056
41542
  EditorProvider as p,
41057
41543
  useEditor as q,
41058
41544
  ConfigurableEditor as r,
41059
- isReactNativeWebView as s,
41545
+ LinkPreviewHover as s,
41060
41546
  toast as t,
41061
41547
  useHtmlView as u,
41062
41548
  verifyApiKey as v,
41063
- useReactNativeBridge as w,
41064
- editorConfig as x
41549
+ ContentPreview as w,
41550
+ isReactNativeWebView as x,
41551
+ useReactNativeBridge as y,
41552
+ editorConfig as z
41065
41553
  };
41066
- //# sourceMappingURL=index-455942f2.js.map
41554
+ //# sourceMappingURL=index-0bc350db.js.map