Skip to content

Commit

Permalink
Make editor history controlled and onExecute reactive (#136)
Browse files Browse the repository at this point in the history
* make editor history controlled

* docs

* add changeset for controlled editor history

* fix-build

* add changeset
  • Loading branch information
OskarDamkjaer authored Nov 10, 2023
1 parent 706cd60 commit 37e41a4
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 77 deletions.
3 changes: 2 additions & 1 deletion .changeset/pre.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"changesets": [
"brown-ravens-obey",
"fuzzy-rice-train",
"nervous-rabbits-greet"
"nervous-rabbits-greet",
"quick-berries-report"
]
}
5 changes: 5 additions & 0 deletions .changeset/quick-berries-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@neo4j-cypher/react-codemirror': patch
---

Editor history is now a controlled prop
31 changes: 25 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions packages/react-codemirror-playground/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @neo4j-cypher/react-codemirror-playground

## 2.0.0-next.2

### Patch Changes

- Updated dependencies [3866e43]
- @neo4j-cypher/react-codemirror@2.0.0-next.2

## 2.0.0-next.1

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/react-codemirror-playground/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@neo4j-cypher/react-codemirror-playground",
"private": true,
"version": "2.0.0-next.1",
"version": "2.0.0-next.2",
"type": "module",
"scripts": {
"dev": "vite --open",
Expand All @@ -21,7 +21,7 @@
},
"dependencies": {
"@neo4j-cypher/language-support": "2.0.0-next.0",
"@neo4j-cypher/react-codemirror": "2.0.0-next.1",
"@neo4j-cypher/react-codemirror": "2.0.0-next.2",
"@codemirror/autocomplete": "^6.5.1",
"@codemirror/commands": "^6.2.2",
"@codemirror/language": "^6.6.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-codemirror-playground/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export function App() {
prompt="neo4j$"
onExecute={() => setCommandRanCount((c) => c + 1)}
theme={darkMode ? 'dark' : 'light'}
initialHistory={Object.values(demos)}
history={Object.values(demos)}
schema={schema}
/>

Expand Down
6 changes: 6 additions & 0 deletions packages/react-codemirror/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @neo4j-cypher/react-codemirror

## 2.0.0-next.2

### Patch Changes

- 3866e43: Editor history is now a controlled prop

## 2.0.0-next.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/react-codemirror/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"codemirror",
"codemirror 6"
],
"version": "2.0.0-next.1",
"version": "2.0.0-next.2",
"main": "./dist/cjs/index.cjs",
"module": "./dist/esm/index.mjs",
"types": "./dist/types/index.d.ts",
Expand Down
71 changes: 46 additions & 25 deletions packages/react-codemirror/src/CypherEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ import {
} from '@codemirror/view';
import type { DbSchema } from '@neo4j-cypher/language-support';
import { Component, createRef } from 'react';
import {
replaceHistory,
replMode as historyNavigation,
} from './history-navigation';
import { cypher, CypherConfig } from './lang-cypher/lang-cypher';
import { basicNeo4jSetup } from './neo4j-setup';
import { replMode } from './repl-mode';
import { getThemeExtension } from './themes';

export interface CypherEditorProps {
Expand All @@ -37,15 +40,10 @@ export interface CypherEditorProps {
*/
onExecute?: (cmd: string) => void;
/**
* Seed the editor history with some initial history entries
* Navigateable via up/down arrow keys
*/
initialHistory?: string[];
/**
* Callback when a new history entry is added, useful for keeping track of history
* outside of the editor.
* The editor history navigateable via up/down arrow keys. Order newest to oldest.
* Add to this list with the `onExecute` callback for REPL style history.
*/
onNewHistoryEntry?: (historyEntry: string) => void;
history?: string[];
/**
* When set to `true` the editor will use the background color of the parent element.
*
Expand Down Expand Up @@ -100,6 +98,25 @@ export interface CypherEditorProps {
onChange?(value: string, viewUpdate: ViewUpdate): void;
}

const executeKeybinding = (onExecute?: (cmd: string) => void) =>
onExecute
? [
{
key: 'Ctrl-Enter',
mac: 'Mod-Enter',
preventDefault: true,
run: (view: EditorView) => {
const doc = view.state.doc.toString();
if (doc.trim() !== '') {
onExecute(doc);
}

return true;
},
},
]
: [];

const themeCompartment = new Compartment();
const keyBindingCompartment = new Compartment();

Expand Down Expand Up @@ -158,34 +175,24 @@ export class CypherEditor extends Component<CypherEditorProps> {
overrideThemeBackgroundColor: false,
lineWrap: false,
extraKeybindings: [],
initialHistory: [],
history: [],
theme: 'light',
};

componentDidMount(): void {
const {
theme,
onExecute,
initialHistory,
onNewHistoryEntry,
extraKeybindings,
lineWrap,
overrideThemeBackgroundColor,
schema,
lint,
onChange,
onExecute,
} = this.props;

this.schemaRef.current = { schema, lint };

const maybeReplMode = onExecute
? replMode({
onExecute,
initialHistory,
onNewHistoryEntry,
})
: [];

const themeExtension = getThemeExtension(
theme,
overrideThemeBackgroundColor,
Expand All @@ -209,12 +216,14 @@ export class CypherEditor extends Component<CypherEditorProps> {

this.editorState.current = EditorState.create({
extensions: [
maybeReplMode,
keyBindingCompartment.of(
keymap.of([...executeKeybinding(onExecute), ...extraKeybindings]),
),
historyNavigation(this.props),
basicNeo4jSetup(),
themeCompartment.of(themeExtension),
changeListener,
cypher(this.schemaRef.current),
keyBindingCompartment.of(keymap.of(extraKeybindings)),
lineWrap ? EditorView.lineWrapping : [],

lineNumbers({
Expand Down Expand Up @@ -279,14 +288,26 @@ export class CypherEditor extends Component<CypherEditorProps> {
});
}

if (prevProps.extraKeybindings !== this.props.extraKeybindings) {
if (
prevProps.extraKeybindings !== this.props.extraKeybindings ||
prevProps.onExecute !== this.props.onExecute
) {
this.editorView.current.dispatch({
effects: keyBindingCompartment.reconfigure(
keymap.of(this.props.extraKeybindings),
keymap.of([
...executeKeybinding(this.props.onExecute),
...this.props.extraKeybindings,
]),
),
});
}

if (prevProps.history?.length !== this.props.history?.length) {
this.editorView.current.dispatch({
effects: replaceHistory.of(this.props.history ?? []),
});
}

/*
The cypher configuration is a mutable object that is passed to the cypher language extension.
Much like how the schema based completions work in the official sql language extension.
Expand Down
Loading

0 comments on commit 37e41a4

Please sign in to comment.