1- import { useState , useCallback , useMemo } from 'react' ;
2- import Editor , { type BeforeMount } from '@monaco-editor/react' ;
1+ import { useState , useCallback , useEffect , useMemo , useRef } from 'react' ;
2+ import Editor , { type BeforeMount , type OnMount } from '@monaco-editor/react' ;
3+ import type { IDisposable } from 'monaco-editor' ;
34import {
45 DEFAULT_JSON ,
56 VITESSE_DARK_MONACO_THEME ,
@@ -15,10 +16,19 @@ interface JsonFormatterProps {
1516 onThemeChange : ( isDark : boolean ) => void ;
1617}
1718
19+ function formatJsonValue ( value : string ) {
20+ return JSON . stringify ( JSON . parse ( value ) , null , 2 ) ;
21+ }
22+
23+ function minifyJsonValue ( value : string ) {
24+ return JSON . stringify ( JSON . parse ( value ) ) ;
25+ }
26+
1827export default function JsonFormatter ( { isDarkMode, onThemeChange } : JsonFormatterProps ) {
1928 const [ jsonText , setJsonText ] = useState ( DEFAULT_JSON ) ;
2029 const [ error , setError ] = useState ( '' ) ;
2130 const [ success , setSuccess ] = useState ( '' ) ;
31+ const pasteDisposableRef = useRef < IDisposable | null > ( null ) ;
2232 const jsonValidation = useMemo ( ( ) => validateJson ( jsonText ) , [ jsonText ] ) ;
2333
2434 const applyJsonValue = useCallback ( ( value : string ) => {
@@ -29,8 +39,7 @@ export default function JsonFormatter({ isDarkMode, onThemeChange }: JsonFormatt
2939
3040 const formatJson = useCallback ( ( ) => {
3141 try {
32- const parsed = JSON . parse ( jsonText ) ;
33- const formatted = JSON . stringify ( parsed , null , 2 ) ;
42+ const formatted = formatJsonValue ( jsonText ) ;
3443 setJsonText ( formatted ) ;
3544 setError ( '' ) ;
3645 setSuccess ( 'JSON formatted successfully!' ) ;
@@ -50,8 +59,7 @@ export default function JsonFormatter({ isDarkMode, onThemeChange }: JsonFormatt
5059
5160 const minifyJson = useCallback ( ( ) => {
5261 try {
53- const parsed = JSON . parse ( jsonText ) ;
54- const minified = JSON . stringify ( parsed ) ;
62+ const minified = minifyJsonValue ( jsonText ) ;
5563 setJsonText ( minified ) ;
5664 setError ( '' ) ;
5765 setSuccess ( 'JSON minified successfully!' ) ;
@@ -113,6 +121,44 @@ export default function JsonFormatter({ isDarkMode, onThemeChange }: JsonFormatt
113121 monaco . editor . defineTheme ( VITESSE_LIGHT_THEME , VITESSE_LIGHT_MONACO_THEME ) ;
114122 } , [ ] ) ;
115123
124+ const handleEditorMount = useCallback < OnMount > ( ( editor ) => {
125+ pasteDisposableRef . current ?. dispose ( ) ;
126+ pasteDisposableRef . current = editor . onDidPaste ( ( ) => {
127+ const value = editor . getValue ( ) ;
128+
129+ try {
130+ const formatted = formatJsonValue ( value ) ;
131+
132+ if ( formatted !== value ) {
133+ const model = editor . getModel ( ) ;
134+
135+ if ( model ) {
136+ editor . executeEdits ( 'auto-format-paste' , [
137+ {
138+ range : model . getFullModelRange ( ) ,
139+ text : formatted ,
140+ forceMoveMarkers : true ,
141+ } ,
142+ ] ) ;
143+ editor . pushUndoStop ( ) ;
144+ }
145+ }
146+
147+ setError ( '' ) ;
148+ setSuccess ( 'JSON formatted successfully!' ) ;
149+ setTimeout ( ( ) => setSuccess ( '' ) , 3000 ) ;
150+ } catch {
151+ // Keep the pasted text unchanged; the existing validation status shows the parse error.
152+ }
153+ } ) ;
154+ } , [ ] ) ;
155+
156+ useEffect ( ( ) => {
157+ return ( ) => {
158+ pasteDisposableRef . current ?. dispose ( ) ;
159+ } ;
160+ } , [ ] ) ;
161+
116162 const themeClass = isDarkMode ? 'dark' : 'light' ;
117163 const editorTheme = isDarkMode ? VITESSE_DARK_THEME : VITESSE_LIGHT_THEME ;
118164 const validationError =
@@ -177,6 +223,7 @@ export default function JsonFormatter({ isDarkMode, onThemeChange }: JsonFormatt
177223 value = { jsonText }
178224 onChange = { handleInputChange }
179225 beforeMount = { registerEditorThemes }
226+ onMount = { handleEditorMount }
180227 theme = { editorTheme }
181228 options = { {
182229 contextmenu : false ,
0 commit comments