mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(editor): Improve UX for brace completion from selection (#5024)
⚡ Improve UX for brace completion from selection
This commit is contained in:
parent
afc529799d
commit
52077e2c45
|
@ -39,15 +39,32 @@ export default mixins(expressionManager, workflowHelpers).extend({
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value(newValue) {
|
value(newValue) {
|
||||||
try {
|
const payload: Record<string, unknown> = {
|
||||||
this.editor?.dispatch({
|
|
||||||
changes: {
|
changes: {
|
||||||
from: 0,
|
from: 0,
|
||||||
to: this.editor.state.doc.length,
|
to: this.editor?.state.doc.length,
|
||||||
insert: newValue,
|
insert: newValue,
|
||||||
},
|
},
|
||||||
selection: { anchor: this.cursorPosition, head: this.cursorPosition },
|
selection: { anchor: this.cursorPosition, head: this.cursorPosition },
|
||||||
});
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If completion from selection, preserve selection.
|
||||||
|
*/
|
||||||
|
if (this.editor) {
|
||||||
|
const [range] = this.editor.state.selection.ranges;
|
||||||
|
|
||||||
|
const isBraceAutoinsertion =
|
||||||
|
this.editor.state.sliceDoc(range.from - 1, range.from) === '{' &&
|
||||||
|
this.editor.state.sliceDoc(range.to, range.to + 1) === '}';
|
||||||
|
|
||||||
|
if (isBraceAutoinsertion) {
|
||||||
|
payload.selection = { anchor: range.from, head: range.to };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.editor?.dispatch(payload);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// ignore out-of-range selection error on drop
|
// ignore out-of-range selection error on drop
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,19 +23,18 @@ const inputHandler = EditorView.inputHandler.of((view, from, to, insert) => {
|
||||||
view.dispatch(transaction);
|
view.dispatch(transaction);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customizations to inject whitespace and braces
|
* Customizations to inject whitespace and braces for setup and completion
|
||||||
* for resolvable setup and completion
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const cursor = view.state.selection.main.head;
|
const cursor = view.state.selection.main.head;
|
||||||
|
|
||||||
// inject whitespace and second brace on completion: {| } -> {{ | }}
|
// inject whitespace and second brace for brace completion: {| } -> {{ | }}
|
||||||
|
|
||||||
const isSecondBraceForNewExpression =
|
const isBraceCompletion =
|
||||||
view.state.sliceDoc(cursor - 2, cursor) === '{{' &&
|
view.state.sliceDoc(cursor - 2, cursor) === '{{' &&
|
||||||
view.state.sliceDoc(cursor, cursor + 1) === '}';
|
view.state.sliceDoc(cursor, cursor + 1) === '}';
|
||||||
|
|
||||||
if (isSecondBraceForNewExpression) {
|
if (isBraceCompletion) {
|
||||||
view.dispatch({
|
view.dispatch({
|
||||||
changes: { from: cursor, to: cursor + 2, insert: ' }' },
|
changes: { from: cursor, to: cursor + 2, insert: ' }' },
|
||||||
selection: { anchor: cursor + 1 },
|
selection: { anchor: cursor + 1 },
|
||||||
|
@ -44,28 +43,30 @@ const inputHandler = EditorView.inputHandler.of((view, from, to, insert) => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// inject whitespace on setup: empty -> {| }
|
// inject whitespace for brace setup: empty -> {| }
|
||||||
|
|
||||||
const isFirstBraceForNewExpression =
|
const isBraceSetup =
|
||||||
view.state.sliceDoc(cursor - 1, cursor) === '{' &&
|
view.state.sliceDoc(cursor - 1, cursor) === '{' &&
|
||||||
view.state.sliceDoc(cursor, cursor + 1) === '}';
|
view.state.sliceDoc(cursor, cursor + 1) === '}';
|
||||||
|
|
||||||
if (isFirstBraceForNewExpression) {
|
if (isBraceSetup) {
|
||||||
view.dispatch({ changes: { from: cursor, insert: ' ' } });
|
view.dispatch({ changes: { from: cursor, insert: ' ' } });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// when selected, surround with whitespaces on completion: {{abc}} -> {{ abc }}
|
// inject whitespace for brace completion from selection: {{abc|}} -> {{ abc| }}
|
||||||
|
|
||||||
const doc = view.state.doc.toString();
|
const [range] = view.state.selection.ranges;
|
||||||
const openMarkerIndex = doc.lastIndexOf('{', cursor);
|
|
||||||
const closeMarkerIndex = doc.indexOf('}}', cursor);
|
|
||||||
|
|
||||||
if (openMarkerIndex !== -1 && closeMarkerIndex !== -1) {
|
const isBraceCompletionFromSelection =
|
||||||
|
view.state.sliceDoc(range.from - 2, range.from) === '{{' &&
|
||||||
|
view.state.sliceDoc(range.to, range.to + 2) === '}}';
|
||||||
|
|
||||||
|
if (isBraceCompletionFromSelection) {
|
||||||
view.dispatch(
|
view.dispatch(
|
||||||
{ changes: { from: openMarkerIndex + 1, insert: ' ' } },
|
{ changes: { from: range.from, insert: ' ' } },
|
||||||
{ changes: { from: closeMarkerIndex, insert: ' ' } },
|
{ changes: { from: range.to, insert: ' ' }, selection: { anchor: range.to, head: range.to } },
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue