@neo4j-cypher/react-codemirror 2.0.0-next.1 → 2.0.0-next.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @neo4j-cypher/react-codemirror
2
2
 
3
+ ## 2.0.0-next.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [a790700]
8
+ - Updated dependencies [08db455]
9
+ - @neo4j-cypher/language-support@2.0.0-next.1
10
+
11
+ ## 2.0.0-next.2
12
+
13
+ ### Patch Changes
14
+
15
+ - 3866e43: Editor history is now a controlled prop
16
+
3
17
  ## 2.0.0-next.1
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -4,7 +4,7 @@ This package can be built with `npm run build` and then published to npm with `n
4
4
 
5
5
  ## Usage
6
6
 
7
- `npm install @neo4j-cypher/reactcodemirror`
7
+ `npm install @neo4j-cypher/react-codemirror@next`
8
8
 
9
9
  ```tsx
10
10
  import { useState } from 'react';
@@ -26,6 +26,9 @@ For a full example, see the [react-codemirror-playground](https://github.com/neo
26
26
 
27
27
  Currently we only support using the codemirror editor via the react wrapper, but we plan to release the codemirror extensions separately as well.
28
28
 
29
+ ## Learning codemirror
30
+ It can take a little time to get into the CodeMirror6 ways of thinking, Trevor Harmon has a [great blog post](https://thetrevorharmon.com/blog/learning-codemirror/) explaining the cm6 "primitives". He also has a demo on how to integrate ANTLR4 with codemirror over [here](https://github.com/thetrevorharmon/zephyr-demo).
31
+
29
32
  ### Completion Icons
30
33
 
31
34
  We use unmodified copies of Visual Studio Code Icons from microsofts repository [here](https://github.com/microsoft/vscode-icons) licensed under creative commons.
@@ -34,6 +34,167 @@ var import_state4 = require("@codemirror/state");
34
34
  var import_view4 = require("@codemirror/view");
35
35
  var import_react = require("react");
36
36
 
37
+ // src/history-navigation.ts
38
+ var import_state = require("@codemirror/state");
39
+ var import_view = require("@codemirror/view");
40
+ var import_state2 = require("@codemirror/state");
41
+ var DRAFT_ENTRY_INDEX = -1;
42
+ var historyInitialState = {
43
+ history: [],
44
+ index: DRAFT_ENTRY_INDEX,
45
+ documentUpdate: null,
46
+ draft: ""
47
+ };
48
+ var historyState = import_state2.StateField.define({
49
+ create() {
50
+ return historyInitialState;
51
+ },
52
+ toJSON(value) {
53
+ return JSON.stringify(value);
54
+ },
55
+ update(value, transaction) {
56
+ for (const effect of transaction.effects) {
57
+ if (effect.is(moveInHistory)) {
58
+ if (value.history.length === 0) {
59
+ return {
60
+ ...value,
61
+ documentUpdate: null
62
+ };
63
+ }
64
+ const currentHistoryIndex = value.index;
65
+ if (effect.value === "BACK") {
66
+ const newHistoryIndex = currentHistoryIndex + 1;
67
+ if (newHistoryIndex === value.history.length) {
68
+ return {
69
+ ...value,
70
+ documentUpdate: null
71
+ };
72
+ }
73
+ let draft = value.draft;
74
+ if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
75
+ draft = transaction.state.doc.toString();
76
+ }
77
+ return {
78
+ ...value,
79
+ draft,
80
+ index: newHistoryIndex,
81
+ documentUpdate: value.history[newHistoryIndex]
82
+ };
83
+ } else if (effect.value === "FORWARDS") {
84
+ const newHistoryIndex = currentHistoryIndex - 1;
85
+ if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
86
+ return { ...value, documentUpdate: null };
87
+ }
88
+ if (newHistoryIndex === DRAFT_ENTRY_INDEX) {
89
+ return {
90
+ ...value,
91
+ index: newHistoryIndex,
92
+ documentUpdate: value.draft
93
+ };
94
+ } else {
95
+ return {
96
+ ...value,
97
+ index: newHistoryIndex,
98
+ documentUpdate: value.history[newHistoryIndex]
99
+ };
100
+ }
101
+ }
102
+ } else if (effect.is(replaceHistory)) {
103
+ return {
104
+ ...value,
105
+ index: DRAFT_ENTRY_INDEX,
106
+ history: effect.value
107
+ };
108
+ }
109
+ }
110
+ return value;
111
+ }
112
+ });
113
+ var moveInHistory = import_state.StateEffect.define();
114
+ var replaceHistory = import_state.StateEffect.define();
115
+ function navigateHistory(view, direction) {
116
+ view.dispatch(
117
+ view.state.update({
118
+ effects: moveInHistory.of(direction),
119
+ selection: { anchor: view.state.doc.length }
120
+ })
121
+ );
122
+ const updatedHistory = view.state.field(historyState, false);
123
+ if (updatedHistory.documentUpdate !== null) {
124
+ view.dispatch(
125
+ view.state.update({
126
+ changes: {
127
+ from: 0,
128
+ to: view.state.doc.length,
129
+ insert: updatedHistory.documentUpdate
130
+ }
131
+ })
132
+ );
133
+ }
134
+ }
135
+ var replMode = ({ history: history2 }) => {
136
+ return [
137
+ historyState.init(() => ({
138
+ ...historyInitialState,
139
+ history: history2
140
+ })),
141
+ import_view.keymap.of([
142
+ {
143
+ key: "ArrowUp",
144
+ preventDefault: true,
145
+ run: (view) => {
146
+ const { empty, head } = view.state.selection.main;
147
+ if (!empty || head !== 0) {
148
+ return false;
149
+ }
150
+ navigateHistory(view, "BACK");
151
+ return true;
152
+ }
153
+ },
154
+ {
155
+ mac: "Cmd-ArrowUp",
156
+ win: "Ctrl-ArrowUp",
157
+ linux: "Ctrl-ArrowUp",
158
+ preventDefault: true,
159
+ run: (view) => {
160
+ const { empty, head } = view.state.selection.main;
161
+ if (!empty || head !== 0) {
162
+ return false;
163
+ }
164
+ navigateHistory(view, "BACK");
165
+ return true;
166
+ }
167
+ },
168
+ {
169
+ key: "ArrowDown",
170
+ preventDefault: true,
171
+ run: (view) => {
172
+ const { empty, head } = view.state.selection.main;
173
+ if (!empty || head !== view.state.doc.length) {
174
+ return false;
175
+ }
176
+ navigateHistory(view, "FORWARDS");
177
+ return true;
178
+ }
179
+ },
180
+ {
181
+ mac: "Cmd-ArrowDown",
182
+ win: "Ctrl-ArrowDown",
183
+ linux: "Ctrl-ArrowDown",
184
+ preventDefault: true,
185
+ run: (view) => {
186
+ const { empty, head } = view.state.selection.main;
187
+ if (!empty || head !== view.state.doc.length) {
188
+ return false;
189
+ }
190
+ navigateHistory(view, "FORWARDS");
191
+ return true;
192
+ }
193
+ }
194
+ ])
195
+ ];
196
+ };
197
+
37
198
  // src/lang-cypher/lang-cypher.ts
38
199
  var import_language2 = require("@codemirror/language");
39
200
 
@@ -257,8 +418,8 @@ var import_autocomplete2 = require("@codemirror/autocomplete");
257
418
  var import_commands = require("@codemirror/commands");
258
419
  var import_language3 = require("@codemirror/language");
259
420
  var import_search = require("@codemirror/search");
260
- var import_state = require("@codemirror/state");
261
- var import_view = require("@codemirror/view");
421
+ var import_state3 = require("@codemirror/state");
422
+ var import_view2 = require("@codemirror/view");
262
423
  var import_lint2 = require("@codemirror/lint");
263
424
 
264
425
  // src/icons.ts
@@ -366,11 +527,11 @@ var basicNeo4jSetup = () => {
366
527
  }
367
528
  ].flat();
368
529
  const extensions = [];
369
- extensions.push((0, import_view.highlightSpecialChars)());
530
+ extensions.push((0, import_view2.highlightSpecialChars)());
370
531
  extensions.push((0, import_commands.history)());
371
- extensions.push((0, import_view.drawSelection)());
372
- extensions.push((0, import_view.dropCursor)());
373
- extensions.push(import_state.EditorState.allowMultipleSelections.of(true));
532
+ extensions.push((0, import_view2.drawSelection)());
533
+ extensions.push((0, import_view2.dropCursor)());
534
+ extensions.push(import_state3.EditorState.allowMultipleSelections.of(true));
374
535
  extensions.push((0, import_language3.indentOnInput)());
375
536
  extensions.push(
376
537
  (0, import_language3.syntaxHighlighting)(import_language3.defaultHighlightStyle, { fallback: true })
@@ -384,7 +545,7 @@ var basicNeo4jSetup = () => {
384
545
  addToOptions: [
385
546
  {
386
547
  render(completion, state) {
387
- const isDarkTheme = state.facet(import_view.EditorView.darkTheme);
548
+ const isDarkTheme = state.facet(import_view2.EditorView.darkTheme);
388
549
  const icon = document.createElement("span");
389
550
  icon.innerHTML = getIconForType(completion.type, isDarkTheme);
390
551
  const svgElement = icon.children[0];
@@ -397,194 +558,13 @@ var basicNeo4jSetup = () => {
397
558
  ]
398
559
  })
399
560
  );
400
- extensions.push((0, import_view.rectangularSelection)());
401
- extensions.push((0, import_view.crosshairCursor)());
561
+ extensions.push((0, import_view2.rectangularSelection)());
562
+ extensions.push((0, import_view2.crosshairCursor)());
402
563
  extensions.push((0, import_search.highlightSelectionMatches)());
403
- extensions.push(import_view.keymap.of(keymaps));
564
+ extensions.push(import_view2.keymap.of(keymaps));
404
565
  return extensions;
405
566
  };
406
567
 
407
- // src/repl-mode.ts
408
- var import_state2 = require("@codemirror/state");
409
- var import_view2 = require("@codemirror/view");
410
- var import_state3 = require("@codemirror/state");
411
- var DRAFT_ENTRY_INDEX = -1;
412
- var historyInitialState = {
413
- history: [],
414
- index: DRAFT_ENTRY_INDEX,
415
- documentUpdate: null,
416
- draft: ""
417
- };
418
- var historyState = import_state3.StateField.define({
419
- create() {
420
- return historyInitialState;
421
- },
422
- toJSON(value) {
423
- return JSON.stringify(value);
424
- },
425
- update(value, transaction) {
426
- for (const effect of transaction.effects) {
427
- if (effect.is(moveInHistory)) {
428
- if (value.history.length === 0) {
429
- return {
430
- ...value,
431
- documentUpdate: null
432
- };
433
- }
434
- const currentHistoryIndex = value.index;
435
- if (effect.value === "BACK") {
436
- const newHistoryIndex = currentHistoryIndex + 1;
437
- if (newHistoryIndex === value.history.length) {
438
- return {
439
- ...value,
440
- documentUpdate: null
441
- };
442
- }
443
- let draft = value.draft;
444
- if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
445
- draft = transaction.state.doc.toString();
446
- }
447
- return {
448
- ...value,
449
- draft,
450
- index: newHistoryIndex,
451
- documentUpdate: value.history[newHistoryIndex]
452
- };
453
- } else if (effect.value === "FORWARDS") {
454
- const newHistoryIndex = currentHistoryIndex - 1;
455
- if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
456
- return { ...value, documentUpdate: null };
457
- }
458
- if (newHistoryIndex === DRAFT_ENTRY_INDEX) {
459
- return {
460
- ...value,
461
- index: newHistoryIndex,
462
- documentUpdate: value.draft
463
- };
464
- } else {
465
- return {
466
- ...value,
467
- index: newHistoryIndex,
468
- documentUpdate: value.history[newHistoryIndex]
469
- };
470
- }
471
- }
472
- } else if (effect.is(pushToHistory)) {
473
- return {
474
- ...value,
475
- index: DRAFT_ENTRY_INDEX,
476
- history: [effect.value, ...value.history]
477
- };
478
- }
479
- }
480
- return value;
481
- }
482
- });
483
- var moveInHistory = import_state2.StateEffect.define();
484
- var pushToHistory = import_state2.StateEffect.define();
485
- function navigateHistory(view, direction) {
486
- view.dispatch(
487
- view.state.update({
488
- effects: moveInHistory.of(direction),
489
- selection: { anchor: view.state.doc.length }
490
- })
491
- );
492
- const updatedHistory = view.state.field(historyState, false);
493
- if (updatedHistory.documentUpdate !== null) {
494
- view.dispatch(
495
- view.state.update({
496
- changes: {
497
- from: 0,
498
- to: view.state.doc.length,
499
- insert: updatedHistory.documentUpdate
500
- }
501
- })
502
- );
503
- }
504
- }
505
- var replMode = ({
506
- onExecute,
507
- onNewHistoryEntry,
508
- initialHistory
509
- }) => {
510
- return [
511
- historyState.init(() => ({
512
- ...historyInitialState,
513
- history: initialHistory
514
- })),
515
- import_view2.keymap.of([
516
- {
517
- key: "Ctrl-Enter",
518
- mac: "Mod-Enter",
519
- preventDefault: true,
520
- run: (view) => {
521
- const doc = view.state.doc.toString();
522
- if (doc.trim() !== "") {
523
- onExecute?.(doc);
524
- onNewHistoryEntry?.(doc);
525
- view.dispatch({
526
- effects: pushToHistory.of(doc)
527
- });
528
- }
529
- return true;
530
- }
531
- },
532
- {
533
- key: "ArrowUp",
534
- preventDefault: true,
535
- run: (view) => {
536
- const { empty, head } = view.state.selection.main;
537
- if (!empty || head !== 0) {
538
- return false;
539
- }
540
- navigateHistory(view, "BACK");
541
- return true;
542
- }
543
- },
544
- {
545
- mac: "Cmd-ArrowUp",
546
- win: "Ctrl-ArrowUp",
547
- linux: "Ctrl-ArrowUp",
548
- preventDefault: true,
549
- run: (view) => {
550
- const { empty, head } = view.state.selection.main;
551
- if (!empty || head !== 0) {
552
- return false;
553
- }
554
- navigateHistory(view, "BACK");
555
- return true;
556
- }
557
- },
558
- {
559
- key: "ArrowDown",
560
- preventDefault: true,
561
- run: (view) => {
562
- const { empty, head } = view.state.selection.main;
563
- if (!empty || head !== view.state.doc.length) {
564
- return false;
565
- }
566
- navigateHistory(view, "FORWARDS");
567
- return true;
568
- }
569
- },
570
- {
571
- mac: "Cmd-ArrowDown",
572
- win: "Ctrl-ArrowDown",
573
- linux: "Ctrl-ArrowDown",
574
- preventDefault: true,
575
- run: (view) => {
576
- const { empty, head } = view.state.selection.main;
577
- if (!empty || head !== view.state.doc.length) {
578
- return false;
579
- }
580
- navigateHistory(view, "FORWARDS");
581
- return true;
582
- }
583
- }
584
- ])
585
- ];
586
- };
587
-
588
568
  // src/themes.ts
589
569
  var import_ayu = require("ayu");
590
570
 
@@ -1267,6 +1247,20 @@ function getThemeExtension(theme, inheritBgColor) {
1267
1247
 
1268
1248
  // src/CypherEditor.tsx
1269
1249
  var import_jsx_runtime = require("react/jsx-runtime");
1250
+ var executeKeybinding = (onExecute) => onExecute ? [
1251
+ {
1252
+ key: "Ctrl-Enter",
1253
+ mac: "Mod-Enter",
1254
+ preventDefault: true,
1255
+ run: (view) => {
1256
+ const doc = view.state.doc.toString();
1257
+ if (doc.trim() !== "") {
1258
+ onExecute(doc);
1259
+ }
1260
+ return true;
1261
+ }
1262
+ }
1263
+ ] : [];
1270
1264
  var themeCompartment = new import_state4.Compartment();
1271
1265
  var keyBindingCompartment = new import_state4.Compartment();
1272
1266
  var ExternalEdit = import_state4.Annotation.define();
@@ -1320,28 +1314,21 @@ var CypherEditor = class extends import_react.Component {
1320
1314
  overrideThemeBackgroundColor: false,
1321
1315
  lineWrap: false,
1322
1316
  extraKeybindings: [],
1323
- initialHistory: [],
1317
+ history: [],
1324
1318
  theme: "light"
1325
1319
  };
1326
1320
  componentDidMount() {
1327
1321
  const {
1328
1322
  theme,
1329
- onExecute,
1330
- initialHistory,
1331
- onNewHistoryEntry,
1332
1323
  extraKeybindings,
1333
1324
  lineWrap,
1334
1325
  overrideThemeBackgroundColor,
1335
1326
  schema,
1336
1327
  lint,
1337
- onChange
1328
+ onChange,
1329
+ onExecute
1338
1330
  } = this.props;
1339
1331
  this.schemaRef.current = { schema, lint };
1340
- const maybeReplMode = onExecute ? replMode({
1341
- onExecute,
1342
- initialHistory,
1343
- onNewHistoryEntry
1344
- }) : [];
1345
1332
  const themeExtension = getThemeExtension(
1346
1333
  theme,
1347
1334
  overrideThemeBackgroundColor
@@ -1360,12 +1347,14 @@ var CypherEditor = class extends import_react.Component {
1360
1347
  ] : [];
1361
1348
  this.editorState.current = import_state4.EditorState.create({
1362
1349
  extensions: [
1363
- maybeReplMode,
1350
+ keyBindingCompartment.of(
1351
+ import_view4.keymap.of([...executeKeybinding(onExecute), ...extraKeybindings])
1352
+ ),
1353
+ replMode(this.props),
1364
1354
  basicNeo4jSetup(),
1365
1355
  themeCompartment.of(themeExtension),
1366
1356
  changeListener,
1367
1357
  cypher(this.schemaRef.current),
1368
- keyBindingCompartment.of(import_view4.keymap.of(extraKeybindings)),
1369
1358
  lineWrap ? import_view4.EditorView.lineWrapping : [],
1370
1359
  (0, import_view4.lineNumbers)({
1371
1360
  formatNumber: (a, state) => {
@@ -1415,13 +1404,21 @@ var CypherEditor = class extends import_react.Component {
1415
1404
  )
1416
1405
  });
1417
1406
  }
1418
- if (prevProps.extraKeybindings !== this.props.extraKeybindings) {
1407
+ if (prevProps.extraKeybindings !== this.props.extraKeybindings || prevProps.onExecute !== this.props.onExecute) {
1419
1408
  this.editorView.current.dispatch({
1420
1409
  effects: keyBindingCompartment.reconfigure(
1421
- import_view4.keymap.of(this.props.extraKeybindings)
1410
+ import_view4.keymap.of([
1411
+ ...executeKeybinding(this.props.onExecute),
1412
+ ...this.props.extraKeybindings
1413
+ ])
1422
1414
  )
1423
1415
  });
1424
1416
  }
1417
+ if (prevProps.history?.length !== this.props.history?.length) {
1418
+ this.editorView.current.dispatch({
1419
+ effects: replaceHistory.of(this.props.history ?? [])
1420
+ });
1421
+ }
1425
1422
  this.schemaRef.current.schema = this.props.schema;
1426
1423
  this.schemaRef.current.lint = this.props.lint;
1427
1424
  }