@eccenca/gui-elements 24.0.1 → 24.1.0-featureimprovepublishingprocesscmem6356.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +82 -0
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +3 -3
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +13 -3
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js +3 -3
- package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +4 -2
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/cjs/components/Card/CardActions.js +2 -1
- package/dist/cjs/components/Card/CardActions.js.map +1 -1
- package/dist/cjs/components/Card/CardContent.js +4 -6
- package/dist/cjs/components/Card/CardContent.js.map +1 -1
- package/dist/cjs/components/ContentGroup/ContentGroup.js +95 -0
- package/dist/cjs/components/ContentGroup/ContentGroup.js.map +1 -0
- package/dist/cjs/components/Dialog/SimpleDialog.js +3 -3
- package/dist/cjs/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js +12 -0
- package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/cjs/components/Label/Label.js +8 -3
- package/dist/cjs/components/Label/Label.js.map +1 -1
- package/dist/cjs/components/Menu/MenuItem.js +3 -2
- package/dist/cjs/components/Menu/MenuItem.js.map +1 -1
- package/dist/cjs/components/OverviewItem/OverviewItem.js +5 -2
- package/dist/cjs/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/cjs/components/OverviewItem/OverviewItemList.js +2 -2
- package/dist/cjs/components/OverviewItem/OverviewItemList.js.map +1 -1
- package/dist/cjs/components/Switch/Switch.js +6 -4
- package/dist/cjs/components/Switch/Switch.js.map +1 -1
- package/dist/cjs/components/Tag/TagList.js +1 -1
- package/dist/cjs/components/Tag/TagList.js.map +1 -1
- package/dist/cjs/components/TextField/SearchField.js +19 -2
- package/dist/cjs/components/TextField/SearchField.js.map +1 -1
- package/dist/cjs/components/Typography/OverflowText.js +1 -1
- package/dist/cjs/components/Typography/OverflowText.js.map +1 -1
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/extensions/codemirror/CodeMirror.js +93 -11
- package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/cjs/extensions/codemirror/debouncedLinter.js +18 -0
- package/dist/cjs/extensions/codemirror/debouncedLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js +1 -1
- package/dist/cjs/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js.map +1 -1
- package/dist/cjs/extensions/codemirror/linters/jsLinter.js +36 -0
- package/dist/cjs/extensions/codemirror/linters/jsLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/linters/turtleLinter.js +81 -0
- package/dist/cjs/extensions/codemirror/linters/turtleLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/tests/codemirrorTestHelper.js +4 -1
- package/dist/cjs/extensions/codemirror/tests/codemirrorTestHelper.js.map +1 -1
- package/dist/cjs/extensions/codemirror/toolbars/commands/markdown.command.js +278 -0
- package/dist/cjs/extensions/codemirror/toolbars/commands/markdown.command.js.map +1 -0
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js +47 -0
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -0
- package/dist/cjs/extensions/codemirror/types.js +3 -0
- package/dist/cjs/extensions/codemirror/types.js.map +1 -0
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +140 -41
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/cjs/extensions/react-flow/nodes/nodeUtils.js +5 -6
- package/dist/cjs/extensions/react-flow/nodes/nodeUtils.js.map +1 -1
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +4 -4
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +13 -3
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js +14 -3
- package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js +4 -3
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/esm/components/Card/CardActions.js +2 -1
- package/dist/esm/components/Card/CardActions.js.map +1 -1
- package/dist/esm/components/Card/CardContent.js +4 -5
- package/dist/esm/components/Card/CardContent.js.map +1 -1
- package/dist/esm/components/ContentGroup/ContentGroup.js +100 -0
- package/dist/esm/components/ContentGroup/ContentGroup.js.map +1 -0
- package/dist/esm/components/Dialog/SimpleDialog.js +4 -4
- package/dist/esm/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/esm/components/Icon/canonicalIconNames.js +12 -0
- package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/esm/components/Label/Label.js +8 -3
- package/dist/esm/components/Label/Label.js.map +1 -1
- package/dist/esm/components/Menu/MenuItem.js +3 -2
- package/dist/esm/components/Menu/MenuItem.js.map +1 -1
- package/dist/esm/components/OverviewItem/OverviewItem.js +5 -2
- package/dist/esm/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/esm/components/OverviewItem/OverviewItemList.js +2 -2
- package/dist/esm/components/OverviewItem/OverviewItemList.js.map +1 -1
- package/dist/esm/components/Switch/Switch.js +7 -5
- package/dist/esm/components/Switch/Switch.js.map +1 -1
- package/dist/esm/components/Tag/TagList.js +1 -1
- package/dist/esm/components/Tag/TagList.js.map +1 -1
- package/dist/esm/components/TextField/SearchField.js +35 -2
- package/dist/esm/components/TextField/SearchField.js.map +1 -1
- package/dist/esm/components/Typography/OverflowText.js +1 -1
- package/dist/esm/components/Typography/OverflowText.js.map +1 -1
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/extensions/codemirror/CodeMirror.js +94 -13
- package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/esm/extensions/codemirror/debouncedLinter.js +15 -0
- package/dist/esm/extensions/codemirror/debouncedLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js +1 -1
- package/dist/esm/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js.map +1 -1
- package/dist/esm/extensions/codemirror/linters/jsLinter.js +32 -0
- package/dist/esm/extensions/codemirror/linters/jsLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/linters/turtleLinter.js +77 -0
- package/dist/esm/extensions/codemirror/linters/turtleLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/tests/codemirrorTestHelper.js +4 -0
- package/dist/esm/extensions/codemirror/tests/codemirrorTestHelper.js.map +1 -1
- package/dist/esm/extensions/codemirror/toolbars/commands/markdown.command.js +283 -0
- package/dist/esm/extensions/codemirror/toolbars/commands/markdown.command.js.map +1 -0
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js +41 -0
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -0
- package/dist/esm/extensions/codemirror/types.js +2 -0
- package/dist/esm/extensions/codemirror/types.js.map +1 -0
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js +149 -48
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/esm/extensions/react-flow/nodes/nodeUtils.js +5 -6
- package/dist/esm/extensions/react-flow/nodes/nodeUtils.js.map +1 -1
- package/dist/types/cmem/ActivityControl/ActivityControlWidget.d.ts +1 -1
- package/dist/types/cmem/react-flow/StickyNoteModal/StickyNoteModal.d.ts +5 -1
- package/dist/types/components/AutoSuggestion/ExtendedCodeEditor.d.ts +11 -6
- package/dist/types/components/Card/CardActions.d.ts +5 -1
- package/dist/types/components/Card/CardContent.d.ts +1 -2
- package/dist/types/components/ContentGroup/ContentGroup.d.ts +78 -0
- package/dist/types/components/Dialog/SimpleDialog.d.ts +4 -1
- package/dist/types/components/Icon/canonicalIconNames.d.ts +12 -0
- package/dist/types/components/Label/Label.d.ts +7 -1
- package/dist/types/components/Menu/MenuItem.d.ts +8 -1
- package/dist/types/components/OverviewItem/OverviewItem.d.ts +13 -1
- package/dist/types/components/OverviewItem/OverviewItemList.d.ts +3 -2
- package/dist/types/components/ProgressBar/ProgressBar.d.ts +2 -2
- package/dist/types/components/Structure/TitleSubsection.d.ts +7 -0
- package/dist/types/components/Switch/Switch.d.ts +3 -3
- package/dist/types/components/Tabs/Tab.d.ts +14 -0
- package/dist/types/components/TextField/SearchField.d.ts +1 -1
- package/dist/types/components/Typography/OverflowText.d.ts +23 -2
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/extensions/codemirror/CodeMirror.d.ts +32 -5
- package/dist/types/extensions/codemirror/debouncedLinter.d.ts +4 -0
- package/dist/types/extensions/codemirror/linters/jsLinter.d.ts +5 -0
- package/dist/types/extensions/codemirror/linters/turtleLinter.d.ts +5 -0
- package/dist/types/extensions/codemirror/tests/codemirrorTestHelper.d.ts +1 -0
- package/dist/types/extensions/codemirror/toolbars/commands/markdown.command.d.ts +55 -0
- package/dist/types/extensions/codemirror/toolbars/markdown.toolbar.d.ts +12 -0
- package/dist/types/extensions/codemirror/types.d.ts +5 -0
- package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +18 -4
- package/dist/types/extensions/react-flow/nodes/nodeUtils.d.ts +7 -6
- package/package.json +50 -47
- package/src/cmem/ActivityControl/ActivityControlWidget.tsx +5 -2
- package/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx +16 -2
- package/src/cmem/react-flow/configuration/_colors-graph.scss +4 -1
- package/src/cmem/react-flow/configuration/_colors-workflow.scss +3 -0
- package/src/components/AutoSuggestion/AutoSuggestion.tsx +14 -3
- package/src/components/AutoSuggestion/ExtendedCodeEditor.tsx +29 -6
- package/src/components/AutocompleteField/AutoCompleteField.tsx +5 -3
- package/src/components/Card/CardActions.tsx +6 -0
- package/src/components/Card/CardContent.tsx +8 -4
- package/src/components/Card/card.scss +15 -0
- package/src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx +3 -2
- package/src/components/ContentGroup/ContentGroup.stories.tsx +47 -0
- package/src/components/ContentGroup/ContentGroup.tsx +256 -0
- package/src/components/ContentGroup/_contentgroup.scss +56 -0
- package/src/components/ContextOverlay/ContextOverlay.stories.tsx +15 -4
- package/src/components/Depiction/depiction.scss +7 -0
- package/src/components/Dialog/SimpleDialog.tsx +9 -2
- package/src/components/Dialog/stories/AlertDialog.stories.tsx +5 -1
- package/src/components/Dialog/stories/Modal.stories.tsx +4 -2
- package/src/components/Dialog/stories/SimpleDialog.stories.tsx +5 -2
- package/src/components/Icon/canonicalIconNames.tsx +12 -0
- package/src/components/Label/Label.stories.tsx +2 -1
- package/src/components/Label/Label.tsx +17 -1
- package/src/components/Label/label.scss +5 -1
- package/src/components/Menu/MenuItem.tsx +27 -1
- package/src/components/Menu/menu.scss +1 -0
- package/src/components/OverviewItem/OverviewItem.tsx +24 -1
- package/src/components/OverviewItem/OverviewItemList.tsx +3 -2
- package/src/components/OverviewItem/overviewitem.scss +4 -1
- package/src/components/OverviewItem/stories/OverviewItem.stories.tsx +6 -12
- package/src/components/Select/Select.stories.tsx +4 -1
- package/src/components/Switch/Switch.tsx +27 -8
- package/src/components/Tag/TagList.tsx +2 -2
- package/src/components/TextField/SearchField.tsx +37 -9
- package/src/components/TextField/stories/SearchField.stories.tsx +15 -1
- package/src/components/TextField/stories/TextField.stories.tsx +2 -1
- package/src/components/TextField/textfield.scss +17 -3
- package/src/components/Typography/OverflowText.tsx +24 -3
- package/src/components/Typography/stories/OverflowText.stories.tsx +33 -0
- package/src/components/index.scss +1 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/codemirror/CodeMirror.stories.tsx +19 -1
- package/src/extensions/codemirror/CodeMirror.tsx +154 -16
- package/src/extensions/codemirror/_codemirror.scss +130 -1
- package/src/extensions/codemirror/debouncedLinter.ts +26 -0
- package/src/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.ts +1 -1
- package/src/extensions/codemirror/linters/jsLinter.ts +38 -0
- package/src/extensions/codemirror/linters/turtleLinter.ts +102 -0
- package/src/extensions/codemirror/tests/codemirrorTestHelper.ts +4 -0
- package/src/extensions/codemirror/toolbars/commands/markdown.command.ts +340 -0
- package/src/extensions/codemirror/toolbars/markdown.toolbar.tsx +117 -0
- package/src/extensions/codemirror/types.ts +7 -0
- package/src/extensions/react-flow/_config.scss +1 -0
- package/src/extensions/react-flow/nodes/NodeContent.tsx +170 -52
- package/src/extensions/react-flow/nodes/_nodes.scss +71 -35
- package/src/extensions/react-flow/nodes/nodeUtils.tsx +16 -14
- package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +51 -12
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Meta, StoryFn } from "@storybook/react";
|
|
3
3
|
|
|
4
|
+
import { helpersArgTypes } from "../../../.storybook/helpers";
|
|
5
|
+
|
|
4
6
|
import { CodeEditor } from "./CodeMirror";
|
|
5
7
|
|
|
6
8
|
export default {
|
|
@@ -11,14 +13,30 @@ export default {
|
|
|
11
13
|
onChange: {
|
|
12
14
|
action: "value changed",
|
|
13
15
|
},
|
|
16
|
+
intent: {
|
|
17
|
+
...helpersArgTypes.exampleIntent,
|
|
18
|
+
},
|
|
14
19
|
},
|
|
15
20
|
} as Meta<typeof CodeEditor>;
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
let forcedUpdateKey = 0; // @see https://github.com/storybookjs/storybook/issues/13375#issuecomment-1291011856
|
|
23
|
+
const TemplateFull: StoryFn<typeof CodeEditor> = (args) => <CodeEditor {...args} key={++forcedUpdateKey} />;
|
|
18
24
|
|
|
19
25
|
export const BasicExample = TemplateFull.bind({});
|
|
20
26
|
BasicExample.args = {
|
|
21
27
|
name: "codeinput",
|
|
22
28
|
mode: "markdown",
|
|
23
29
|
defaultValue: "**test me**",
|
|
30
|
+
useToolbar: true,
|
|
31
|
+
disabled: false,
|
|
32
|
+
readOnly: true,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const LinterExample = TemplateFull.bind({});
|
|
36
|
+
LinterExample.args = {
|
|
37
|
+
name: "codeinput",
|
|
38
|
+
defaultValue: "**test me**",
|
|
39
|
+
mode: "javascript",
|
|
40
|
+
useLinting: true,
|
|
41
|
+
autoFocus: true,
|
|
24
42
|
};
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import React, { useRef } from "react";
|
|
1
|
+
import React, { useMemo, useRef } from "react";
|
|
2
2
|
import { defaultKeymap, indentWithTab } from "@codemirror/commands";
|
|
3
3
|
import { foldKeymap } from "@codemirror/language";
|
|
4
4
|
import { EditorState, Extension } from "@codemirror/state";
|
|
5
5
|
import { DOMEventHandlers, EditorView, KeyBinding, keymap, Rect, ViewUpdate } from "@codemirror/view";
|
|
6
6
|
import { minimalSetup } from "codemirror";
|
|
7
7
|
|
|
8
|
+
import { IntentTypes } from "../../common/Intent";
|
|
8
9
|
import { markField } from "../../components/AutoSuggestion/extensions/markText";
|
|
10
|
+
import { TestableComponent } from "../../components/interfaces";
|
|
11
|
+
import { MarkdownToolbar } from "./toolbars/markdown.toolbar";
|
|
12
|
+
import { Markdown } from "../../cmem/markdown/Markdown";
|
|
9
13
|
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
|
|
10
14
|
|
|
11
15
|
//hooks
|
|
@@ -14,6 +18,8 @@ import {
|
|
|
14
18
|
supportedCodeEditorModes,
|
|
15
19
|
useCodeMirrorModeExtension,
|
|
16
20
|
} from "./hooks/useCodemirrorModeExtension.hooks";
|
|
21
|
+
import { jsLinter } from "./linters/jsLinter";
|
|
22
|
+
import { turtleLinter } from "./linters/turtleLinter";
|
|
17
23
|
//adaptations
|
|
18
24
|
import {
|
|
19
25
|
adaptedCodeFolding,
|
|
@@ -23,12 +29,14 @@ import {
|
|
|
23
29
|
adaptedHighlightActiveLine,
|
|
24
30
|
adaptedHighlightSpecialChars,
|
|
25
31
|
adaptedLineNumbers,
|
|
32
|
+
adaptedLintGutter,
|
|
26
33
|
adaptedPlaceholder,
|
|
27
34
|
} from "./tests/codemirrorTestHelper";
|
|
35
|
+
import { ExtensionCreator } from "./types";
|
|
28
36
|
|
|
29
|
-
export interface CodeEditorProps {
|
|
37
|
+
export interface CodeEditorProps extends TestableComponent {
|
|
30
38
|
// Is called with the editor instance that allows access via the CodeMirror API
|
|
31
|
-
setEditorView?: (editor: EditorView | undefined) =>
|
|
39
|
+
setEditorView?: (editor: EditorView | undefined) => void;
|
|
32
40
|
/**
|
|
33
41
|
* `name` attribute of connected textarea element.
|
|
34
42
|
*/
|
|
@@ -50,7 +58,7 @@ export interface CodeEditorProps {
|
|
|
50
58
|
/**
|
|
51
59
|
* Called when the focus status changes
|
|
52
60
|
*/
|
|
53
|
-
onFocusChange?: (focused: boolean) =>
|
|
61
|
+
onFocusChange?: (focused: boolean) => void;
|
|
54
62
|
/**
|
|
55
63
|
* Called when the user presses a key
|
|
56
64
|
*/
|
|
@@ -62,7 +70,7 @@ export interface CodeEditorProps {
|
|
|
62
70
|
/**
|
|
63
71
|
* Called when the user selects text
|
|
64
72
|
*/
|
|
65
|
-
onSelection?: (ranges: { from: number; to: number }[]) =>
|
|
73
|
+
onSelection?: (ranges: { from: number; to: number }[]) => void;
|
|
66
74
|
/**
|
|
67
75
|
* Called when the cursor position changes
|
|
68
76
|
*/
|
|
@@ -71,7 +79,6 @@ export interface CodeEditorProps {
|
|
|
71
79
|
/**
|
|
72
80
|
* Syntax mode of the code editor.
|
|
73
81
|
*/
|
|
74
|
-
|
|
75
82
|
mode?: SupportedCodeEditorModes;
|
|
76
83
|
/**
|
|
77
84
|
* Default value used first when the editor is instanciated.
|
|
@@ -133,6 +140,32 @@ export interface CodeEditorProps {
|
|
|
133
140
|
* If the <Tab> key is enabled as normal input, i.e. it won't have the behavior of changing to the next input element, expected in a web app.
|
|
134
141
|
*/
|
|
135
142
|
enableTab?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Enables linting feature in the editor ("turtle" and "javascript" modes can use linting currently).
|
|
145
|
+
*/
|
|
146
|
+
useLinting?: boolean;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Autofocus the editor when it is rendered
|
|
150
|
+
*/
|
|
151
|
+
autoFocus?: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Intent state of the code editor.
|
|
154
|
+
*/
|
|
155
|
+
intent?: IntentTypes | "edited" | "removed";
|
|
156
|
+
/**
|
|
157
|
+
* Disables the editor.
|
|
158
|
+
*/
|
|
159
|
+
disabled?: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Add toolbar for mode.
|
|
162
|
+
* Currently only `markdown` is supported.
|
|
163
|
+
*/
|
|
164
|
+
useToolbar?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Get the translation for a specific key
|
|
167
|
+
*/
|
|
168
|
+
translate?: (key: string) => string | false;
|
|
136
169
|
}
|
|
137
170
|
|
|
138
171
|
const addExtensionsFor = (flag: boolean, ...extensions: Extension[]) => (flag ? [...extensions] : []);
|
|
@@ -140,6 +173,13 @@ const addToKeyMapConfigFor = (flag: boolean, ...keys: any) => (flag ? [...keys]
|
|
|
140
173
|
const addHandlersFor = (flag: boolean, handlerName: string, handler: any) =>
|
|
141
174
|
flag ? ({ [handlerName]: handler } as DOMEventHandlers<any>) : {};
|
|
142
175
|
|
|
176
|
+
const ModeLinterMap: ReadonlyMap<SupportedCodeEditorModes, ReadonlyArray<ExtensionCreator>> = new Map([
|
|
177
|
+
["turtle", [turtleLinter]],
|
|
178
|
+
["javascript", [jsLinter]],
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
const ModeToolbarSupport: ReadonlyArray<SupportedCodeEditorModes> = ["markdown"];
|
|
182
|
+
|
|
143
183
|
/**
|
|
144
184
|
* Includes a code editor, currently we use CodeMirror library as base.
|
|
145
185
|
*/
|
|
@@ -170,8 +210,33 @@ export const CodeEditor = ({
|
|
|
170
210
|
tabForceSpaceForModes = ["python", "yaml"],
|
|
171
211
|
enableTab = false,
|
|
172
212
|
height,
|
|
213
|
+
useLinting = false,
|
|
214
|
+
"data-test-id": dataTestId,
|
|
215
|
+
autoFocus = false,
|
|
216
|
+
disabled = false,
|
|
217
|
+
intent,
|
|
218
|
+
useToolbar,
|
|
219
|
+
translate,
|
|
220
|
+
...otherCodeEditorProps
|
|
173
221
|
}: CodeEditorProps) => {
|
|
174
222
|
const parent = useRef<any>(undefined);
|
|
223
|
+
const [view, setView] = React.useState<EditorView | undefined>();
|
|
224
|
+
const [showPreview, setShowPreview] = React.useState<boolean>(false);
|
|
225
|
+
|
|
226
|
+
const linters = useMemo(() => {
|
|
227
|
+
if (!mode) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const values = [adaptedLintGutter()];
|
|
232
|
+
|
|
233
|
+
const linters = ModeLinterMap.get(mode);
|
|
234
|
+
if (linters) {
|
|
235
|
+
values.push(...linters.map((linter) => linter()));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return values;
|
|
239
|
+
}, [mode]);
|
|
175
240
|
|
|
176
241
|
const onKeyDownHandler = (event: KeyboardEvent, view: EditorView) => {
|
|
177
242
|
if (onKeyDown && !onKeyDown(event)) {
|
|
@@ -192,6 +257,14 @@ export const CodeEditor = ({
|
|
|
192
257
|
}
|
|
193
258
|
};
|
|
194
259
|
|
|
260
|
+
const getTranslation = (key: string): string | false => {
|
|
261
|
+
if (translate && typeof translate === "function") {
|
|
262
|
+
return translate(key);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return false;
|
|
266
|
+
};
|
|
267
|
+
|
|
195
268
|
React.useEffect(() => {
|
|
196
269
|
const tabIndent =
|
|
197
270
|
!!(tabIntentStyle === "tab" && mode && !(tabForceSpaceForModes ?? []).includes(mode)) || enableTab;
|
|
@@ -219,13 +292,23 @@ export const CodeEditor = ({
|
|
|
219
292
|
keymap?.of(keyMapConfigs),
|
|
220
293
|
EditorState?.tabSize.of(tabIntentSize),
|
|
221
294
|
EditorState?.readOnly.of(readOnly),
|
|
295
|
+
EditorView?.editable.of(!disabled),
|
|
222
296
|
AdaptedEditorViewDomEventHandlers(domEventHandlers) as Extension,
|
|
223
297
|
EditorView?.updateListener.of((v: ViewUpdate) => {
|
|
224
|
-
|
|
298
|
+
if (disabled) return;
|
|
299
|
+
|
|
300
|
+
if (onChange && v.docChanged) {
|
|
301
|
+
// Only fire if the text has actually been changed
|
|
302
|
+
onChange(v.state.doc.toString());
|
|
303
|
+
}
|
|
225
304
|
|
|
226
305
|
if (onSelection)
|
|
227
306
|
onSelection(v.state.selection.ranges.filter((r) => !r.empty).map(({ from, to }) => ({ from, to })));
|
|
228
307
|
|
|
308
|
+
if (onFocusChange && intent && !v.view.dom.classList?.contains(`${eccgui}-intent--${intent}`)) {
|
|
309
|
+
v.view.dom.classList.add(`${eccgui}-intent--${intent}`);
|
|
310
|
+
}
|
|
311
|
+
|
|
229
312
|
if (onCursorChange) {
|
|
230
313
|
const cursorPosition = v.state.selection.main.head ?? 0;
|
|
231
314
|
const editorRect = v.view.dom.getBoundingClientRect();
|
|
@@ -250,6 +333,7 @@ export const CodeEditor = ({
|
|
|
250
333
|
addExtensionsFor(shouldHighlightActiveLine, adaptedHighlightActiveLine()),
|
|
251
334
|
addExtensionsFor(wrapLines, EditorView?.lineWrapping),
|
|
252
335
|
addExtensionsFor(supportCodeFolding, adaptedFoldGutter(), adaptedCodeFolding()),
|
|
336
|
+
addExtensionsFor(useLinting, ...linters),
|
|
253
337
|
additionalExtensions,
|
|
254
338
|
];
|
|
255
339
|
|
|
@@ -260,18 +344,67 @@ export const CodeEditor = ({
|
|
|
260
344
|
}),
|
|
261
345
|
parent: parent.current,
|
|
262
346
|
});
|
|
347
|
+
setView(view);
|
|
263
348
|
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
349
|
+
if (view?.dom) {
|
|
350
|
+
if (height) {
|
|
351
|
+
view.dom.style.height = typeof height === "string" ? height : `${height}px`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (disabled) {
|
|
355
|
+
view.dom.className += ` ${eccgui}-disabled`;
|
|
356
|
+
}
|
|
267
357
|
|
|
268
|
-
|
|
358
|
+
if (intent) {
|
|
359
|
+
view.dom.className += ` ${eccgui}-intent--${intent}`;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (autoFocus) {
|
|
363
|
+
view.focus();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (setEditorView) {
|
|
367
|
+
setEditorView(view);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
269
370
|
|
|
270
371
|
return () => {
|
|
271
372
|
view.destroy();
|
|
272
|
-
|
|
373
|
+
if (setEditorView) {
|
|
374
|
+
setEditorView(undefined);
|
|
375
|
+
setView(undefined);
|
|
376
|
+
}
|
|
273
377
|
};
|
|
274
|
-
}, [parent.current, mode, preventLineNumbers]);
|
|
378
|
+
}, [parent.current, mode, preventLineNumbers, wrapLines]);
|
|
379
|
+
|
|
380
|
+
const hasToolbarSupport = mode && ModeToolbarSupport.indexOf(mode) > -1 && useToolbar;
|
|
381
|
+
|
|
382
|
+
const editorToolbar = (mode?: SupportedCodeEditorModes): JSX.Element => {
|
|
383
|
+
switch (mode) {
|
|
384
|
+
case "markdown":
|
|
385
|
+
return (
|
|
386
|
+
<div>
|
|
387
|
+
<div className={`${eccgui}-codeeditor__toolbar`}>
|
|
388
|
+
<MarkdownToolbar
|
|
389
|
+
view={view}
|
|
390
|
+
togglePreviewStatus={() => setShowPreview((p) => !p)}
|
|
391
|
+
showPreview={showPreview}
|
|
392
|
+
translate={getTranslation}
|
|
393
|
+
disabled={disabled}
|
|
394
|
+
readonly={readOnly}
|
|
395
|
+
/>
|
|
396
|
+
</div>
|
|
397
|
+
{showPreview && (
|
|
398
|
+
<div className={`${eccgui}-codeeditor__preview`}>
|
|
399
|
+
<Markdown>{view?.state.doc.toString() ?? ""}</Markdown>
|
|
400
|
+
</div>
|
|
401
|
+
)}
|
|
402
|
+
</div>
|
|
403
|
+
);
|
|
404
|
+
default:
|
|
405
|
+
return <></>;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
275
408
|
|
|
276
409
|
return (
|
|
277
410
|
<div
|
|
@@ -279,12 +412,17 @@ export const CodeEditor = ({
|
|
|
279
412
|
// overwrite/extend some attributes
|
|
280
413
|
id={id ? id : name ? `codemirror-${name}` : undefined}
|
|
281
414
|
ref={parent}
|
|
282
|
-
|
|
415
|
+
// @deprecated (v25) fallback with static test id will be removed
|
|
416
|
+
data-test-id={dataTestId ? dataTestId : "codemirror-wrapper"}
|
|
283
417
|
className={
|
|
284
418
|
`${eccgui}-codeeditor ${eccgui}-codeeditor--mode-${mode}` +
|
|
285
|
-
(outerDivAttributes?.className ? ` ${outerDivAttributes?.className}` : "")
|
|
419
|
+
(outerDivAttributes?.className ? ` ${outerDivAttributes?.className}` : "") +
|
|
420
|
+
(hasToolbarSupport ? ` ${eccgui}-codeeditor--has-toolbar` : "")
|
|
286
421
|
}
|
|
287
|
-
|
|
422
|
+
{...otherCodeEditorProps}
|
|
423
|
+
>
|
|
424
|
+
{hasToolbarSupport && editorToolbar(mode)}
|
|
425
|
+
</div>
|
|
288
426
|
);
|
|
289
427
|
};
|
|
290
428
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
@use "sass:color";
|
|
2
|
+
|
|
1
3
|
// own vars
|
|
2
4
|
$eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default;
|
|
5
|
+
$eccgui-color-codeeditor-separation: $eccgui-color-separation-divider !default;
|
|
6
|
+
$eccgui-size-codeeditor-height: 20rem !default;
|
|
7
|
+
$eccgui-size-codeeditor-toolbar-height: $button-height !default;
|
|
3
8
|
|
|
4
9
|
// adjustments
|
|
5
10
|
// stylelint-disable selector-class-pattern
|
|
@@ -12,9 +17,39 @@ $eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default
|
|
|
12
17
|
width: 100%;
|
|
13
18
|
}
|
|
14
19
|
|
|
20
|
+
&__toolbar {
|
|
21
|
+
position: absolute;
|
|
22
|
+
z-index: 3;
|
|
23
|
+
left: 1px;
|
|
24
|
+
right: 1px;
|
|
25
|
+
top: 1px;
|
|
26
|
+
border-radius: $pt-border-radius $pt-border-radius 0 0;
|
|
27
|
+
border-bottom: solid 1px $eccgui-color-codeeditor-separation;
|
|
28
|
+
background-color: $eccgui-color-codeeditor-background;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&--has-toolbar {
|
|
32
|
+
.cm-scroller {
|
|
33
|
+
margin-top: $eccgui-size-codeeditor-toolbar-height !important;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&__preview {
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: calc(#{$eccgui-size-codeeditor-toolbar-height} + 1px) !important;
|
|
40
|
+
left: 1px;
|
|
41
|
+
right: 1px;
|
|
42
|
+
bottom: 1px;
|
|
43
|
+
z-index: 2;
|
|
44
|
+
padding: $button-padding;
|
|
45
|
+
overflow-y: auto;
|
|
46
|
+
background-color: $eccgui-color-codeeditor-background;
|
|
47
|
+
border-radius: 0 0 $pt-border-radius $pt-border-radius;
|
|
48
|
+
}
|
|
49
|
+
|
|
15
50
|
.cm-editor {
|
|
16
51
|
width: 100%;
|
|
17
|
-
height:
|
|
52
|
+
height: $eccgui-size-codeeditor-height;
|
|
18
53
|
clip-path: unset !important; // we may check later why they set inset(0) now
|
|
19
54
|
background-color: $eccgui-color-codeeditor-background;
|
|
20
55
|
border-radius: $pt-border-radius;
|
|
@@ -22,6 +57,63 @@ $eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default
|
|
|
22
57
|
// get them a "border" like input boxes from blueprintjs
|
|
23
58
|
box-shadow: input-transition-shadow($input-shadow-color-focus), $pt-input-box-shadow;
|
|
24
59
|
|
|
60
|
+
&.#{eccgui}-disabled {
|
|
61
|
+
@extend .#{$ns}-input, .#{$ns}-disabled;
|
|
62
|
+
|
|
63
|
+
height: $eccgui-size-codeeditor-height;
|
|
64
|
+
padding: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&[class*="#{$eccgui}-intent--"] {
|
|
68
|
+
animation-duration: 1s;
|
|
69
|
+
animation-delay: 0.5s;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@each $each-intent, $each-bgcolor in $eccgui-map-intent-bgcolors {
|
|
73
|
+
&.#{eccgui}-intent--#{$each-intent} {
|
|
74
|
+
background-color: color.mix($each-bgcolor, $eccgui-color-textfield-background, 24%);
|
|
75
|
+
animation-name: intent-state-flash-#{$each-intent};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&.#{eccgui}-intent--warning {
|
|
80
|
+
@include pt-input-intent($eccgui-color-warning-text);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&.#{eccgui}-intent--success {
|
|
84
|
+
@include pt-input-intent($eccgui-color-success-text);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&.#{eccgui}-intent--danger {
|
|
88
|
+
@include pt-input-intent($eccgui-color-danger-text);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&.#{eccgui}-intent--primary {
|
|
92
|
+
@include pt-input-intent($eccgui-color-info-text);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&.#{eccgui}-intent--info {
|
|
96
|
+
@include pt-input-intent($eccgui-color-info-text);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&.#{eccgui}-intent--accent {
|
|
100
|
+
@include pt-input-intent($eccgui-color-primary);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&.#{eccgui}-intent--neutral {
|
|
104
|
+
@include pt-input-intent($eccgui-color-workspace-text);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&.#{eccgui}-intent--edited {
|
|
108
|
+
@include pt-input-intent($eccgui-color-info-text);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&.#{eccgui}-intent--removed {
|
|
112
|
+
@include pt-input-intent($eccgui-color-danger-text);
|
|
113
|
+
|
|
114
|
+
text-decoration: line-through $eccgui-color-danger-text 2px;
|
|
115
|
+
}
|
|
116
|
+
|
|
25
117
|
.cm-scroller {
|
|
26
118
|
width: calc(100% - 2px);
|
|
27
119
|
height: calc(100% - 2px);
|
|
@@ -34,6 +126,43 @@ $eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default
|
|
|
34
126
|
&.cm-focused {
|
|
35
127
|
outline: none;
|
|
36
128
|
box-shadow: input-transition-shadow($input-shadow-color-focus, true), $input-box-shadow-focus;
|
|
129
|
+
|
|
130
|
+
&.#{eccgui}-intent--warning {
|
|
131
|
+
box-shadow: input-transition-shadow($eccgui-color-warning-text, true), $input-box-shadow-focus;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.#{eccgui}-intent--success {
|
|
135
|
+
box-shadow: input-transition-shadow($eccgui-color-success-text, true), $input-box-shadow-focus;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&.#{eccgui}-intent--danger {
|
|
139
|
+
box-shadow: input-transition-shadow($eccgui-color-danger-text, true), $input-box-shadow-focus;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&.#{eccgui}-intent--primary {
|
|
143
|
+
box-shadow: input-transition-shadow($eccgui-color-info-text, true), $input-box-shadow-focus;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
&.#{eccgui}-intent--info {
|
|
147
|
+
box-shadow: input-transition-shadow($eccgui-color-info-text, true), $input-box-shadow-focus;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&.#{eccgui}-intent--accent {
|
|
151
|
+
box-shadow: input-transition-shadow($eccgui-color-warning-text, true), $input-box-shadow-focus;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
&.#{eccgui}-intent--neutral {
|
|
155
|
+
box-shadow: input-transition-shadow($eccgui-color-workspace-text, true), $input-box-shadow-focus;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
&.#{eccgui}-intent--edited {
|
|
159
|
+
box-shadow: input-transition-shadow($eccgui-color-info-text, true), $input-box-shadow-focus;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
&.#{eccgui}-intent--removed {
|
|
163
|
+
text-decoration: line-through $eccgui-color-danger-text 2px;
|
|
164
|
+
box-shadow: input-transition-shadow($eccgui-color-danger-text, true), $input-box-shadow-focus;
|
|
165
|
+
}
|
|
37
166
|
}
|
|
38
167
|
|
|
39
168
|
.CodeMirror-hscrollbar {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Diagnostic } from "@codemirror/lint";
|
|
2
|
+
import { EditorView } from "@codemirror/view";
|
|
3
|
+
import { debounce } from "lodash";
|
|
4
|
+
|
|
5
|
+
import { Linter } from "./types";
|
|
6
|
+
|
|
7
|
+
const DEBOUNCE_TIME = 500;
|
|
8
|
+
|
|
9
|
+
export const debouncedLinter = (lintFunction: Linter, time = DEBOUNCE_TIME) => {
|
|
10
|
+
const debouncedFn = debounce(
|
|
11
|
+
(
|
|
12
|
+
view: EditorView,
|
|
13
|
+
resolve: (diagnostics: ReadonlyArray<Diagnostic> | Promise<ReadonlyArray<Diagnostic>>) => void
|
|
14
|
+
) => {
|
|
15
|
+
const diagnostics = lintFunction(view);
|
|
16
|
+
resolve(diagnostics);
|
|
17
|
+
},
|
|
18
|
+
time
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return (view: EditorView) => {
|
|
22
|
+
return new Promise<ReadonlyArray<Diagnostic>>((resolve) => {
|
|
23
|
+
debouncedFn(view, resolve);
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -48,6 +48,6 @@ export const useCodeMirrorModeExtension = (mode?: SupportedCodeEditorModes) => {
|
|
|
48
48
|
return !mode
|
|
49
49
|
? adaptedSyntaxHighlighting(defaultHighlightStyle)
|
|
50
50
|
: v6AdaptedModes.has(mode)
|
|
51
|
-
? ((typeof supportedModes[mode] === "function" ? supportedModes[mode] : () =>
|
|
51
|
+
? ((typeof supportedModes[mode] === "function" ? supportedModes[mode] : () => null) as () => LanguageSupport)()
|
|
52
52
|
: StreamLanguage?.define(supportedModes[mode] as StreamParser<unknown>);
|
|
53
53
|
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Diagnostic, linter } from "@codemirror/lint";
|
|
2
|
+
import { JSHINT as jshint } from "jshint";
|
|
3
|
+
|
|
4
|
+
import { ExtensionCreator } from "../types";
|
|
5
|
+
|
|
6
|
+
const lintOptions = {
|
|
7
|
+
esversion: 11,
|
|
8
|
+
browser: true,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sets up the javascript linter. Documentation: https://codemirror.net/examples/lint/
|
|
13
|
+
*/
|
|
14
|
+
export const jsLinter: ExtensionCreator = () => {
|
|
15
|
+
return linter((view) => {
|
|
16
|
+
const diagnostics: Array<Diagnostic> = [];
|
|
17
|
+
const codeText = view.state.doc.toJSON();
|
|
18
|
+
jshint(codeText, lintOptions);
|
|
19
|
+
const errors = jshint?.data()?.errors;
|
|
20
|
+
|
|
21
|
+
if (errors && errors.length > 0) {
|
|
22
|
+
errors.forEach((error) => {
|
|
23
|
+
const selectedLine = view.state.doc.line(error.line);
|
|
24
|
+
|
|
25
|
+
const diagnostic: Diagnostic = {
|
|
26
|
+
from: selectedLine.from,
|
|
27
|
+
to: selectedLine.to,
|
|
28
|
+
severity: "error",
|
|
29
|
+
message: error.reason,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
diagnostics.push(diagnostic);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return diagnostics;
|
|
37
|
+
});
|
|
38
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Diagnostic, linter } from "@codemirror/lint";
|
|
2
|
+
import { EditorView } from "@codemirror/view";
|
|
3
|
+
import { Parser } from "n3";
|
|
4
|
+
|
|
5
|
+
import { debouncedLinter } from "../debouncedLinter";
|
|
6
|
+
import { ExtensionCreator, Linter } from "../types";
|
|
7
|
+
|
|
8
|
+
const parser = new Parser();
|
|
9
|
+
|
|
10
|
+
const EMPTY_RESOURCE = "<>";
|
|
11
|
+
|
|
12
|
+
const getError = (message: string, view: EditorView) => {
|
|
13
|
+
const lineMatch = message.match(/(?<=line )\d{1,}/);
|
|
14
|
+
const valueMatch = message.match(/"([^"]*)"/);
|
|
15
|
+
|
|
16
|
+
const lineNumber = lineMatch ? Number(lineMatch[0]) : 1;
|
|
17
|
+
// the [1] index is used to get the caputre group
|
|
18
|
+
const errorContent = valueMatch && valueMatch[1];
|
|
19
|
+
|
|
20
|
+
const line = view.state.doc.line(lineNumber);
|
|
21
|
+
const position = line.text.search(errorContent ?? /\S/);
|
|
22
|
+
|
|
23
|
+
const from = line.from + position;
|
|
24
|
+
const errorLength = errorContent?.length;
|
|
25
|
+
|
|
26
|
+
return { from, to: errorLength ? from + errorLength : line.to };
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getQuadError = (view: EditorView) => {
|
|
30
|
+
const lines = view.state.doc.toJSON();
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
33
|
+
const input = lines[i].trim();
|
|
34
|
+
|
|
35
|
+
if (!input) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (input.includes(EMPTY_RESOURCE)) {
|
|
40
|
+
// i + 1 is used here because the codemirror uses 1-indexes
|
|
41
|
+
const line = view.state.doc.line(i + 1);
|
|
42
|
+
const position = line.text.search(EMPTY_RESOURCE);
|
|
43
|
+
|
|
44
|
+
const from = line.from + position;
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
from,
|
|
48
|
+
to: from + EMPTY_RESOURCE.length,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { from: 0, to: view.state.doc.length };
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const n3Linter: Linter = (view) => {
|
|
57
|
+
const diagnostics: Array<Diagnostic> = [];
|
|
58
|
+
const value = view.state.doc.toString();
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const quads = parser.parse(value);
|
|
62
|
+
|
|
63
|
+
quads.forEach((quad) => {
|
|
64
|
+
if (!quad.subject || !quad.predicate || !quad.object) {
|
|
65
|
+
const { from, to } = getQuadError(view);
|
|
66
|
+
|
|
67
|
+
view.dispatch({
|
|
68
|
+
scrollIntoView: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
diagnostics.push({
|
|
72
|
+
from,
|
|
73
|
+
to,
|
|
74
|
+
severity: "error",
|
|
75
|
+
message: `Invalid RDF quad:\n\nsubject: ${quad.subject}\npredicate: ${quad.predicate}\nobject: ${quad.object}`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
} catch (error) {
|
|
80
|
+
const { message } = error as Error;
|
|
81
|
+
|
|
82
|
+
const { from, to } = getError(message, view);
|
|
83
|
+
|
|
84
|
+
view.dispatch({
|
|
85
|
+
scrollIntoView: true,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
diagnostics.push({
|
|
89
|
+
from,
|
|
90
|
+
to,
|
|
91
|
+
severity: "error",
|
|
92
|
+
message: (error as Error).message,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return diagnostics;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Sets up the turtle linter. Documentation: https://codemirror.net/examples/lint/
|
|
101
|
+
*/
|
|
102
|
+
export const turtleLinter: ExtensionCreator = () => linter(debouncedLinter(n3Linter));
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { EditorView, placeholder, highlightSpecialChars, lineNumbers, highlightActiveLine } from "@codemirror/view";
|
|
11
11
|
import { syntaxHighlighting, foldGutter, codeFolding } from "@codemirror/language";
|
|
12
12
|
import { Extension } from "@codemirror/state";
|
|
13
|
+
import { lintGutter } from "@codemirror/lint";
|
|
13
14
|
|
|
14
15
|
/** placeholder extension, current error '_view.placeholder is not a function' */
|
|
15
16
|
export const adaptedPlaceholder = (text?: string) =>
|
|
@@ -55,3 +56,6 @@ export const adaptedFoldGutter = (props?: any) =>
|
|
|
55
56
|
|
|
56
57
|
export const adaptedCodeFolding = (props?: any) =>
|
|
57
58
|
typeof codeFolding === "function" ? codeFolding(props) : emptyExtension;
|
|
59
|
+
|
|
60
|
+
export const adaptedLintGutter = (props?: any) =>
|
|
61
|
+
typeof lintGutter === "function" ? lintGutter(props) : emptyExtension;
|