@@ -6,6 +6,7 @@ import { DOMEventHandlers, EditorView, KeyBinding, keymap, Rect, ViewUpdate } fr
66import { minimalSetup } from "codemirror" ;
77
88import { Markdown } from "../../cmem/markdown/Markdown" ;
9+ import { EditorAppearanceConfigMenu } from "./toolbars/EditorAppearanceConfigMenu" ;
910import { IntentTypes } from "../../common/Intent" ;
1011import { markField } from "../../components/AutoSuggestion/extensions/markText" ;
1112import { TestableComponent } from "../../components/interfaces" ;
@@ -36,7 +37,17 @@ import {
3637import { MarkdownToolbar } from "./toolbars/markdown.toolbar" ;
3738import { ExtensionCreator } from "./types" ;
3839
39- export interface CodeEditorProps extends Omit < React . HTMLAttributes < HTMLDivElement > , "translate" | "onChange" | "onKeyDown" | "onMouseDown" | "onScroll" > , TestableComponent {
40+ interface EditorAppearance {
41+ /**
42+ * If enabled the code editor won't show numbers before each line.
43+ */
44+ preventLineNumbers ?: boolean ;
45+
46+ /** Long lines are wrapped and displayed on multiple lines */
47+ wrapLines ?: boolean ;
48+ }
49+
50+ export interface CodeEditorProps extends EditorAppearance , Omit < React . HTMLAttributes < HTMLDivElement > , "translate" | "onChange" | "onKeyDown" | "onMouseDown" | "onScroll" > , TestableComponent {
4051 // Is called with the editor instance that allows access via the CodeMirror API
4152 setEditorView ?: ( editor : EditorView | undefined ) => void ;
4253 /**
@@ -86,22 +97,15 @@ export interface CodeEditorProps extends Omit<React.HTMLAttributes<HTMLDivElemen
8697 * Default value used first when the editor is instanciated.
8798 */
8899 defaultValue ?: string ;
89- /**
90- * If enabled the code editor won't show numbers before each line.
91- */
92- preventLineNumbers ?: boolean ;
93100
94101 /** Set read-only mode. Default: false */
95102 readOnly ?: boolean ;
96103
97104 /** Optional height of the component */
98105 height ?: number | string ;
99106
100- /** Long lines are wrapped and displayed on multiple lines */
101- wrapLines ?: boolean ;
102-
103107 /**
104- * Add properties to the `div` used as warpper element.
108+ * Add properties to the `div` used as wrapper element.
105109 * @deprecated (v26) You can now use all properties directly on `CodeEditor`.
106110 */
107111 outerDivAttributes ?: Omit < React . HTMLAttributes < HTMLDivElement > , "id" | "data-test-id" | "data-testid" | "translate" | "onChange" | "onKeyDown" | "onMouseDown" | "onScroll" > ;
@@ -186,6 +190,18 @@ const ModeLinterMap: ReadonlyMap<SupportedCodeEditorModes, ReadonlyArray<Extensi
186190
187191const ModeToolbarSupport : ReadonlyArray < SupportedCodeEditorModes > = [ "markdown" ] ;
188192
193+ const defaultAppearanceForModeWithToolbar : ReadonlyMap < SupportedCodeEditorModes , EditorAppearance > = new Map ( [
194+ [ "markdown" , { wrapLines : true , preventLineNumbers : true } ]
195+ ] ) ;
196+
197+ const getDefaultAppearanceForModeWithToolbar = ( hasToolbar : boolean , mode ?: SupportedCodeEditorModes ) : EditorAppearance | undefined => {
198+ if ( hasToolbar && mode ) {
199+ return defaultAppearanceForModeWithToolbar . get ( mode ) ;
200+ }
201+
202+ return undefined ;
203+ }
204+
189205/**
190206 * Includes a code editor, currently we use CodeMirror library as base.
191207 */
@@ -200,11 +216,11 @@ export const CodeEditor = ({
200216 name,
201217 id,
202218 mode,
203- preventLineNumbers = false ,
219+ preventLineNumbers,
220+ wrapLines,
204221 defaultValue = "" ,
205222 readOnly = false ,
206223 shouldHaveMinimalSetup = true ,
207- wrapLines = false ,
208224 onScroll,
209225 setEditorView,
210226 supportCodeFolding = false ,
@@ -221,12 +237,20 @@ export const CodeEditor = ({
221237 autoFocus = false ,
222238 disabled = false ,
223239 intent,
224- useToolbar,
240+ useToolbar = false ,
225241 translate,
226242 ...otherCodeEditorProps
227243} : CodeEditorProps ) => {
228244 const parent = useRef < any > ( undefined ) ;
229245 const [ view , setView ] = React . useState < EditorView | undefined > ( ) ;
246+ const defaultAppearanceForModeWithToolbar = getDefaultAppearanceForModeWithToolbar ( useToolbar , mode ) ;
247+ const [ editorAppearance , setEditorAppearance ] = React . useState < { [ s : string ] : boolean ; } > (
248+ {
249+ // we also set the fallback default here
250+ wrapLines : wrapLines ?? defaultAppearanceForModeWithToolbar ?. wrapLines ?? false ,
251+ preventLineNumbers : preventLineNumbers ?? defaultAppearanceForModeWithToolbar ?. preventLineNumbers ?? false ,
252+ }
253+ )
230254 const currentView = React . useRef < EditorView > ( )
231255 currentView . current = view
232256 const currentReadOnly = React . useRef ( readOnly )
@@ -235,6 +259,8 @@ export const CodeEditor = ({
235259 currentOnChange . current = onChange
236260 const currentDisabled = React . useRef ( disabled )
237261 currentDisabled . current = disabled
262+ const currentIntent = React . useRef ( intent )
263+ currentIntent . current = intent
238264 const [ showPreview , setShowPreview ] = React . useState < boolean > ( false ) ;
239265 // CodeMirror Compartments in order to allow for re-configuration after initialization
240266 const readOnlyCompartment = React . useRef < Compartment > ( compartment ( ) )
@@ -333,8 +359,8 @@ export const CodeEditor = ({
333359 if ( onSelection )
334360 onSelection ( v . state . selection . ranges . filter ( ( r ) => ! r . empty ) . map ( ( { from, to } ) => ( { from, to } ) ) ) ;
335361
336- if ( onFocusChange && intent && ! v . view . dom . classList ?. contains ( `${ eccgui } -intent--${ intent } ` ) ) {
337- v . view . dom . classList . add ( `${ eccgui } -intent--${ intent } ` ) ;
362+ if ( onFocusChange && currentIntent . current && ! v . view . dom . classList ?. contains ( `${ eccgui } -intent--${ currentIntent . current } ` ) ) {
363+ v . view . dom . classList . add ( `${ eccgui } -intent--${ currentIntent . current } ` ) ;
338364 }
339365
340366 if ( onCursorChange ) {
@@ -357,9 +383,9 @@ export const CodeEditor = ({
357383 }
358384 } ) ,
359385 shouldHaveMinimalSetupCompartment . current . of ( addExtensionsFor ( shouldHaveMinimalSetup , minimalSetup ) ) ,
360- preventLineNumbersCompartment . current . of ( addExtensionsFor ( ! preventLineNumbers , adaptedLineNumbers ( ) ) ) ,
386+ preventLineNumbersCompartment . current . of ( addExtensionsFor ( ! editorAppearance . preventLineNumbers , adaptedLineNumbers ( ) ) ) ,
361387 shouldHighlightActiveLineCompartment . current . of ( addExtensionsFor ( shouldHighlightActiveLine , adaptedHighlightActiveLine ( ) ) ) ,
362- wrapLinesCompartment . current . of ( addExtensionsFor ( wrapLines , EditorView ?. lineWrapping ) ) ,
388+ wrapLinesCompartment . current . of ( addExtensionsFor ( ( editorAppearance . wrapLines ! ) , EditorView ?. lineWrapping ) ) ,
363389 supportCodeFoldingCompartment . current . of ( addExtensionsFor ( supportCodeFolding , adaptedFoldGutter ( ) , adaptedCodeFolding ( ) ) ) ,
364390 useLintingCompartment . current . of ( addExtensionsFor ( useLinting , ...linters ) ) ,
365391 adaptedSyntaxHighlighting ( defaultHighlightStyle ) ,
@@ -384,8 +410,8 @@ export const CodeEditor = ({
384410 view . dom . classList . add ( `${ eccgui } -disabled` ) ;
385411 }
386412
387- if ( intent ) {
388- view . dom . className += ` ${ eccgui } -intent--${ intent } ` ;
413+ if ( currentIntent . current ) {
414+ view . dom . className += ` ${ eccgui } -intent--${ currentIntent . current } ` ;
389415 }
390416
391417 if ( autoFocus ) {
@@ -447,20 +473,28 @@ export const CodeEditor = ({
447473 } , [ disabled ] )
448474
449475 React . useEffect ( ( ) => {
450- updateExtension ( addExtensionsFor ( shouldHaveMinimalSetup ?? true , minimalSetup ) , shouldHaveMinimalSetupCompartment . current )
451- } , [ shouldHaveMinimalSetup ] )
476+ setEditorAppearance ( {
477+ ...editorAppearance ,
478+ preventLineNumbers : preventLineNumbers ?? editorAppearance ?. preventLineNumbers ?? false ,
479+ } ) ;
480+ updateExtension ( addExtensionsFor ( ! editorAppearance . preventLineNumbers , adaptedLineNumbers ( ) ) , preventLineNumbersCompartment . current )
481+ } , [ preventLineNumbers , editorAppearance . preventLineNumbers ] )
452482
453483 React . useEffect ( ( ) => {
454- updateExtension ( addExtensionsFor ( ! preventLineNumbers , adaptedLineNumbers ( ) ) , preventLineNumbersCompartment . current )
455- } , [ preventLineNumbers ] )
484+ setEditorAppearance ( {
485+ ...editorAppearance ,
486+ wrapLines : wrapLines ?? editorAppearance ?. wrapLines ?? false ,
487+ } ) ;
488+ updateExtension ( addExtensionsFor ( editorAppearance . wrapLines ! , EditorView ?. lineWrapping ) , wrapLinesCompartment . current )
489+ } , [ wrapLines , editorAppearance . wrapLines ] )
456490
457491 React . useEffect ( ( ) => {
458- updateExtension ( addExtensionsFor ( shouldHighlightActiveLine ?? false , adaptedHighlightActiveLine ( ) ) , shouldHighlightActiveLineCompartment . current )
459- } , [ shouldHighlightActiveLine ] )
492+ updateExtension ( addExtensionsFor ( shouldHaveMinimalSetup ?? true , minimalSetup ) , shouldHaveMinimalSetupCompartment . current )
493+ } , [ shouldHaveMinimalSetup ] )
460494
461495 React . useEffect ( ( ) => {
462- updateExtension ( addExtensionsFor ( wrapLines ?? false , EditorView ?. lineWrapping ) , wrapLinesCompartment . current )
463- } , [ wrapLines ] )
496+ updateExtension ( addExtensionsFor ( shouldHighlightActiveLine ?? false , adaptedHighlightActiveLine ( ) ) , shouldHighlightActiveLineCompartment . current )
497+ } , [ shouldHighlightActiveLine ] )
464498
465499 React . useEffect ( ( ) => {
466500 updateExtension ( addExtensionsFor ( supportCodeFolding ?? false , adaptedFoldGutter ( ) , adaptedCodeFolding ( ) ) , supportCodeFoldingCompartment . current )
@@ -485,6 +519,17 @@ export const CodeEditor = ({
485519 translate = { getTranslation }
486520 disabled = { disabled }
487521 readonly = { readOnly }
522+ configMenu = { (
523+ < EditorAppearanceConfigMenu
524+ config = { { ...editorAppearance } }
525+ configLocked = { {
526+ wrapLines,
527+ preventLineNumbers,
528+ } }
529+ setConfig = { setEditorAppearance }
530+ configPropertyTranslate = { getTranslation }
531+ />
532+ ) }
488533 />
489534 </ div >
490535 { showPreview && (
0 commit comments