9
9
KeyBinding ,
10
10
keymap ,
11
11
lineNumbers ,
12
+ placeholder ,
12
13
ViewUpdate ,
13
14
} from '@codemirror/view' ;
14
15
import type { DbSchema } from '@neo4j-cypher/language-support' ;
@@ -23,6 +24,7 @@ import { cleanupWorkers } from './lang-cypher/syntaxValidation';
23
24
import { basicNeo4jSetup } from './neo4jSetup' ;
24
25
import { getThemeExtension } from './themes' ;
25
26
27
+ type DomEventHandlers = Parameters < typeof EditorView . domEventHandlers > [ 0 ] ;
26
28
export interface CypherEditorProps {
27
29
/**
28
30
* The prompt to show on single line editors
@@ -42,7 +44,7 @@ export interface CypherEditorProps {
42
44
*/
43
45
onExecute ?: ( cmd : string ) => void ;
44
46
/**
45
- * The editor history navigateable via up/down arrow keys. Order newest to oldest.
47
+ * The editor history navigable via up/down arrow keys. Order newest to oldest.
46
48
* Add to this list with the `onExecute` callback for REPL style history.
47
49
*/
48
50
history ?: string [ ] ;
@@ -102,6 +104,37 @@ export interface CypherEditorProps {
102
104
* @param {ViewUpdate } viewUpdate - the view update from codemirror
103
105
*/
104
106
onChange ?( value : string , viewUpdate : ViewUpdate ) : void ;
107
+
108
+ /**
109
+ * Map of event handlers to add to the editor.
110
+ *
111
+ * Note that the props are compared by reference, meaning object defined inline
112
+ * will cause the editor to re-render (much like the style prop does in this example:
113
+ * <div style={{}} />
114
+ *
115
+ * Memoize the object if you want/need to avoid this.
116
+ *
117
+ * @example
118
+ * // listen to blur events
119
+ * <CypherEditor domEventHandlers={{blur: () => console.log("blur event fired")}} />
120
+ */
121
+ domEventHandlers ?: DomEventHandlers ;
122
+ /**
123
+ * Placeholder text to display when the editor is empty.
124
+ */
125
+ placeholder ?: string ;
126
+ /**
127
+ * Whether the editor should show line numbers.
128
+ *
129
+ * @default true
130
+ */
131
+ lineNumbers ?: boolean ;
132
+ /**
133
+ * Whether the editor is read-only.
134
+ *
135
+ * @default false
136
+ */
137
+ readonly ?: boolean ;
105
138
}
106
139
107
140
const executeKeybinding = ( onExecute ?: ( cmd : string ) => void ) =>
@@ -125,6 +158,20 @@ const executeKeybinding = (onExecute?: (cmd: string) => void) =>
125
158
126
159
const themeCompartment = new Compartment ( ) ;
127
160
const keyBindingCompartment = new Compartment ( ) ;
161
+ const lineNumbersCompartment = new Compartment ( ) ;
162
+ const readOnlyCompartment = new Compartment ( ) ;
163
+ const placeholderCompartment = new Compartment ( ) ;
164
+ const domEventHandlerCompartment = new Compartment ( ) ;
165
+
166
+ const formatLineNumber =
167
+ ( prompt ?: string ) => ( a : number , state : EditorState ) => {
168
+ if ( state . doc . lines === 1 && prompt !== undefined ) {
169
+ return prompt ;
170
+ }
171
+
172
+ return a . toString ( ) ;
173
+ } ;
174
+
128
175
type CypherEditorState = { cypherSupportEnabled : boolean } ;
129
176
130
177
const ExternalEdit = Annotation . define < boolean > ( ) ;
@@ -188,6 +235,7 @@ export class CypherEditor extends Component<
188
235
extraKeybindings : [ ] ,
189
236
history : [ ] ,
190
237
theme : 'light' ,
238
+ lineNumbers : true ,
191
239
} ;
192
240
193
241
private debouncedOnChange = this . props . onChange
@@ -249,15 +297,20 @@ export class CypherEditor extends Component<
249
297
cypher ( this . schemaRef . current ) ,
250
298
lineWrap ? EditorView . lineWrapping : [ ] ,
251
299
252
- lineNumbers ( {
253
- formatNumber : ( a , state ) => {
254
- if ( state . doc . lines === 1 && this . props . prompt !== undefined ) {
255
- return this . props . prompt ;
256
- }
257
-
258
- return a . toString ( ) ;
259
- } ,
260
- } ) ,
300
+ lineNumbersCompartment . of (
301
+ this . props . lineNumbers
302
+ ? lineNumbers ( { formatNumber : formatLineNumber ( this . props . prompt ) } )
303
+ : [ ] ,
304
+ ) ,
305
+ readOnlyCompartment . of ( EditorState . readOnly . of ( this . props . readonly ) ) ,
306
+ placeholderCompartment . of (
307
+ this . props . placeholder ? placeholder ( this . props . placeholder ) : [ ] ,
308
+ ) ,
309
+ domEventHandlerCompartment . of (
310
+ this . props . domEventHandlers
311
+ ? EditorView . domEventHandlers ( this . props . domEventHandlers )
312
+ : [ ] ,
313
+ ) ,
261
314
] ,
262
315
doc : this . props . value ,
263
316
} ) ;
@@ -313,6 +366,35 @@ export class CypherEditor extends Component<
313
366
} ) ;
314
367
}
315
368
369
+ if (
370
+ prevProps . lineNumbers !== this . props . lineNumbers ||
371
+ prevProps . prompt !== this . props . prompt
372
+ ) {
373
+ this . editorView . current . dispatch ( {
374
+ effects : lineNumbersCompartment . reconfigure (
375
+ this . props . lineNumbers
376
+ ? lineNumbers ( { formatNumber : formatLineNumber ( this . props . prompt ) } )
377
+ : [ ] ,
378
+ ) ,
379
+ } ) ;
380
+ }
381
+
382
+ if ( prevProps . readonly !== this . props . readonly ) {
383
+ this . editorView . current . dispatch ( {
384
+ effects : readOnlyCompartment . reconfigure (
385
+ EditorState . readOnly . of ( this . props . readonly ) ,
386
+ ) ,
387
+ } ) ;
388
+ }
389
+
390
+ if ( prevProps . placeholder !== this . props . placeholder ) {
391
+ this . editorView . current . dispatch ( {
392
+ effects : placeholderCompartment . reconfigure (
393
+ this . props . placeholder ? placeholder ( this . props . placeholder ) : [ ] ,
394
+ ) ,
395
+ } ) ;
396
+ }
397
+
316
398
if (
317
399
prevProps . extraKeybindings !== this . props . extraKeybindings ||
318
400
prevProps . onExecute !== this . props . onExecute
@@ -327,6 +409,16 @@ export class CypherEditor extends Component<
327
409
} ) ;
328
410
}
329
411
412
+ if ( prevProps . domEventHandlers !== this . props . domEventHandlers ) {
413
+ this . editorView . current . dispatch ( {
414
+ effects : domEventHandlerCompartment . reconfigure (
415
+ this . props . domEventHandlers
416
+ ? EditorView . domEventHandlers ( this . props . domEventHandlers )
417
+ : [ ] ,
418
+ ) ,
419
+ } ) ;
420
+ }
421
+
330
422
// This component rerenders on every keystroke and comparing the
331
423
// full lists of editor strings on every render could be expensive.
332
424
const didChangeHistoryEstimate =
0 commit comments