@@ -34,6 +34,55 @@ export const Editor = ({
34
34
const divEl = useRef < HTMLDivElement > ( null ) ;
35
35
const editorRef =
36
36
useRef < import ( 'monaco-editor' ) . editor . IStandaloneCodeEditor > ( null ) ;
37
+ const urlUpdateTimer = useRef < number | null > ( null ) ;
38
+
39
+ function decodeParam ( value : string | null ) : string | null {
40
+ if ( ! value ) return null ;
41
+ try {
42
+ return decodeURIComponent ( value ) ;
43
+ } catch {
44
+ return value ;
45
+ }
46
+ }
47
+
48
+ function getInitialCode ( ) : string {
49
+ if ( typeof window === 'undefined' ) {
50
+ return [ 'let a: any;' , 'a.b = 10;' ] . join ( '\n' ) ;
51
+ }
52
+ const { search, hash } = window . location ;
53
+ const searchParams = new URLSearchParams ( search ) ;
54
+ // URLSearchParams.get already decodes percent-encoding
55
+ const fromSearch = searchParams . get ( 'code' ) ;
56
+ if ( fromSearch != null ) return fromSearch ;
57
+ // Also support hash like #code=...
58
+ if ( hash && hash . startsWith ( '#' ) ) {
59
+ const hashParams = new URLSearchParams ( hash . slice ( 1 ) ) ;
60
+ const fromHash = hashParams . get ( 'code' ) ;
61
+ if ( fromHash != null ) return fromHash ;
62
+ }
63
+ return [ 'let a: any;' , 'a.b = 10;' ] . join ( '\n' ) ;
64
+ }
65
+
66
+ function scheduleSerializeToUrl ( value : string ) {
67
+ if ( typeof window === 'undefined' ) return ;
68
+ if ( urlUpdateTimer . current ) {
69
+ window . clearTimeout ( urlUpdateTimer . current ) ;
70
+ urlUpdateTimer . current = null ;
71
+ }
72
+ urlUpdateTimer . current = window . setTimeout ( ( ) => {
73
+ try {
74
+ const url = new URL ( window . location . href ) ;
75
+ url . searchParams . set ( 'code' , value ) ;
76
+ // Remove any code=... from hash if present to avoid ambiguity
77
+ if ( url . hash && url . hash . includes ( 'code=' ) ) {
78
+ url . hash = '' ;
79
+ }
80
+ window . history . replaceState ( null , '' , url . toString ( ) ) ;
81
+ } catch {
82
+ // ignore URL update errors
83
+ }
84
+ } , 300 ) ;
85
+ }
37
86
// get value from editor using forwardRef
38
87
React . useImperativeHandle ( ref , ( ) => ( {
39
88
getValue : ( ) => editorRef . current ?. getValue ( ) ,
@@ -68,15 +117,24 @@ export const Editor = ({
68
117
}
69
118
70
119
const editor = monaco . editor . create ( divEl . current , {
71
- value : [ 'let a: any;' , 'a.b = 10;' ] . join ( '\n' ) ,
120
+ value : getInitialCode ( ) ,
72
121
language : 'typescript' ,
73
122
automaticLayout : true ,
74
123
scrollBeyondLastLine : false ,
75
124
} ) ;
125
+ // Ensure ref is set before first onChange so parent can read value
126
+ editorRef . current = editor ;
127
+ // Trigger initial onChange + URL sync with initial value
128
+ {
129
+ const initialVal = editor . getValue ( ) || '' ;
130
+ onChange ( initialVal ) ;
131
+ scheduleSerializeToUrl ( initialVal ) ;
132
+ }
76
133
editor . onDidChangeModelContent ( ( ) => {
77
- onChange ( editor . getValue ( ) || '' ) ;
134
+ const val = editor . getValue ( ) || '' ;
135
+ onChange ( val ) ;
136
+ scheduleSerializeToUrl ( val ) ;
78
137
} ) ;
79
- editorRef . current = editor ;
80
138
81
139
return ( ) => {
82
140
editor . dispose ( ) ;
0 commit comments