@moontra/moonui-pro 2.8.8 → 2.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +129 -40
- package/package.json +1 -1
- package/src/components/rich-text-editor/index.tsx +143 -41
package/dist/index.mjs
CHANGED
|
@@ -50379,13 +50379,7 @@ function RichTextEditor({
|
|
|
50379
50379
|
color: true,
|
|
50380
50380
|
ai: true
|
|
50381
50381
|
},
|
|
50382
|
-
aiConfig = {
|
|
50383
|
-
provider: "openai",
|
|
50384
|
-
apiKey: "",
|
|
50385
|
-
model: "gpt-3.5-turbo",
|
|
50386
|
-
temperature: 0.7,
|
|
50387
|
-
maxTokens: 1e3
|
|
50388
|
-
},
|
|
50382
|
+
aiConfig = {},
|
|
50389
50383
|
persistAISettings = true
|
|
50390
50384
|
}) {
|
|
50391
50385
|
const { hasProAccess, isLoading } = useSubscription();
|
|
@@ -50406,30 +50400,40 @@ function RichTextEditor({
|
|
|
50406
50400
|
if (persistAISettings && typeof window !== "undefined") {
|
|
50407
50401
|
try {
|
|
50408
50402
|
const stored = localStorage.getItem("moonui-ai-settings");
|
|
50403
|
+
console.log("[RichTextEditor] Loading AI settings from localStorage:", stored);
|
|
50409
50404
|
if (stored) {
|
|
50410
50405
|
const parsed = JSON.parse(stored);
|
|
50411
|
-
|
|
50412
|
-
|
|
50413
|
-
|
|
50414
|
-
|
|
50415
|
-
|
|
50416
|
-
|
|
50406
|
+
console.log("[RichTextEditor] Parsed AI settings:", parsed);
|
|
50407
|
+
const settings = {
|
|
50408
|
+
provider: aiConfig.provider !== void 0 ? aiConfig.provider : parsed.provider || "openai",
|
|
50409
|
+
apiKey: aiConfig.apiKey !== void 0 ? aiConfig.apiKey : parsed.apiKey || "",
|
|
50410
|
+
model: aiConfig.model !== void 0 ? aiConfig.model : parsed.model || "gpt-3.5-turbo",
|
|
50411
|
+
temperature: aiConfig.temperature !== void 0 ? aiConfig.temperature : parsed.temperature ?? 0.7,
|
|
50412
|
+
maxTokens: aiConfig.maxTokens !== void 0 ? aiConfig.maxTokens : parsed.maxTokens ?? 1e3
|
|
50417
50413
|
};
|
|
50414
|
+
console.log("[RichTextEditor] Final settings with props override:", settings);
|
|
50415
|
+
return settings;
|
|
50418
50416
|
}
|
|
50419
50417
|
} catch (e) {
|
|
50420
50418
|
console.error("Failed to load AI settings from localStorage:", e);
|
|
50421
50419
|
}
|
|
50422
50420
|
}
|
|
50423
|
-
|
|
50421
|
+
const defaultSettings = {
|
|
50424
50422
|
provider: aiConfig.provider || "openai",
|
|
50425
50423
|
apiKey: aiConfig.apiKey || "",
|
|
50426
50424
|
model: aiConfig.model || "gpt-3.5-turbo",
|
|
50427
50425
|
temperature: aiConfig.temperature ?? 0.7,
|
|
50428
50426
|
maxTokens: aiConfig.maxTokens ?? 1e3
|
|
50429
50427
|
};
|
|
50428
|
+
console.log("[RichTextEditor] Using default settings:", defaultSettings);
|
|
50429
|
+
return defaultSettings;
|
|
50430
50430
|
});
|
|
50431
50431
|
const [isAiSettingsOpen, setIsAiSettingsOpen] = useState(false);
|
|
50432
50432
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
50433
|
+
const [typingText, setTypingText] = useState("");
|
|
50434
|
+
const [isTyping, setIsTyping] = useState(false);
|
|
50435
|
+
const typingIntervalRef = useRef(null);
|
|
50436
|
+
const [currentAction, setCurrentAction] = useState("");
|
|
50433
50437
|
const [isSourceView, setIsSourceView] = useState(false);
|
|
50434
50438
|
const [sourceContent, setSourceContent] = useState("");
|
|
50435
50439
|
const [currentTextColor, setCurrentTextColor] = useState("#000000");
|
|
@@ -50440,6 +50444,13 @@ function RichTextEditor({
|
|
|
50440
50444
|
}
|
|
50441
50445
|
return "en";
|
|
50442
50446
|
});
|
|
50447
|
+
useEffect(() => {
|
|
50448
|
+
return () => {
|
|
50449
|
+
if (typingIntervalRef.current) {
|
|
50450
|
+
clearTimeout(typingIntervalRef.current);
|
|
50451
|
+
}
|
|
50452
|
+
};
|
|
50453
|
+
}, []);
|
|
50443
50454
|
const slashCommands = [
|
|
50444
50455
|
{
|
|
50445
50456
|
id: "rewrite",
|
|
@@ -50710,6 +50721,7 @@ function RichTextEditor({
|
|
|
50710
50721
|
});
|
|
50711
50722
|
return;
|
|
50712
50723
|
}
|
|
50724
|
+
setCurrentAction(action);
|
|
50713
50725
|
const processingToast = toast({
|
|
50714
50726
|
title: "Processing with AI...",
|
|
50715
50727
|
description: getActionDescription(action, targetLanguage),
|
|
@@ -50719,15 +50731,30 @@ function RichTextEditor({
|
|
|
50719
50731
|
const result = await callAI(action, selectedText || editor.getText(), targetLanguage);
|
|
50720
50732
|
processingToast.dismiss();
|
|
50721
50733
|
if (result) {
|
|
50734
|
+
setIsTyping(true);
|
|
50735
|
+
setTypingText("");
|
|
50722
50736
|
if (selectedText) {
|
|
50723
|
-
editor.chain().focus().deleteSelection().
|
|
50724
|
-
}
|
|
50725
|
-
|
|
50726
|
-
|
|
50727
|
-
|
|
50728
|
-
|
|
50729
|
-
|
|
50730
|
-
|
|
50737
|
+
editor.chain().focus().deleteSelection().run();
|
|
50738
|
+
}
|
|
50739
|
+
let currentIndex = 0;
|
|
50740
|
+
const typeSpeed = 30;
|
|
50741
|
+
const typeNextChar = () => {
|
|
50742
|
+
if (currentIndex < result.length) {
|
|
50743
|
+
const nextChar = result[currentIndex];
|
|
50744
|
+
setTypingText((prev) => prev + nextChar);
|
|
50745
|
+
editor.chain().focus().insertContent(nextChar).run();
|
|
50746
|
+
currentIndex++;
|
|
50747
|
+
typingIntervalRef.current = setTimeout(typeNextChar, typeSpeed);
|
|
50748
|
+
} else {
|
|
50749
|
+
setIsTyping(false);
|
|
50750
|
+
setTypingText("");
|
|
50751
|
+
toast({
|
|
50752
|
+
title: "AI action completed",
|
|
50753
|
+
description: "Your text has been updated successfully."
|
|
50754
|
+
});
|
|
50755
|
+
}
|
|
50756
|
+
};
|
|
50757
|
+
typeNextChar();
|
|
50731
50758
|
}
|
|
50732
50759
|
};
|
|
50733
50760
|
const getActionDescription = (action, targetLanguage) => {
|
|
@@ -51267,10 +51294,10 @@ function RichTextEditor({
|
|
|
51267
51294
|
variant: "ghost",
|
|
51268
51295
|
size: "sm",
|
|
51269
51296
|
className: "h-8 px-3 bg-purple-100 hover:bg-purple-200 dark:bg-purple-900 dark:hover:bg-purple-800 transition-colors",
|
|
51270
|
-
disabled: isProcessing,
|
|
51297
|
+
disabled: isProcessing || isTyping,
|
|
51271
51298
|
children: [
|
|
51272
|
-
isProcessing ? /* @__PURE__ */ jsx(RefreshCw, { className: "w-4 h-4 mr-1 animate-spin" }) : /* @__PURE__ */ jsx(Wand2, { className: "w-4 h-4 mr-1" }),
|
|
51273
|
-
"AI Tools"
|
|
51299
|
+
isProcessing || isTyping ? /* @__PURE__ */ jsx(RefreshCw, { className: "w-4 h-4 mr-1 animate-spin" }) : /* @__PURE__ */ jsx(Wand2, { className: "w-4 h-4 mr-1" }),
|
|
51300
|
+
isTyping ? "Typing..." : "AI Tools"
|
|
51274
51301
|
]
|
|
51275
51302
|
}
|
|
51276
51303
|
) }),
|
|
@@ -51283,7 +51310,7 @@ function RichTextEditor({
|
|
|
51283
51310
|
MoonUIDropdownMenuItemPro,
|
|
51284
51311
|
{
|
|
51285
51312
|
onClick: () => handleAIAction("rewrite"),
|
|
51286
|
-
disabled: isProcessing,
|
|
51313
|
+
disabled: isProcessing || isTyping,
|
|
51287
51314
|
children: [
|
|
51288
51315
|
/* @__PURE__ */ jsx(RefreshCw, { className: "w-4 h-4 mr-2" }),
|
|
51289
51316
|
"Rewrite Selection",
|
|
@@ -51295,7 +51322,7 @@ function RichTextEditor({
|
|
|
51295
51322
|
MoonUIDropdownMenuItemPro,
|
|
51296
51323
|
{
|
|
51297
51324
|
onClick: () => handleAIAction("improve"),
|
|
51298
|
-
disabled: isProcessing,
|
|
51325
|
+
disabled: isProcessing || isTyping,
|
|
51299
51326
|
children: [
|
|
51300
51327
|
/* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 mr-2" }),
|
|
51301
51328
|
"Improve Writing"
|
|
@@ -51306,7 +51333,7 @@ function RichTextEditor({
|
|
|
51306
51333
|
MoonUIDropdownMenuItemPro,
|
|
51307
51334
|
{
|
|
51308
51335
|
onClick: () => handleAIAction("expand"),
|
|
51309
|
-
disabled: isProcessing,
|
|
51336
|
+
disabled: isProcessing || isTyping,
|
|
51310
51337
|
children: [
|
|
51311
51338
|
/* @__PURE__ */ jsx(Maximize, { className: "w-4 h-4 mr-2" }),
|
|
51312
51339
|
"Expand Text"
|
|
@@ -51317,7 +51344,7 @@ function RichTextEditor({
|
|
|
51317
51344
|
MoonUIDropdownMenuItemPro,
|
|
51318
51345
|
{
|
|
51319
51346
|
onClick: () => handleAIAction("summarize"),
|
|
51320
|
-
disabled: isProcessing,
|
|
51347
|
+
disabled: isProcessing || isTyping,
|
|
51321
51348
|
children: [
|
|
51322
51349
|
/* @__PURE__ */ jsx(FileText, { className: "w-4 h-4 mr-2" }),
|
|
51323
51350
|
"Summarize"
|
|
@@ -51328,7 +51355,7 @@ function RichTextEditor({
|
|
|
51328
51355
|
MoonUIDropdownMenuItemPro,
|
|
51329
51356
|
{
|
|
51330
51357
|
onClick: () => handleAIAction("continue"),
|
|
51331
|
-
disabled: isProcessing,
|
|
51358
|
+
disabled: isProcessing || isTyping,
|
|
51332
51359
|
children: [
|
|
51333
51360
|
/* @__PURE__ */ jsx(Plus, { className: "w-4 h-4 mr-2" }),
|
|
51334
51361
|
"Continue Writing"
|
|
@@ -51344,7 +51371,7 @@ function RichTextEditor({
|
|
|
51344
51371
|
MoonUIDropdownMenuItemPro,
|
|
51345
51372
|
{
|
|
51346
51373
|
onClick: () => handleAIAction("tone_professional"),
|
|
51347
|
-
disabled: isProcessing,
|
|
51374
|
+
disabled: isProcessing || isTyping,
|
|
51348
51375
|
children: [
|
|
51349
51376
|
/* @__PURE__ */ jsx(Briefcase, { className: "w-4 h-4 mr-2" }),
|
|
51350
51377
|
"Make Professional"
|
|
@@ -51355,7 +51382,7 @@ function RichTextEditor({
|
|
|
51355
51382
|
MoonUIDropdownMenuItemPro,
|
|
51356
51383
|
{
|
|
51357
51384
|
onClick: () => handleAIAction("tone_casual"),
|
|
51358
|
-
disabled: isProcessing,
|
|
51385
|
+
disabled: isProcessing || isTyping,
|
|
51359
51386
|
children: [
|
|
51360
51387
|
/* @__PURE__ */ jsx(MessageSquare, { className: "w-4 h-4 mr-2" }),
|
|
51361
51388
|
"Make Casual"
|
|
@@ -51366,7 +51393,7 @@ function RichTextEditor({
|
|
|
51366
51393
|
MoonUIDropdownMenuItemPro,
|
|
51367
51394
|
{
|
|
51368
51395
|
onClick: () => handleAIAction("tone_friendly"),
|
|
51369
|
-
disabled: isProcessing,
|
|
51396
|
+
disabled: isProcessing || isTyping,
|
|
51370
51397
|
children: [
|
|
51371
51398
|
/* @__PURE__ */ jsx(Heart, { className: "w-4 h-4 mr-2" }),
|
|
51372
51399
|
"Make Friendly"
|
|
@@ -51377,7 +51404,7 @@ function RichTextEditor({
|
|
|
51377
51404
|
MoonUIDropdownMenuItemPro,
|
|
51378
51405
|
{
|
|
51379
51406
|
onClick: () => handleAIAction("tone_formal"),
|
|
51380
|
-
disabled: isProcessing,
|
|
51407
|
+
disabled: isProcessing || isTyping,
|
|
51381
51408
|
children: [
|
|
51382
51409
|
/* @__PURE__ */ jsx(GraduationCap, { className: "w-4 h-4 mr-2" }),
|
|
51383
51410
|
"Make Formal"
|
|
@@ -51393,7 +51420,7 @@ function RichTextEditor({
|
|
|
51393
51420
|
MoonUIDropdownMenuItemPro,
|
|
51394
51421
|
{
|
|
51395
51422
|
onClick: () => handleAIAction("fix"),
|
|
51396
|
-
disabled: isProcessing,
|
|
51423
|
+
disabled: isProcessing || isTyping,
|
|
51397
51424
|
children: [
|
|
51398
51425
|
/* @__PURE__ */ jsx(Check, { className: "w-4 h-4 mr-2" }),
|
|
51399
51426
|
"Fix Grammar & Spelling",
|
|
@@ -51402,7 +51429,7 @@ function RichTextEditor({
|
|
|
51402
51429
|
}
|
|
51403
51430
|
),
|
|
51404
51431
|
/* @__PURE__ */ jsxs(MoonUIDropdownMenuSubPro, { children: [
|
|
51405
|
-
/* @__PURE__ */ jsxs(MoonUIDropdownMenuSubTriggerPro, { disabled: isProcessing, children: [
|
|
51432
|
+
/* @__PURE__ */ jsxs(MoonUIDropdownMenuSubTriggerPro, { disabled: isProcessing || isTyping, children: [
|
|
51406
51433
|
/* @__PURE__ */ jsx(Languages, { className: "w-4 h-4 mr-2" }),
|
|
51407
51434
|
"Translate",
|
|
51408
51435
|
lastTranslateLanguage && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-muted-foreground", children: SUPPORTED_LANGUAGES.find((l) => l.code === lastTranslateLanguage)?.nativeName || "English" })
|
|
@@ -51415,7 +51442,7 @@ function RichTextEditor({
|
|
|
51415
51442
|
localStorage.setItem("moonui-last-translate-language", language.code);
|
|
51416
51443
|
handleAIAction("translate", language.name);
|
|
51417
51444
|
},
|
|
51418
|
-
disabled: isProcessing,
|
|
51445
|
+
disabled: isProcessing || isTyping,
|
|
51419
51446
|
children: [
|
|
51420
51447
|
/* @__PURE__ */ jsx("span", { className: "text-sm", children: language.nativeName }),
|
|
51421
51448
|
/* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-muted-foreground", children: language.name }),
|
|
@@ -51429,7 +51456,7 @@ function RichTextEditor({
|
|
|
51429
51456
|
MoonUIDropdownMenuItemPro,
|
|
51430
51457
|
{
|
|
51431
51458
|
onClick: () => handleAIAction("ideas"),
|
|
51432
|
-
disabled: isProcessing,
|
|
51459
|
+
disabled: isProcessing || isTyping,
|
|
51433
51460
|
children: [
|
|
51434
51461
|
/* @__PURE__ */ jsx(Lightbulb, { className: "w-4 h-4 mr-2" }),
|
|
51435
51462
|
"Generate Ideas"
|
|
@@ -51518,6 +51545,9 @@ function RichTextEditor({
|
|
|
51518
51545
|
onChange: (e) => {
|
|
51519
51546
|
const newSettings = { ...aiSettings, apiKey: e.target.value };
|
|
51520
51547
|
setAiSettings(newSettings);
|
|
51548
|
+
if (persistAISettings) {
|
|
51549
|
+
localStorage.setItem("moonui-ai-settings", JSON.stringify(newSettings));
|
|
51550
|
+
}
|
|
51521
51551
|
},
|
|
51522
51552
|
placeholder: "sk-..."
|
|
51523
51553
|
}
|
|
@@ -51532,6 +51562,9 @@ function RichTextEditor({
|
|
|
51532
51562
|
onValueChange: (value) => {
|
|
51533
51563
|
const newSettings = { ...aiSettings, model: value };
|
|
51534
51564
|
setAiSettings(newSettings);
|
|
51565
|
+
if (persistAISettings) {
|
|
51566
|
+
localStorage.setItem("moonui-ai-settings", JSON.stringify(newSettings));
|
|
51567
|
+
}
|
|
51535
51568
|
},
|
|
51536
51569
|
children: [
|
|
51537
51570
|
/* @__PURE__ */ jsx(MoonUISelectTriggerPro, { children: /* @__PURE__ */ jsx(MoonUISelectValuePro, {}) }),
|
|
@@ -51574,6 +51607,9 @@ function RichTextEditor({
|
|
|
51574
51607
|
onChange: (e) => {
|
|
51575
51608
|
const newSettings = { ...aiSettings, temperature: parseFloat(e.target.value) };
|
|
51576
51609
|
setAiSettings(newSettings);
|
|
51610
|
+
if (persistAISettings) {
|
|
51611
|
+
localStorage.setItem("moonui-ai-settings", JSON.stringify(newSettings));
|
|
51612
|
+
}
|
|
51577
51613
|
}
|
|
51578
51614
|
}
|
|
51579
51615
|
)
|
|
@@ -51591,6 +51627,9 @@ function RichTextEditor({
|
|
|
51591
51627
|
onChange: (e) => {
|
|
51592
51628
|
const newSettings = { ...aiSettings, maxTokens: parseInt(e.target.value) };
|
|
51593
51629
|
setAiSettings(newSettings);
|
|
51630
|
+
if (persistAISettings) {
|
|
51631
|
+
localStorage.setItem("moonui-ai-settings", JSON.stringify(newSettings));
|
|
51632
|
+
}
|
|
51594
51633
|
}
|
|
51595
51634
|
}
|
|
51596
51635
|
)
|
|
@@ -51793,7 +51832,7 @@ function RichTextEditor({
|
|
|
51793
51832
|
/* @__PURE__ */ jsx(
|
|
51794
51833
|
"div",
|
|
51795
51834
|
{
|
|
51796
|
-
className: "overflow-auto",
|
|
51835
|
+
className: "overflow-auto relative",
|
|
51797
51836
|
style: { height: typeof height === "number" ? `${height}px` : height },
|
|
51798
51837
|
children: isSourceView ? /* @__PURE__ */ jsx(
|
|
51799
51838
|
"textarea",
|
|
@@ -51803,7 +51842,57 @@ function RichTextEditor({
|
|
|
51803
51842
|
className: "w-full h-full p-4 font-mono text-sm resize-none focus:outline-none bg-gray-50 dark:bg-gray-900",
|
|
51804
51843
|
placeholder: "HTML source code..."
|
|
51805
51844
|
}
|
|
51806
|
-
) : /* @__PURE__ */
|
|
51845
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
51846
|
+
/* @__PURE__ */ jsx(EditorContent, { editor }),
|
|
51847
|
+
isProcessing && /* @__PURE__ */ jsx(
|
|
51848
|
+
motion.div,
|
|
51849
|
+
{
|
|
51850
|
+
initial: { opacity: 0 },
|
|
51851
|
+
animate: { opacity: 1 },
|
|
51852
|
+
exit: { opacity: 0 },
|
|
51853
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm flex items-center justify-center z-50",
|
|
51854
|
+
children: /* @__PURE__ */ jsx("div", { className: "bg-card border rounded-lg p-6 shadow-lg max-w-sm w-full mx-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center space-y-4", children: [
|
|
51855
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
51856
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 h-16 border-4 border-purple-200 dark:border-purple-800 rounded-full animate-pulse" }),
|
|
51857
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(Wand2, { className: "w-8 h-8 text-purple-600 dark:text-purple-400 animate-bounce" }) })
|
|
51858
|
+
] }),
|
|
51859
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center space-y-2", children: [
|
|
51860
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-lg", children: "AI is thinking..." }),
|
|
51861
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: getActionDescription(
|
|
51862
|
+
currentAction,
|
|
51863
|
+
lastTranslateLanguage
|
|
51864
|
+
) })
|
|
51865
|
+
] }),
|
|
51866
|
+
/* @__PURE__ */ jsxs("div", { className: "flex space-x-1", children: [
|
|
51867
|
+
/* @__PURE__ */ jsx(
|
|
51868
|
+
motion.div,
|
|
51869
|
+
{
|
|
51870
|
+
animate: { scale: [1, 1.5, 1] },
|
|
51871
|
+
transition: { duration: 0.6, repeat: Infinity, delay: 0 },
|
|
51872
|
+
className: "w-2 h-2 bg-purple-600 dark:bg-purple-400 rounded-full"
|
|
51873
|
+
}
|
|
51874
|
+
),
|
|
51875
|
+
/* @__PURE__ */ jsx(
|
|
51876
|
+
motion.div,
|
|
51877
|
+
{
|
|
51878
|
+
animate: { scale: [1, 1.5, 1] },
|
|
51879
|
+
transition: { duration: 0.6, repeat: Infinity, delay: 0.2 },
|
|
51880
|
+
className: "w-2 h-2 bg-purple-600 dark:bg-purple-400 rounded-full"
|
|
51881
|
+
}
|
|
51882
|
+
),
|
|
51883
|
+
/* @__PURE__ */ jsx(
|
|
51884
|
+
motion.div,
|
|
51885
|
+
{
|
|
51886
|
+
animate: { scale: [1, 1.5, 1] },
|
|
51887
|
+
transition: { duration: 0.6, repeat: Infinity, delay: 0.4 },
|
|
51888
|
+
className: "w-2 h-2 bg-purple-600 dark:bg-purple-400 rounded-full"
|
|
51889
|
+
}
|
|
51890
|
+
)
|
|
51891
|
+
] })
|
|
51892
|
+
] }) })
|
|
51893
|
+
}
|
|
51894
|
+
)
|
|
51895
|
+
] })
|
|
51807
51896
|
}
|
|
51808
51897
|
)
|
|
51809
51898
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moontra/moonui-pro",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.10",
|
|
4
4
|
"description": "Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import React, { useState } from 'react';
|
|
3
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { useEditor, EditorContent } from '@tiptap/react';
|
|
5
5
|
import StarterKit from '@tiptap/starter-kit';
|
|
6
6
|
import Placeholder from '@tiptap/extension-placeholder';
|
|
@@ -300,13 +300,7 @@ export function RichTextEditor({
|
|
|
300
300
|
color: true,
|
|
301
301
|
ai: true,
|
|
302
302
|
},
|
|
303
|
-
aiConfig = {
|
|
304
|
-
provider: 'openai',
|
|
305
|
-
apiKey: '',
|
|
306
|
-
model: 'gpt-3.5-turbo',
|
|
307
|
-
temperature: 0.7,
|
|
308
|
-
maxTokens: 1000,
|
|
309
|
-
},
|
|
303
|
+
aiConfig = {},
|
|
310
304
|
persistAISettings = true,
|
|
311
305
|
}: RichTextEditorProps) {
|
|
312
306
|
// Pro access kontrolü
|
|
@@ -348,16 +342,20 @@ export function RichTextEditor({
|
|
|
348
342
|
if (persistAISettings && typeof window !== 'undefined') {
|
|
349
343
|
try {
|
|
350
344
|
const stored = localStorage.getItem('moonui-ai-settings');
|
|
345
|
+
console.log('[RichTextEditor] Loading AI settings from localStorage:', stored);
|
|
351
346
|
if (stored) {
|
|
352
347
|
const parsed = JSON.parse(stored);
|
|
348
|
+
console.log('[RichTextEditor] Parsed AI settings:', parsed);
|
|
353
349
|
// Props'tan gelen değerler her zaman öncelikli
|
|
354
|
-
|
|
355
|
-
provider: (aiConfig.provider
|
|
356
|
-
apiKey: aiConfig.apiKey
|
|
357
|
-
model: aiConfig.model
|
|
358
|
-
temperature: aiConfig.temperature
|
|
359
|
-
maxTokens: aiConfig.maxTokens
|
|
350
|
+
const settings = {
|
|
351
|
+
provider: (aiConfig.provider !== undefined ? aiConfig.provider : parsed.provider || 'openai') as 'openai' | 'claude' | 'gemini' | 'cohere',
|
|
352
|
+
apiKey: aiConfig.apiKey !== undefined ? aiConfig.apiKey : parsed.apiKey || '',
|
|
353
|
+
model: aiConfig.model !== undefined ? aiConfig.model : parsed.model || 'gpt-3.5-turbo',
|
|
354
|
+
temperature: aiConfig.temperature !== undefined ? aiConfig.temperature : parsed.temperature ?? 0.7,
|
|
355
|
+
maxTokens: aiConfig.maxTokens !== undefined ? aiConfig.maxTokens : parsed.maxTokens ?? 1000,
|
|
360
356
|
};
|
|
357
|
+
console.log('[RichTextEditor] Final settings with props override:', settings);
|
|
358
|
+
return settings;
|
|
361
359
|
}
|
|
362
360
|
} catch (e) {
|
|
363
361
|
console.error('Failed to load AI settings from localStorage:', e);
|
|
@@ -365,16 +363,22 @@ export function RichTextEditor({
|
|
|
365
363
|
}
|
|
366
364
|
|
|
367
365
|
// LocalStorage yoksa veya persist kapalıysa props/varsayılan değerleri kullan
|
|
368
|
-
|
|
366
|
+
const defaultSettings = {
|
|
369
367
|
provider: (aiConfig.provider || 'openai') as 'openai' | 'claude' | 'gemini' | 'cohere',
|
|
370
368
|
apiKey: aiConfig.apiKey || '',
|
|
371
369
|
model: aiConfig.model || 'gpt-3.5-turbo',
|
|
372
370
|
temperature: aiConfig.temperature ?? 0.7,
|
|
373
371
|
maxTokens: aiConfig.maxTokens ?? 1000,
|
|
374
372
|
};
|
|
373
|
+
console.log('[RichTextEditor] Using default settings:', defaultSettings);
|
|
374
|
+
return defaultSettings;
|
|
375
375
|
});
|
|
376
376
|
const [isAiSettingsOpen, setIsAiSettingsOpen] = useState(false);
|
|
377
377
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
378
|
+
const [typingText, setTypingText] = useState('');
|
|
379
|
+
const [isTyping, setIsTyping] = useState(false);
|
|
380
|
+
const typingIntervalRef = useRef<NodeJS.Timeout | null>(null);
|
|
381
|
+
const [currentAction, setCurrentAction] = useState('');
|
|
378
382
|
const [isSourceView, setIsSourceView] = useState(false);
|
|
379
383
|
const [sourceContent, setSourceContent] = useState('');
|
|
380
384
|
const [currentTextColor, setCurrentTextColor] = useState('#000000');
|
|
@@ -386,6 +390,15 @@ export function RichTextEditor({
|
|
|
386
390
|
}
|
|
387
391
|
return 'en';
|
|
388
392
|
});
|
|
393
|
+
|
|
394
|
+
// Clean up typewriter effect on unmount
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
return () => {
|
|
397
|
+
if (typingIntervalRef.current) {
|
|
398
|
+
clearTimeout(typingIntervalRef.current);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
}, []);
|
|
389
402
|
|
|
390
403
|
// Slash commands tanımları
|
|
391
404
|
const slashCommands: SlashCommand[] = [
|
|
@@ -668,6 +681,9 @@ export function RichTextEditor({
|
|
|
668
681
|
return;
|
|
669
682
|
}
|
|
670
683
|
|
|
684
|
+
// Set current action for UI
|
|
685
|
+
setCurrentAction(action);
|
|
686
|
+
|
|
671
687
|
// Show processing toast
|
|
672
688
|
const processingToast = toast({
|
|
673
689
|
title: "Processing with AI...",
|
|
@@ -681,17 +697,39 @@ export function RichTextEditor({
|
|
|
681
697
|
processingToast.dismiss();
|
|
682
698
|
|
|
683
699
|
if (result) {
|
|
700
|
+
// Start typewriter effect
|
|
701
|
+
setIsTyping(true);
|
|
702
|
+
setTypingText('');
|
|
703
|
+
|
|
684
704
|
if (selectedText) {
|
|
685
|
-
editor.chain().focus().deleteSelection().
|
|
686
|
-
} else {
|
|
687
|
-
editor.chain().focus().insertContent(result).run();
|
|
705
|
+
editor.chain().focus().deleteSelection().run();
|
|
688
706
|
}
|
|
689
707
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
708
|
+
let currentIndex = 0;
|
|
709
|
+
const typeSpeed = 30; // ms per character
|
|
710
|
+
|
|
711
|
+
const typeNextChar = () => {
|
|
712
|
+
if (currentIndex < result.length) {
|
|
713
|
+
const nextChar = result[currentIndex];
|
|
714
|
+
setTypingText(prev => prev + nextChar);
|
|
715
|
+
editor.chain().focus().insertContent(nextChar).run();
|
|
716
|
+
currentIndex++;
|
|
717
|
+
typingIntervalRef.current = setTimeout(typeNextChar, typeSpeed);
|
|
718
|
+
} else {
|
|
719
|
+
// Typing complete
|
|
720
|
+
setIsTyping(false);
|
|
721
|
+
setTypingText('');
|
|
722
|
+
|
|
723
|
+
// Success toast
|
|
724
|
+
toast({
|
|
725
|
+
title: "AI action completed",
|
|
726
|
+
description: "Your text has been updated successfully.",
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
// Start typing
|
|
732
|
+
typeNextChar();
|
|
695
733
|
}
|
|
696
734
|
};
|
|
697
735
|
|
|
@@ -1316,14 +1354,14 @@ export function RichTextEditor({
|
|
|
1316
1354
|
variant="ghost"
|
|
1317
1355
|
size="sm"
|
|
1318
1356
|
className="h-8 px-3 bg-purple-100 hover:bg-purple-200 dark:bg-purple-900 dark:hover:bg-purple-800 transition-colors"
|
|
1319
|
-
disabled={isProcessing}
|
|
1357
|
+
disabled={isProcessing || isTyping}
|
|
1320
1358
|
>
|
|
1321
|
-
{isProcessing ? (
|
|
1359
|
+
{isProcessing || isTyping ? (
|
|
1322
1360
|
<RefreshCw className="w-4 h-4 mr-1 animate-spin" />
|
|
1323
1361
|
) : (
|
|
1324
1362
|
<Wand2 className="w-4 h-4 mr-1" />
|
|
1325
1363
|
)}
|
|
1326
|
-
AI Tools
|
|
1364
|
+
{isTyping ? 'Typing...' : 'AI Tools'}
|
|
1327
1365
|
</Button>
|
|
1328
1366
|
</DropdownMenuTrigger>
|
|
1329
1367
|
<DropdownMenuContent className="w-64">
|
|
@@ -1333,7 +1371,7 @@ export function RichTextEditor({
|
|
|
1333
1371
|
</div>
|
|
1334
1372
|
<DropdownMenuItem
|
|
1335
1373
|
onClick={() => handleAIAction('rewrite')}
|
|
1336
|
-
disabled={isProcessing}
|
|
1374
|
+
disabled={isProcessing || isTyping}
|
|
1337
1375
|
>
|
|
1338
1376
|
<RefreshCw className="w-4 h-4 mr-2" />
|
|
1339
1377
|
Rewrite Selection
|
|
@@ -1341,28 +1379,28 @@ export function RichTextEditor({
|
|
|
1341
1379
|
</DropdownMenuItem>
|
|
1342
1380
|
<DropdownMenuItem
|
|
1343
1381
|
onClick={() => handleAIAction('improve')}
|
|
1344
|
-
disabled={isProcessing}
|
|
1382
|
+
disabled={isProcessing || isTyping}
|
|
1345
1383
|
>
|
|
1346
1384
|
<Sparkles className="w-4 h-4 mr-2" />
|
|
1347
1385
|
Improve Writing
|
|
1348
1386
|
</DropdownMenuItem>
|
|
1349
1387
|
<DropdownMenuItem
|
|
1350
1388
|
onClick={() => handleAIAction('expand')}
|
|
1351
|
-
disabled={isProcessing}
|
|
1389
|
+
disabled={isProcessing || isTyping}
|
|
1352
1390
|
>
|
|
1353
1391
|
<Maximize className="w-4 h-4 mr-2" />
|
|
1354
1392
|
Expand Text
|
|
1355
1393
|
</DropdownMenuItem>
|
|
1356
1394
|
<DropdownMenuItem
|
|
1357
1395
|
onClick={() => handleAIAction('summarize')}
|
|
1358
|
-
disabled={isProcessing}
|
|
1396
|
+
disabled={isProcessing || isTyping}
|
|
1359
1397
|
>
|
|
1360
1398
|
<FileText className="w-4 h-4 mr-2" />
|
|
1361
1399
|
Summarize
|
|
1362
1400
|
</DropdownMenuItem>
|
|
1363
1401
|
<DropdownMenuItem
|
|
1364
1402
|
onClick={() => handleAIAction('continue')}
|
|
1365
|
-
disabled={isProcessing}
|
|
1403
|
+
disabled={isProcessing || isTyping}
|
|
1366
1404
|
>
|
|
1367
1405
|
<Plus className="w-4 h-4 mr-2" />
|
|
1368
1406
|
Continue Writing
|
|
@@ -1375,28 +1413,28 @@ export function RichTextEditor({
|
|
|
1375
1413
|
</div>
|
|
1376
1414
|
<DropdownMenuItem
|
|
1377
1415
|
onClick={() => handleAIAction('tone_professional')}
|
|
1378
|
-
disabled={isProcessing}
|
|
1416
|
+
disabled={isProcessing || isTyping}
|
|
1379
1417
|
>
|
|
1380
1418
|
<Briefcase className="w-4 h-4 mr-2" />
|
|
1381
1419
|
Make Professional
|
|
1382
1420
|
</DropdownMenuItem>
|
|
1383
1421
|
<DropdownMenuItem
|
|
1384
1422
|
onClick={() => handleAIAction('tone_casual')}
|
|
1385
|
-
disabled={isProcessing}
|
|
1423
|
+
disabled={isProcessing || isTyping}
|
|
1386
1424
|
>
|
|
1387
1425
|
<MessageSquare className="w-4 h-4 mr-2" />
|
|
1388
1426
|
Make Casual
|
|
1389
1427
|
</DropdownMenuItem>
|
|
1390
1428
|
<DropdownMenuItem
|
|
1391
1429
|
onClick={() => handleAIAction('tone_friendly')}
|
|
1392
|
-
disabled={isProcessing}
|
|
1430
|
+
disabled={isProcessing || isTyping}
|
|
1393
1431
|
>
|
|
1394
1432
|
<Heart className="w-4 h-4 mr-2" />
|
|
1395
1433
|
Make Friendly
|
|
1396
1434
|
</DropdownMenuItem>
|
|
1397
1435
|
<DropdownMenuItem
|
|
1398
1436
|
onClick={() => handleAIAction('tone_formal')}
|
|
1399
|
-
disabled={isProcessing}
|
|
1437
|
+
disabled={isProcessing || isTyping}
|
|
1400
1438
|
>
|
|
1401
1439
|
<GraduationCap className="w-4 h-4 mr-2" />
|
|
1402
1440
|
Make Formal
|
|
@@ -1409,14 +1447,14 @@ export function RichTextEditor({
|
|
|
1409
1447
|
</div>
|
|
1410
1448
|
<DropdownMenuItem
|
|
1411
1449
|
onClick={() => handleAIAction('fix')}
|
|
1412
|
-
disabled={isProcessing}
|
|
1450
|
+
disabled={isProcessing || isTyping}
|
|
1413
1451
|
>
|
|
1414
1452
|
<Check className="w-4 h-4 mr-2" />
|
|
1415
1453
|
Fix Grammar & Spelling
|
|
1416
1454
|
<span className="ml-auto text-xs text-muted-foreground">F7</span>
|
|
1417
1455
|
</DropdownMenuItem>
|
|
1418
1456
|
<DropdownMenuSub>
|
|
1419
|
-
<DropdownMenuSubTrigger disabled={isProcessing}>
|
|
1457
|
+
<DropdownMenuSubTrigger disabled={isProcessing || isTyping}>
|
|
1420
1458
|
<Languages className="w-4 h-4 mr-2" />
|
|
1421
1459
|
Translate
|
|
1422
1460
|
{lastTranslateLanguage && (
|
|
@@ -1436,7 +1474,7 @@ export function RichTextEditor({
|
|
|
1436
1474
|
// Çeviriyi yap
|
|
1437
1475
|
handleAIAction('translate', language.name);
|
|
1438
1476
|
}}
|
|
1439
|
-
disabled={isProcessing}
|
|
1477
|
+
disabled={isProcessing || isTyping}
|
|
1440
1478
|
>
|
|
1441
1479
|
<span className="text-sm">{language.nativeName}</span>
|
|
1442
1480
|
<span className="ml-auto text-xs text-muted-foreground">{language.name}</span>
|
|
@@ -1449,7 +1487,7 @@ export function RichTextEditor({
|
|
|
1449
1487
|
</DropdownMenuSub>
|
|
1450
1488
|
<DropdownMenuItem
|
|
1451
1489
|
onClick={() => handleAIAction('ideas')}
|
|
1452
|
-
disabled={isProcessing}
|
|
1490
|
+
disabled={isProcessing || isTyping}
|
|
1453
1491
|
>
|
|
1454
1492
|
<Lightbulb className="w-4 h-4 mr-2" />
|
|
1455
1493
|
Generate Ideas
|
|
@@ -1544,6 +1582,10 @@ export function RichTextEditor({
|
|
|
1544
1582
|
onChange={(e) => {
|
|
1545
1583
|
const newSettings = { ...aiSettings, apiKey: e.target.value };
|
|
1546
1584
|
setAiSettings(newSettings);
|
|
1585
|
+
// Save to localStorage immediately
|
|
1586
|
+
if (persistAISettings) {
|
|
1587
|
+
localStorage.setItem('moonui-ai-settings', JSON.stringify(newSettings));
|
|
1588
|
+
}
|
|
1547
1589
|
}}
|
|
1548
1590
|
placeholder="sk-..."
|
|
1549
1591
|
/>
|
|
@@ -1555,6 +1597,10 @@ export function RichTextEditor({
|
|
|
1555
1597
|
onValueChange={(value) => {
|
|
1556
1598
|
const newSettings = { ...aiSettings, model: value };
|
|
1557
1599
|
setAiSettings(newSettings);
|
|
1600
|
+
// Save to localStorage immediately
|
|
1601
|
+
if (persistAISettings) {
|
|
1602
|
+
localStorage.setItem('moonui-ai-settings', JSON.stringify(newSettings));
|
|
1603
|
+
}
|
|
1558
1604
|
}}
|
|
1559
1605
|
>
|
|
1560
1606
|
<SelectTrigger>
|
|
@@ -1603,6 +1649,10 @@ export function RichTextEditor({
|
|
|
1603
1649
|
onChange={(e) => {
|
|
1604
1650
|
const newSettings = { ...aiSettings, temperature: parseFloat(e.target.value) };
|
|
1605
1651
|
setAiSettings(newSettings);
|
|
1652
|
+
// Save to localStorage immediately
|
|
1653
|
+
if (persistAISettings) {
|
|
1654
|
+
localStorage.setItem('moonui-ai-settings', JSON.stringify(newSettings));
|
|
1655
|
+
}
|
|
1606
1656
|
}}
|
|
1607
1657
|
/>
|
|
1608
1658
|
</div>
|
|
@@ -1617,6 +1667,10 @@ export function RichTextEditor({
|
|
|
1617
1667
|
onChange={(e) => {
|
|
1618
1668
|
const newSettings = { ...aiSettings, maxTokens: parseInt(e.target.value) };
|
|
1619
1669
|
setAiSettings(newSettings);
|
|
1670
|
+
// Save to localStorage immediately
|
|
1671
|
+
if (persistAISettings) {
|
|
1672
|
+
localStorage.setItem('moonui-ai-settings', JSON.stringify(newSettings));
|
|
1673
|
+
}
|
|
1620
1674
|
}}
|
|
1621
1675
|
/>
|
|
1622
1676
|
</div>
|
|
@@ -1834,7 +1888,7 @@ export function RichTextEditor({
|
|
|
1834
1888
|
|
|
1835
1889
|
{/* Editor */}
|
|
1836
1890
|
<div
|
|
1837
|
-
className="overflow-auto"
|
|
1891
|
+
className="overflow-auto relative"
|
|
1838
1892
|
style={{ height: typeof height === 'number' ? `${height}px` : height }}
|
|
1839
1893
|
>
|
|
1840
1894
|
{isSourceView ? (
|
|
@@ -1845,7 +1899,55 @@ export function RichTextEditor({
|
|
|
1845
1899
|
placeholder="HTML source code..."
|
|
1846
1900
|
/>
|
|
1847
1901
|
) : (
|
|
1848
|
-
|
|
1902
|
+
<>
|
|
1903
|
+
<EditorContent editor={editor} />
|
|
1904
|
+
{/* AI Processing Overlay */}
|
|
1905
|
+
{isProcessing && (
|
|
1906
|
+
<motion.div
|
|
1907
|
+
initial={{ opacity: 0 }}
|
|
1908
|
+
animate={{ opacity: 1 }}
|
|
1909
|
+
exit={{ opacity: 0 }}
|
|
1910
|
+
className="absolute inset-0 bg-background/80 backdrop-blur-sm flex items-center justify-center z-50"
|
|
1911
|
+
>
|
|
1912
|
+
<div className="bg-card border rounded-lg p-6 shadow-lg max-w-sm w-full mx-4">
|
|
1913
|
+
<div className="flex flex-col items-center space-y-4">
|
|
1914
|
+
<div className="relative">
|
|
1915
|
+
<div className="w-16 h-16 border-4 border-purple-200 dark:border-purple-800 rounded-full animate-pulse"></div>
|
|
1916
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
1917
|
+
<Wand2 className="w-8 h-8 text-purple-600 dark:text-purple-400 animate-bounce" />
|
|
1918
|
+
</div>
|
|
1919
|
+
</div>
|
|
1920
|
+
<div className="text-center space-y-2">
|
|
1921
|
+
<h3 className="font-semibold text-lg">AI is thinking...</h3>
|
|
1922
|
+
<p className="text-sm text-muted-foreground">
|
|
1923
|
+
{getActionDescription(
|
|
1924
|
+
currentAction,
|
|
1925
|
+
lastTranslateLanguage
|
|
1926
|
+
)}
|
|
1927
|
+
</p>
|
|
1928
|
+
</div>
|
|
1929
|
+
<div className="flex space-x-1">
|
|
1930
|
+
<motion.div
|
|
1931
|
+
animate={{ scale: [1, 1.5, 1] }}
|
|
1932
|
+
transition={{ duration: 0.6, repeat: Infinity, delay: 0 }}
|
|
1933
|
+
className="w-2 h-2 bg-purple-600 dark:bg-purple-400 rounded-full"
|
|
1934
|
+
/>
|
|
1935
|
+
<motion.div
|
|
1936
|
+
animate={{ scale: [1, 1.5, 1] }}
|
|
1937
|
+
transition={{ duration: 0.6, repeat: Infinity, delay: 0.2 }}
|
|
1938
|
+
className="w-2 h-2 bg-purple-600 dark:bg-purple-400 rounded-full"
|
|
1939
|
+
/>
|
|
1940
|
+
<motion.div
|
|
1941
|
+
animate={{ scale: [1, 1.5, 1] }}
|
|
1942
|
+
transition={{ duration: 0.6, repeat: Infinity, delay: 0.4 }}
|
|
1943
|
+
className="w-2 h-2 bg-purple-600 dark:bg-purple-400 rounded-full"
|
|
1944
|
+
/>
|
|
1945
|
+
</div>
|
|
1946
|
+
</div>
|
|
1947
|
+
</div>
|
|
1948
|
+
</motion.div>
|
|
1949
|
+
)}
|
|
1950
|
+
</>
|
|
1849
1951
|
)}
|
|
1850
1952
|
</div>
|
|
1851
1953
|
</div>
|