Skip to content

Commit d88c170

Browse files
authored
fix(Designer): Added tab indentation option to code editor (#8670)
* Added tab indention option to code editor * Updated unit tests
1 parent c18bd81 commit d88c170

File tree

6 files changed

+48
-8
lines changed

6 files changed

+48
-8
lines changed

apps/Standalone/src/designer/app/AzureLogicAppsDesigner/CodeViewV2.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useMount } from '@fluentui/react-hooks';
22
import type { EditorContentChangedEventArgs } from '@microsoft/designer-ui';
3-
import { MonacoEditor } from '@microsoft/designer-ui';
3+
import { CodeMirrorEditor } from '@microsoft/designer-ui';
44
import { serializeBJSWorkflow, store as DesignerStore, setIsWorkflowDirty, useIsWorkflowDirty } from '@microsoft/logic-apps-designer-v2';
55
import type { AppDispatch } from '@microsoft/logic-apps-designer-v2';
66
import { EditorLanguage, isNullOrUndefined } from '@microsoft/logic-apps-shared';
@@ -60,14 +60,15 @@ const CodeViewEditor = forwardRef(({ workflowKind, isConsumption }: CodeViewProp
6060
return (
6161
<div>
6262
{isNullOrUndefined(code) ? null : (
63-
<MonacoEditor
64-
height="95vh"
63+
<CodeMirrorEditor
64+
height="100vh"
6565
language={EditorLanguage.json}
6666
value={code}
6767
overviewRulerBorder={true}
6868
scrollBeyondLastLine={false}
6969
fontSize={13}
7070
onContentChanged={handleContentChanged}
71+
indentWithTab={true}
7172
/>
7273
)}
7374
</div>

libs/designer-ui/src/lib/editor/codemirror/CodeMirrorEditor.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export const CodeMirrorEditor = forwardRef<CodeMirrorEditorRef, CodeMirrorEditor
8080
onEditorRef,
8181
onMouseDown,
8282
openTokenPicker,
83+
indentWithTab,
8384
},
8485
ref
8586
) => {
@@ -171,7 +172,7 @@ export const CodeMirrorEditor = forwardRef<CodeMirrorEditorRef, CodeMirrorEditor
171172
onScrollChanged,
172173
onMouseDown,
173174
}),
174-
keybindingsCompartment.of(createKeybindingExtensions({ openTokenPicker })),
175+
keybindingsCompartment.of(createKeybindingExtensions({ openTokenPicker, indentWithTab })),
175176
EditorView.theme({
176177
'&': {
177178
fontSize: `${fontSize}px`,
@@ -275,10 +276,10 @@ export const CodeMirrorEditor = forwardRef<CodeMirrorEditorRef, CodeMirrorEditor
275276
useEffect(() => {
276277
if (viewRef.current) {
277278
viewRef.current.dispatch({
278-
effects: keybindingsCompartment.reconfigure(createKeybindingExtensions({ openTokenPicker })),
279+
effects: keybindingsCompartment.reconfigure(createKeybindingExtensions({ openTokenPicker, indentWithTab })),
279280
});
280281
}
281-
}, [openTokenPicker]);
282+
}, [openTokenPicker, indentWithTab]);
282283

283284
// Update value when controlled value changes
284285
useEffect(() => {

libs/designer-ui/src/lib/editor/codemirror/extensions/__tests__/keybindings.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,20 @@ describe('createKeybindingExtensions', () => {
1818
// Base keybindings (default + history) are always included
1919
expect(extensions.length).toBeGreaterThan(0);
2020
});
21+
22+
it('should include indent with tab keybinding when indentWithTab is true', () => {
23+
const extensions = createKeybindingExtensions({ indentWithTab: true });
24+
// Should contain base keybindings (2) + tabSize (1) + keymap (1)
25+
expect(extensions.length).toBe(4);
26+
// This is a bit of a hack, but there's no easy way to inspect the keymap
27+
const keymapExtension = extensions[3] as any;
28+
expect(keymapExtension.value.length).toBe(2);
29+
expect(keymapExtension.value[0].key).toBe('Tab');
30+
expect(keymapExtension.value[1].key).toBe('Shift-Tab');
31+
});
32+
33+
it('should not include indent with tab keybinding when indentWithTab is false', () => {
34+
const extensions = createKeybindingExtensions({ indentWithTab: false });
35+
expect(extensions.length).toBe(2);
36+
});
2137
});

libs/designer-ui/src/lib/editor/codemirror/extensions/keybindings.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
1-
import type { Extension } from '@codemirror/state';
1+
import { EditorState, type Extension } from '@codemirror/state';
22
import { keymap, EditorView } from '@codemirror/view';
3-
import { defaultKeymap, historyKeymap } from '@codemirror/commands';
3+
import { defaultKeymap, historyKeymap, indentLess, insertTab } from '@codemirror/commands';
44

55
export interface KeybindingExtensionOptions {
66
openTokenPicker?(): void;
7+
indentWithTab?: boolean;
78
}
89

910
export const createKeybindingExtensions = (options: KeybindingExtensionOptions): Extension[] => {
1011
const extensions: Extension[] = [keymap.of(defaultKeymap), keymap.of(historyKeymap)];
1112

13+
// Optionally add indent with tab keybinding
14+
if (options.indentWithTab) {
15+
extensions.push(
16+
EditorState.tabSize.of(2),
17+
keymap.of([
18+
{
19+
key: 'Tab',
20+
preventDefault: true,
21+
run: insertTab,
22+
},
23+
{
24+
key: 'Shift-Tab',
25+
preventDefault: true,
26+
run: indentLess,
27+
},
28+
])
29+
);
30+
}
31+
1232
// Alt+/ to open token picker (matching Monaco behavior)
1333
// On macOS, Option+/ produces ÷ character, so we need to handle the keydown event directly
1434
if (options.openTokenPicker) {

libs/designer-ui/src/lib/editor/codemirror/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface CodeMirrorEditorProps {
3232
vertical?: 'auto' | 'hidden' | 'visible';
3333
};
3434
monacoContainerStyle?: React.CSSProperties;
35+
indentWithTab?: boolean;
3536

3637
// Event callbacks
3738
onBlur?(): void;

libs/designer-ui/src/lib/editor/monaco/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
// Re-export the editor component with Monaco name
77
export { CodeMirrorEditor as MonacoEditor } from '../codemirror';
8+
export { CodeMirrorEditor } from '../codemirror';
89

910
// Re-export types with Monaco-compatible names
1011
export type {

0 commit comments

Comments
 (0)