Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional higlighting modes to CodeMirror component #125

Merged
merged 10 commits into from
Oct 5, 2023
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

### Added

- `<PropertyName />`
- provide `labelProps` to configure the automatically injected `Label` element when `PropertyName` is only a string
- `<CodeEditor />`
- support for additional modes: jinja2, yaml and json
- add read-only mode
- add `height` parameter to set a fixed height of the editor
- add `wrapLines` option to control auto-wrapping long lines (the default for wrap long lines is set to false now)
- `<TextField />`:
- Parameter `escapeToBlur`: If set to true the input field blurs/de-focuces when the `Escape` key is pressed.
- `<Modal />`:
Expand Down
68 changes: 61 additions & 7 deletions src/extensions/codemirror/CodeMirror.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
import React, { useEffect, useRef } from "react";
import React, { TextareaHTMLAttributes, useEffect, useRef } from "react";
import CodeMirror from "codemirror";
import { CLASSPREFIX as eccgui } from "../../configuration/constants";

import "codemirror/mode/markdown/markdown.js";
import "codemirror/mode/python/python.js";
import "codemirror/mode/sparql/sparql.js";
import "codemirror/mode/sql/sql.js";
import "codemirror/mode/turtle/turtle.js";
import "codemirror/mode/xml/xml.js";
import "codemirror/mode/jinja2/jinja2.js";
import "codemirror/mode/yaml/yaml.js";
import "codemirror/mode/javascript/javascript.js";

import { CLASSPREFIX as eccgui } from "../../configuration/constants";

export const supportedCodeEditorModes = [
"markdown",
"python",
"sparql",
"sql",
"turtle",
"xml",
"jinja2",
"yaml",
"json",
"undefined",
] as const;
type SupportedModesTuple = typeof supportedCodeEditorModes;
export type SupportedCodeEditorModes = SupportedModesTuple[number];

export interface CodeEditorProps {
/**
Expand All @@ -26,7 +46,7 @@
/**
* Syntax mode of the code editor.
*/
mode?: "markdown" | "python" | "sparql" | "sql" | "turtle" | "xml" | "undefined";
mode?: SupportedCodeEditorModes;
/**
* Default value used first when the editor is instanciated.
*/
Expand All @@ -35,6 +55,17 @@
* If enabled the code editor won't show numbers before each line.
*/
preventLineNumbers?: boolean;

/** Set read-only mode. Default: false */
readOnly?: boolean;

/** Optional height of the component */
height?: number | string;

/** Long lines are wrapped and displayed on multiple lines */
wrapLines?: boolean;

outerDivAttributes?: Partial<TextareaHTMLAttributes<HTMLDivElement>>;
}

/**
Expand All @@ -47,29 +78,38 @@
mode = "undefined",
preventLineNumbers = false,
defaultValue,
readOnly = false,
height,
wrapLines = false,
outerDivAttributes,
}: CodeEditorProps) => {
const domRef = useRef<HTMLTextAreaElement>(null);

useEffect(() => {
const editorInstance = CodeMirror.fromTextArea(domRef.current!, {
mode: mode === "undefined" ? undefined : mode,
lineWrapping: true,
mode: convertMode(mode),

Check failure on line 90 in src/extensions/codemirror/CodeMirror.tsx

View workflow job for this annotation

GitHub Actions / test-code

Type 'string | object | undefined' is not assignable to type 'string | ModeSpec<ModeSpecOptions> | undefined'.
lineWrapping: wrapLines,
lineNumbers: !preventLineNumbers,
tabSize: 2,
theme: "xq-light",
readOnly: readOnly,
});

editorInstance.on("change", (api) => {
onChange(api.getValue());
});

if (height) {
editorInstance.setSize(null, height);
}

return function cleanup() {
editorInstance.toTextArea();
};
}, [onChange, mode, preventLineNumbers]);

return (
<div className={`${eccgui}-codeeditor`}>
<div {...outerDivAttributes} className={`${eccgui}-codeeditor`}>
<textarea
ref={domRef}
/**
Expand All @@ -78,10 +118,24 @@
* unchanged from the code what was took over here.
*/
data-test-id="codemirror-wrapper"
id={!!id ? id : `codemirror-${name}`}
id={id ? id : `codemirror-${name}`}
name={name}
defaultValue={defaultValue}
/>
</div>
);
};

const convertMode = (mode: SupportedCodeEditorModes | undefined): string | object | undefined => {
switch (mode) {
case "undefined":
return undefined;
case "json":
return {
name: "javascript",
json: true,
};
default:
return mode;
}
};
61 changes: 53 additions & 8 deletions src/extensions/codemirror/_codemirror.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,76 @@
@import "~codemirror/theme/xq-light";

// adjustments

// stylelint-disable selector-class-pattern
.#{$eccgui}-codeeditor {
max-width: 100%;

.CodeMirror {
border-radius: $pt-border-radius;
clip-path: unset !important; // we may check later why they set inset(0) now
border-radius: $pt-border-radius;

// get them a "border" like input boxes from blueprintjs
box-shadow: input-transition-shadow($input-shadow-color-focus), $pt-input-box-shadow;

&.CodeMirror-focused {
box-shadow: input-transition-shadow($input-shadow-color-focus, true), $input-box-shadow-focus;
}

.CodeMirror-gutters {
// allow "borders" to shine through
background-color: rgba(0,0,0,0.05);
}

.CodeMirror-scroll {
width: calc(100% - 2px);
height: calc(100% - 2px);

// fix size to prevent wrong calculation of other elements
padding: 0;
margin: 1px;
cursor: text;

// remove scrollbars, codemirrow has own elements to fake them
scrollbar-width: none; // Firefox
-ms-overflow-style: none; // IE, Edge
&::-webkit-scrollbar {
display: none; // Chrome, Safari and Opera
}
}

.CodeMirror-hscrollbar {
bottom: 1px;
height: $eccgui-size-inline-whitespace !important;
}

.CodeMirror-vscrollbar {
top: 1px;
right: 1px;
width: $eccgui-size-inline-whitespace !important;
}

.CodeMirror-scrollbar-filler {
right: 1px;
bottom: 1px;
}

.CodeMirror-sizer {
border-right-width: $eccgui-size-inline-whitespace !important;
}
}
}

.#{$prefix}--accordion__content {
.CodeMirror-scroll, .CodeMirror-sizer, .CodeMirror-gutter, .CodeMirror-gutters, .CodeMirror-linenumber {
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
box-sizing: content-box;
}
}

// fix a few xq-light colors regarding bad contrasts

.cm-s-xq-light {
// add other classes if necessary
.cm-meta {
filter: invert(1);
}
}
// stylelint-enable selector-class-pattern
Loading