@moontra/moonui-pro 2.8.9 → 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 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
- return {
50412
- provider: aiConfig.provider || parsed.provider || "openai",
50413
- apiKey: aiConfig.apiKey || parsed.apiKey || "",
50414
- model: aiConfig.model || parsed.model || "gpt-3.5-turbo",
50415
- temperature: aiConfig.temperature ?? parsed.temperature ?? 0.7,
50416
- maxTokens: aiConfig.maxTokens ?? parsed.maxTokens ?? 1e3
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
- return {
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().insertContent(result).run();
50724
- } else {
50725
- editor.chain().focus().insertContent(result).run();
50726
- }
50727
- toast({
50728
- title: "AI action completed",
50729
- description: "Your text has been updated successfully."
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"
@@ -51805,7 +51832,7 @@ function RichTextEditor({
51805
51832
  /* @__PURE__ */ jsx(
51806
51833
  "div",
51807
51834
  {
51808
- className: "overflow-auto",
51835
+ className: "overflow-auto relative",
51809
51836
  style: { height: typeof height === "number" ? `${height}px` : height },
51810
51837
  children: isSourceView ? /* @__PURE__ */ jsx(
51811
51838
  "textarea",
@@ -51815,7 +51842,57 @@ function RichTextEditor({
51815
51842
  className: "w-full h-full p-4 font-mono text-sm resize-none focus:outline-none bg-gray-50 dark:bg-gray-900",
51816
51843
  placeholder: "HTML source code..."
51817
51844
  }
51818
- ) : /* @__PURE__ */ jsx(EditorContent, { editor })
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
+ ] })
51819
51896
  }
51820
51897
  )
51821
51898
  ] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.8.9",
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
- return {
355
- provider: (aiConfig.provider || parsed.provider || 'openai') as 'openai' | 'claude' | 'gemini' | 'cohere',
356
- apiKey: aiConfig.apiKey || parsed.apiKey || '',
357
- model: aiConfig.model || parsed.model || 'gpt-3.5-turbo',
358
- temperature: aiConfig.temperature ?? parsed.temperature ?? 0.7,
359
- maxTokens: aiConfig.maxTokens ?? parsed.maxTokens ?? 1000,
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
- return {
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().insertContent(result).run();
686
- } else {
687
- editor.chain().focus().insertContent(result).run();
705
+ editor.chain().focus().deleteSelection().run();
688
706
  }
689
707
 
690
- // Success toast
691
- toast({
692
- title: "AI action completed",
693
- description: "Your text has been updated successfully.",
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
@@ -1850,7 +1888,7 @@ export function RichTextEditor({
1850
1888
 
1851
1889
  {/* Editor */}
1852
1890
  <div
1853
- className="overflow-auto"
1891
+ className="overflow-auto relative"
1854
1892
  style={{ height: typeof height === 'number' ? `${height}px` : height }}
1855
1893
  >
1856
1894
  {isSourceView ? (
@@ -1861,7 +1899,55 @@ export function RichTextEditor({
1861
1899
  placeholder="HTML source code..."
1862
1900
  />
1863
1901
  ) : (
1864
- <EditorContent editor={editor} />
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
+ </>
1865
1951
  )}
1866
1952
  </div>
1867
1953
  </div>