@gooddata/sdk-ui-kit 11.52.0 → 11.53.0-alpha.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/esm/@ui/UiConfigEditor/ConfigEditorToolbar.d.ts +26 -0
- package/esm/@ui/UiConfigEditor/ConfigEditorToolbar.d.ts.map +1 -0
- package/esm/@ui/UiConfigEditor/ConfigEditorToolbar.js +38 -0
- package/esm/@ui/UiConfigEditor/UiConfigEditor.d.ts +20 -0
- package/esm/@ui/UiConfigEditor/UiConfigEditor.d.ts.map +1 -0
- package/esm/@ui/UiConfigEditor/UiConfigEditor.js +229 -0
- package/esm/@ui/UiConfigEditor/configEditorGrammars.d.ts +15 -0
- package/esm/@ui/UiConfigEditor/configEditorGrammars.d.ts.map +1 -0
- package/esm/@ui/UiConfigEditor/configEditorGrammars.js +50 -0
- package/esm/@ui/UiConfigEditor/configEditorHighlighting.d.ts +6 -0
- package/esm/@ui/UiConfigEditor/configEditorHighlighting.d.ts.map +1 -0
- package/esm/@ui/UiConfigEditor/configEditorHighlighting.js +31 -0
- package/esm/@ui/UiConfigEditor/configEditorLanguage.d.ts +43 -0
- package/esm/@ui/UiConfigEditor/configEditorLanguage.d.ts.map +1 -0
- package/esm/@ui/UiConfigEditor/configEditorLanguage.js +179 -0
- package/esm/@ui/UiConfigEditor/types.d.ts +135 -0
- package/esm/@ui/UiConfigEditor/types.d.ts.map +1 -0
- package/esm/@ui/UiConfigEditor/types.js +2 -0
- package/esm/@ui/UiMenu/components/defaults/DefaultUiMenuHeader.d.ts.map +1 -1
- package/esm/@ui/UiMenu/components/defaults/DefaultUiMenuHeader.js +5 -2
- package/esm/@ui/UiSubmenuHeader/UiSubmenuHeader.d.ts +2 -2
- package/esm/@ui/UiSubmenuHeader/UiSubmenuHeader.d.ts.map +1 -1
- package/esm/@ui/UiSubmenuHeader/UiSubmenuHeader.js +1 -0
- package/esm/Dialog/StylingEditorDialog/StylingEditorDialog.d.ts +13 -0
- package/esm/Dialog/StylingEditorDialog/StylingEditorDialog.d.ts.map +1 -1
- package/esm/Dialog/StylingEditorDialog/StylingEditorDialog.js +19 -4
- package/esm/List/DateDatasetsListItem.d.ts.map +1 -1
- package/esm/List/DateDatasetsListItem.js +1 -2
- package/esm/index.d.ts +5 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +2 -1
- package/esm/sdk-ui-kit.d.ts +204 -36
- package/esm/syntaxHighlightingInput/SyntaxHighlightingInput.d.ts +7 -1
- package/esm/syntaxHighlightingInput/SyntaxHighlightingInput.d.ts.map +1 -1
- package/esm/syntaxHighlightingInput/SyntaxHighlightingInput.js +2 -1
- package/esm/syntaxHighlightingInput/hooks/useChangeHandler.d.ts.map +1 -1
- package/esm/syntaxHighlightingInput/hooks/useChangeHandler.js +9 -2
- package/esm/syntaxHighlightingInput/hooks/useCodemirror.d.ts +4 -1
- package/esm/syntaxHighlightingInput/hooks/useCodemirror.d.ts.map +1 -1
- package/esm/syntaxHighlightingInput/hooks/useCodemirror.js +2 -2
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorChange.d.ts +12 -1
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorChange.d.ts.map +1 -1
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorChange.js +10 -8
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorEditable.d.ts.map +1 -1
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorEditable.js +11 -4
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorKeymap.d.ts +1 -1
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorKeymap.d.ts.map +1 -1
- package/esm/syntaxHighlightingInput/hooks/useCodemirrorKeymap.js +26 -22
- package/esm/syntaxHighlightingInput/syntaxErrorLinter.d.ts +24 -0
- package/esm/syntaxHighlightingInput/syntaxErrorLinter.d.ts.map +1 -0
- package/esm/syntaxHighlightingInput/syntaxErrorLinter.js +49 -0
- package/package.json +13 -11
- package/src/@ui/UiConfigEditor/UiConfigEditor.scss +169 -0
- package/src/@ui/UiMenu/UiMenu.scss +6 -0
- package/src/@ui/UiSubmenuHeader/UiSubmenuHeader.scss +15 -0
- package/src/@ui/index.scss +1 -0
- package/styles/css/main.css +132 -0
- package/styles/css/main.css.map +1 -1
- package/styles/css/stylingEditorDialog.css +5 -0
- package/styles/css/stylingEditorDialog.css.map +1 -1
- package/styles/scss/stylingEditorDialog.scss +8 -0
- package/esm/syntaxHighlightingInput/YamlEditor.d.ts +0 -35
- package/esm/syntaxHighlightingInput/YamlEditor.d.ts.map +0 -1
- package/esm/syntaxHighlightingInput/YamlEditor.js +0 -32
- package/esm/syntaxHighlightingInput/yamlSyntaxLinter.d.ts +0 -12
- package/esm/syntaxHighlightingInput/yamlSyntaxLinter.d.ts.map +0 -1
- package/esm/syntaxHighlightingInput/yamlSyntaxLinter.js +0 -32
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// (C) 2025 GoodData Corporation
|
|
1
|
+
// (C) 2025-2026 GoodData Corporation
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import { EditorSelection, Transaction } from "@codemirror/state";
|
|
4
|
-
export function useCodemirrorChange(viewRef, value) {
|
|
4
|
+
export function useCodemirrorChange(viewRef, value, externalChangeSelection = "clamp") {
|
|
5
5
|
// Handle external value changes
|
|
6
6
|
useEffect(() => {
|
|
7
7
|
const view = viewRef.current;
|
|
@@ -13,11 +13,13 @@ export function useCodemirrorChange(viewRef, value) {
|
|
|
13
13
|
const hasFocus = view.hasFocus;
|
|
14
14
|
const newLength = value.length;
|
|
15
15
|
// Adjust selection to stay within bounds of new content
|
|
16
|
-
const adjustedSelection =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
const adjustedSelection = externalChangeSelection === "end"
|
|
17
|
+
? EditorSelection.single(newLength)
|
|
18
|
+
: EditorSelection.create(selection.ranges.map((range) => {
|
|
19
|
+
const from = Math.min(range.from, newLength);
|
|
20
|
+
const to = Math.min(range.to, newLength);
|
|
21
|
+
return EditorSelection.range(from, to);
|
|
22
|
+
}), selection.mainIndex);
|
|
21
23
|
view.dispatch({
|
|
22
24
|
changes: { from: 0, to: currentValue.length, insert: value },
|
|
23
25
|
selection: adjustedSelection,
|
|
@@ -30,5 +32,5 @@ export function useCodemirrorChange(viewRef, value) {
|
|
|
30
32
|
view.focus();
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
|
-
}, [value, viewRef]);
|
|
35
|
+
}, [value, viewRef, externalChangeSelection]);
|
|
34
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCodemirrorEditable.d.ts","sourceRoot":"","sources":["../../../src/syntaxHighlightingInput/hooks/useCodemirrorEditable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"useCodemirrorEditable.d.ts","sourceRoot":"","sources":["../../../src/syntaxHighlightingInput/hooks/useCodemirrorEditable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAU9C,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAO;;EAqB9F"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
// (C) 2025 GoodData Corporation
|
|
1
|
+
// (C) 2025-2026 GoodData Corporation
|
|
2
2
|
import { useEffect, useRef } from "react";
|
|
3
|
-
import { Compartment } from "@codemirror/state";
|
|
3
|
+
import { Compartment, EditorState } from "@codemirror/state";
|
|
4
4
|
import { EditorView } from "@codemirror/view";
|
|
5
|
+
// `EditorView.editable` only governs the DOM's contenteditable, which blocks typing; keymap
|
|
6
|
+
// commands (Enter, deletions, undo) consult `EditorState.readOnly` instead, so both must flip
|
|
7
|
+
// together or a "read-only" editor still mutates from the keyboard.
|
|
8
|
+
const editableExtensions = (disabled) => [
|
|
9
|
+
EditorView.editable.of(!disabled),
|
|
10
|
+
EditorState.readOnly.of(disabled),
|
|
11
|
+
];
|
|
5
12
|
export function useCodemirrorEditable(viewRef, disabled) {
|
|
6
13
|
// Editable compartment
|
|
7
14
|
const editableCompartmentRef = useRef(new Compartment());
|
|
8
|
-
const editableCompartmentExtension = editableCompartmentRef.current.of(
|
|
15
|
+
const editableCompartmentExtension = editableCompartmentRef.current.of(editableExtensions(!!disabled));
|
|
9
16
|
// Handle disabled state changes
|
|
10
17
|
useEffect(() => {
|
|
11
18
|
const view = viewRef.current;
|
|
@@ -14,7 +21,7 @@ export function useCodemirrorEditable(viewRef, disabled) {
|
|
|
14
21
|
}
|
|
15
22
|
// Update the editable compartment based on the disabled prop
|
|
16
23
|
view.dispatch({
|
|
17
|
-
effects: editableCompartmentRef.current.reconfigure(
|
|
24
|
+
effects: editableCompartmentRef.current.reconfigure(editableExtensions(!!disabled)),
|
|
18
25
|
});
|
|
19
26
|
}, [disabled, viewRef]);
|
|
20
27
|
return {
|
|
@@ -3,6 +3,6 @@ import { type EditorView } from "@codemirror/view";
|
|
|
3
3
|
export declare function useCodemirrorKeymap({ handleKeyDown }: {
|
|
4
4
|
handleKeyDown: RefObject<((event: KeyboardEvent, view: EditorView) => boolean) | undefined>;
|
|
5
5
|
}): {
|
|
6
|
-
keymapExtension: import("@codemirror/state").Extension;
|
|
6
|
+
keymapExtension: import("@codemirror/state").Extension[];
|
|
7
7
|
};
|
|
8
8
|
//# sourceMappingURL=useCodemirrorKeymap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCodemirrorKeymap.d.ts","sourceRoot":"","sources":["../../../src/syntaxHighlightingInput/hooks/useCodemirrorKeymap.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAW,MAAM,OAAO,CAAC;AAIhD,OAAO,EAAE,KAAK,UAAU,EAAU,MAAM,kBAAkB,CAAC;AAE3D,wBAAgB,mBAAmB,CAAC,EAChC,aAAa,EAChB,EAAE;IACC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC;CAC/F;;
|
|
1
|
+
{"version":3,"file":"useCodemirrorKeymap.d.ts","sourceRoot":"","sources":["../../../src/syntaxHighlightingInput/hooks/useCodemirrorKeymap.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAW,MAAM,OAAO,CAAC;AAIhD,OAAO,EAAE,KAAK,UAAU,EAAU,MAAM,kBAAkB,CAAC;AAE3D,wBAAgB,mBAAmB,CAAC,EAChC,aAAa,EAChB,EAAE;IACC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC;CAC/F;;EA8BA"}
|
|
@@ -1,31 +1,35 @@
|
|
|
1
|
-
// (C) 2025 GoodData Corporation
|
|
1
|
+
// (C) 2025-2026 GoodData Corporation
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { startCompletion } from "@codemirror/autocomplete";
|
|
4
|
-
import { defaultKeymap, historyKeymap } from "@codemirror/commands";
|
|
4
|
+
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
|
|
5
5
|
import { keymap } from "@codemirror/view";
|
|
6
6
|
export function useCodemirrorKeymap({ handleKeyDown, }) {
|
|
7
|
-
// Keymap extension
|
|
7
|
+
// Keymap extension. The history state extension comes with it: `historyKeymap` binds the
|
|
8
|
+
// undo/redo commands, but without `history()` installed they have nothing to operate on.
|
|
8
9
|
const keymapExtension = useMemo(() => {
|
|
9
|
-
return
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
return [
|
|
11
|
+
history(),
|
|
12
|
+
keymap.of([
|
|
13
|
+
// Handle custom keydown events
|
|
14
|
+
{
|
|
15
|
+
any(view, event) {
|
|
16
|
+
return handleKeyDown.current?.(event, view) ?? false;
|
|
17
|
+
},
|
|
14
18
|
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]
|
|
19
|
+
// "Mod" is Ctrl on Windows/Linux, Cmd on macOS
|
|
20
|
+
{
|
|
21
|
+
key: "Mod-i",
|
|
22
|
+
run: startCompletion,
|
|
23
|
+
},
|
|
24
|
+
// Ctrl on Windows
|
|
25
|
+
{
|
|
26
|
+
key: "Ctrl-i",
|
|
27
|
+
run: startCompletion,
|
|
28
|
+
},
|
|
29
|
+
...defaultKeymap,
|
|
30
|
+
...historyKeymap,
|
|
31
|
+
]),
|
|
32
|
+
];
|
|
29
33
|
}, [handleKeyDown]);
|
|
30
34
|
return { keymapExtension };
|
|
31
35
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Diagnostic } from "@codemirror/lint";
|
|
2
|
+
import { type EditorState } from "@codemirror/state";
|
|
3
|
+
/**
|
|
4
|
+
* Collects syntax-error diagnostics by walking the parse tree for error nodes.
|
|
5
|
+
*
|
|
6
|
+
* A blank document reports nothing: grammars differ on whether emptiness parses (JSON requires a
|
|
7
|
+
* value, YAML does not), but an editor the user has not typed into yet is not in error — that is
|
|
8
|
+
* what the caller's own "required" validation says, not the gutter.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function getSyntaxErrorDiagnostics(state: EditorState, message: string): Diagnostic[];
|
|
13
|
+
/**
|
|
14
|
+
* Creates a CodeMirror linter extension that reports syntax errors by walking the parse tree for
|
|
15
|
+
* error nodes.
|
|
16
|
+
*
|
|
17
|
+
* Language-agnostic: it reads the tree the language extension already built for highlighting, so it
|
|
18
|
+
* works for any grammar and costs no extra parse and no extra dependency.
|
|
19
|
+
*
|
|
20
|
+
* @param message - localized message shown on each syntax-error diagnostic
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export declare function createSyntaxErrorLinter(message: string): import("@codemirror/state").Extension;
|
|
24
|
+
//# sourceMappingURL=syntaxErrorLinter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syntaxErrorLinter.d.ts","sourceRoot":"","sources":["../../src/syntaxHighlightingInput/syntaxErrorLinter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAAU,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CA0B3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,yCAEtD"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { syntaxTree } from "@codemirror/language";
|
|
3
|
+
import { linter } from "@codemirror/lint";
|
|
4
|
+
/**
|
|
5
|
+
* Collects syntax-error diagnostics by walking the parse tree for error nodes.
|
|
6
|
+
*
|
|
7
|
+
* A blank document reports nothing: grammars differ on whether emptiness parses (JSON requires a
|
|
8
|
+
* value, YAML does not), but an editor the user has not typed into yet is not in error — that is
|
|
9
|
+
* what the caller's own "required" validation says, not the gutter.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export function getSyntaxErrorDiagnostics(state, message) {
|
|
14
|
+
if (state.doc.toString().trim() === "") {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const diagnostics = [];
|
|
18
|
+
const tree = syntaxTree(state);
|
|
19
|
+
tree.iterate({
|
|
20
|
+
enter(node) {
|
|
21
|
+
if (node.type.isError) {
|
|
22
|
+
diagnostics.push({
|
|
23
|
+
from: node.from,
|
|
24
|
+
// Zero-width error nodes are widened so the marker has something to underline —
|
|
25
|
+
// but never past the end of the document, where an incomplete document's EOF
|
|
26
|
+
// error sits: a diagnostic outside the document is out of contract for the lint
|
|
27
|
+
// state and can throw once decorations are built from it.
|
|
28
|
+
to: Math.min(Math.max(node.to, node.from + 1), state.doc.length),
|
|
29
|
+
severity: "error",
|
|
30
|
+
message,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
return diagnostics;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates a CodeMirror linter extension that reports syntax errors by walking the parse tree for
|
|
39
|
+
* error nodes.
|
|
40
|
+
*
|
|
41
|
+
* Language-agnostic: it reads the tree the language extension already built for highlighting, so it
|
|
42
|
+
* works for any grammar and costs no extra parse and no extra dependency.
|
|
43
|
+
*
|
|
44
|
+
* @param message - localized message shown on each syntax-error diagnostic
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
export function createSyntaxErrorLinter(message) {
|
|
48
|
+
return linter((view) => getSyntaxErrorDiagnostics(view.state, message));
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-kit",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.53.0-alpha.1",
|
|
4
4
|
"description": "GoodData SDK - UI Building Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@aaronhayes/react-use-hubspot-form": "2.1.2",
|
|
39
39
|
"@codemirror/autocomplete": "6.20.0",
|
|
40
40
|
"@codemirror/commands": "6.10.1",
|
|
41
|
+
"@codemirror/lang-json": "6.0.2",
|
|
41
42
|
"@codemirror/lang-yaml": "6.1.3",
|
|
42
43
|
"@codemirror/language": "6.12.1",
|
|
43
44
|
"@codemirror/lint": "6.9.2",
|
|
@@ -76,11 +77,12 @@
|
|
|
76
77
|
"tslib": "2.8.1",
|
|
77
78
|
"unified": "^11.0.5",
|
|
78
79
|
"uuid": "11.1.1",
|
|
79
|
-
"
|
|
80
|
-
"@gooddata/sdk-backend-spi": "11.
|
|
81
|
-
"@gooddata/sdk-
|
|
82
|
-
"@gooddata/sdk-ui
|
|
83
|
-
"@gooddata/util": "11.
|
|
80
|
+
"yaml": "2.8.3",
|
|
81
|
+
"@gooddata/sdk-backend-spi": "11.53.0-alpha.1",
|
|
82
|
+
"@gooddata/sdk-model": "11.53.0-alpha.1",
|
|
83
|
+
"@gooddata/sdk-ui": "11.53.0-alpha.1",
|
|
84
|
+
"@gooddata/util": "11.53.0-alpha.1",
|
|
85
|
+
"@gooddata/sdk-ui-theme-provider": "11.53.0-alpha.1"
|
|
84
86
|
},
|
|
85
87
|
"devDependencies": {
|
|
86
88
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -129,11 +131,11 @@
|
|
|
129
131
|
"typescript": "5.9.3",
|
|
130
132
|
"vitest": "4.1.8",
|
|
131
133
|
"vitest-dom": "0.1.1",
|
|
132
|
-
"@gooddata/
|
|
133
|
-
"@gooddata/
|
|
134
|
-
"@gooddata/
|
|
135
|
-
"@gooddata/sdk-backend-mockingbird": "11.
|
|
136
|
-
"@gooddata/stylelint-config": "11.
|
|
134
|
+
"@gooddata/eslint-config": "11.53.0-alpha.1",
|
|
135
|
+
"@gooddata/oxlint-config": "11.53.0-alpha.1",
|
|
136
|
+
"@gooddata/reference-workspace": "11.53.0-alpha.1",
|
|
137
|
+
"@gooddata/sdk-backend-mockingbird": "11.53.0-alpha.1",
|
|
138
|
+
"@gooddata/stylelint-config": "11.53.0-alpha.1"
|
|
137
139
|
},
|
|
138
140
|
"peerDependencies": {
|
|
139
141
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
|
|
3
|
+
@use "sass:color";
|
|
4
|
+
|
|
5
|
+
@use "../../../styles/scss/variables";
|
|
6
|
+
|
|
7
|
+
.gd-ui-kit-config-editor {
|
|
8
|
+
// The single source for the row-height maths: the fixed editor height below and the pinned
|
|
9
|
+
// content line-height must agree, or `rows` stops meaning whole lines.
|
|
10
|
+
--config-editor-line-height: 1.5;
|
|
11
|
+
|
|
12
|
+
display: flex;
|
|
13
|
+
flex: 1;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
min-height: 0;
|
|
16
|
+
// The frame belongs to the whole control, so the toolbar reads as part of the field rather than
|
|
17
|
+
// as separate chrome floating above it. `overflow: hidden` is what keeps the editor's square
|
|
18
|
+
// corners from poking through the rounded ones.
|
|
19
|
+
border: 1px solid var(--gd-palette-complementary-4);
|
|
20
|
+
border-radius: 3px;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
|
|
23
|
+
&__toolbar {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex: 0 0 auto;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: space-between;
|
|
28
|
+
gap: var(--gd-spacing-10px);
|
|
29
|
+
// A fixed height, so the toolbar reads the same whichever controls happen to be in it —
|
|
30
|
+
// radios, the menu button, or just the Auto-format link. 36px of content plus the divider,
|
|
31
|
+
// sized explicitly so a host's global box-sizing reset cannot change the outcome.
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
height: 37px;
|
|
34
|
+
padding-left: var(--gd-spacing-10px);
|
|
35
|
+
border-bottom: 1px solid var(--gd-palette-complementary-4);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&__languages {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: var(--gd-spacing-10px);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&__actions {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: var(--gd-spacing-10px);
|
|
48
|
+
// Keeps the actions pinned to the right edge even when a single-language editor renders no
|
|
49
|
+
// switcher on the left, where `space-between` alone would let them drift to the start.
|
|
50
|
+
margin-left: auto;
|
|
51
|
+
// Mirrors the switcher's inset on the other side.
|
|
52
|
+
padding-right: var(--gd-spacing-10px);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// With the menu button present the design sits it flush against the frame — the button's own
|
|
56
|
+
// padding is what keeps the ellipsis off the edge, so any padding here would double it.
|
|
57
|
+
&__actions--withMenu {
|
|
58
|
+
padding-right: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__editor {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex: 1;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
min-height: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The shared syntax-highlighting input renders its own wrapper between this element and
|
|
70
|
+
* `.cm-editor`, and that wrapper is a plain block. Without making it part of the flex column the
|
|
71
|
+
* `flex` on `.cm-editor` below is inert, so a long document grows the editor without bound and
|
|
72
|
+
* the surrounding dialog scrolls instead of the editor scrolling inside itself.
|
|
73
|
+
*/
|
|
74
|
+
&__editor > * {
|
|
75
|
+
display: flex;
|
|
76
|
+
flex: 1;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
min-height: 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The shared syntax-highlighting input ships a fixed `height: 100px` on `.cm-editor`, scoped
|
|
83
|
+
* under its own `.gd-input-syntax-highlighting-input` class. That stylesheet is bundled after
|
|
84
|
+
* this one, so at equal specificity it would win — hence the repeated block class, which buys a
|
|
85
|
+
* third class without changing what is matched.
|
|
86
|
+
*
|
|
87
|
+
* Height comes from `rows`, while still growing to fill a taller parent, so the editor works
|
|
88
|
+
* both standalone and as a field in a fixed-height dialog.
|
|
89
|
+
*
|
|
90
|
+
* `--config-editor-rows` is deliberately outside the `--gd-` namespace: that prefix is reserved
|
|
91
|
+
* for theme variables, each of which needs a specification in sdk-ui-theme-provider. This one
|
|
92
|
+
* only carries the `rows` prop into the stylesheet and is not something a theme should set.
|
|
93
|
+
*/
|
|
94
|
+
&.gd-ui-kit-config-editor &__editor .cm-editor {
|
|
95
|
+
// A definite height rather than a floor, so the scroller inside always has something to
|
|
96
|
+
// scroll against: with `min-height` alone a long document grows the editor without bound in
|
|
97
|
+
// any parent that is not itself height-constrained, and the page scrolls instead.
|
|
98
|
+
//
|
|
99
|
+
// `rows` whole lines, plus the 8px of padding CodeMirror puts around its content and the 1px
|
|
100
|
+
// border on each side (the box is border-box). Sizing to whole lines keeps a line from being
|
|
101
|
+
// clipped through the middle, which looks unfinished and makes a screenshot of it turn on how
|
|
102
|
+
// half a glyph happens to be antialiased.
|
|
103
|
+
height: calc(var(--config-editor-rows, 12) * var(--config-editor-line-height) * 1em + 8px);
|
|
104
|
+
// Still grows to take the space when a parent does constrain and offer it, which is what a
|
|
105
|
+
// fixed-height dialog does.
|
|
106
|
+
flex: 1 1 auto;
|
|
107
|
+
min-height: 0;
|
|
108
|
+
// The frame and its corners now belong to the wrapper, so the shared input's own border and
|
|
109
|
+
// radius would draw a second box inside it.
|
|
110
|
+
border: none;
|
|
111
|
+
border-radius: 0;
|
|
112
|
+
// The standard input inner shadow, falling from the toolbar onto the code area. It replaces
|
|
113
|
+
// the shared input's own (which doubles as its focus styling — here focus is shown on the
|
|
114
|
+
// whole field instead), with the design's slightly softer blur.
|
|
115
|
+
box-shadow: inset 0 1px 2px 0 color.adjust(variables.$gd-input-text-box-shadow-color, $alpha: -0.85);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Focus is shown on the whole field instead, so the toolbar is visibly part of what is focused.
|
|
119
|
+
&.gd-ui-kit-config-editor:has(.cm-editor.cm-focused) {
|
|
120
|
+
border-color: var(--gd-palette-primary-base);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Pinned rather than left as `normal`, so the height above is exactly `rows` lines.
|
|
124
|
+
&__editor .cm-content {
|
|
125
|
+
line-height: var(--config-editor-line-height);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Scrolling past the end of a long config should not start scrolling the dialog behind it.
|
|
129
|
+
&__editor .cm-scroller {
|
|
130
|
+
overflow: auto;
|
|
131
|
+
overscroll-behavior: contain;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The design draws no gutter chrome at all: the line numbers sit on the editor's own surface,
|
|
136
|
+
* with no fill and no divider. Making it transparent (rather than a colour) also keeps it
|
|
137
|
+
* correct on a dark theme, where CodeMirror's built-in light-variant gutter would otherwise
|
|
138
|
+
* paint a pale strip — whatever themed background the editor has simply shows through.
|
|
139
|
+
*
|
|
140
|
+
* The repeated block class is for specificity: CodeMirror's own rule is `.cm-editor.cm-light
|
|
141
|
+
* .cm-gutters`, which would otherwise win.
|
|
142
|
+
*/
|
|
143
|
+
&.gd-ui-kit-config-editor &__editor .cm-gutters {
|
|
144
|
+
border-right: none;
|
|
145
|
+
background: transparent;
|
|
146
|
+
color: var(--gd-palette-complementary-6);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&.gd-ui-kit-config-editor &__editor .cm-activeLineGutter {
|
|
150
|
+
background: transparent;
|
|
151
|
+
color: var(--gd-palette-complementary-7);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Muted surface for a value that cannot be edited. Applied to the whole field, toolbar included,
|
|
155
|
+
// now that they share one frame — tinting only the code area would leave a lighter strip on top.
|
|
156
|
+
// The gutter is transparent, so it takes the same muted surface by itself.
|
|
157
|
+
&--disabled,
|
|
158
|
+
&--readOnly {
|
|
159
|
+
background: var(--gd-palette-complementary-1);
|
|
160
|
+
|
|
161
|
+
.cm-editor {
|
|
162
|
+
background: transparent;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&--disabled {
|
|
167
|
+
opacity: 0.7;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -192,6 +192,12 @@
|
|
|
192
192
|
> :not(#{$root}__item-title) {
|
|
193
193
|
flex: none;
|
|
194
194
|
}
|
|
195
|
+
|
|
196
|
+
// The submenu indicator is an affordance, not content, so it takes the muted colour rather
|
|
197
|
+
// than inheriting the label's.
|
|
198
|
+
.gd-icon-navigateright {
|
|
199
|
+
color: var(--gd-palette-complementary-5);
|
|
200
|
+
}
|
|
195
201
|
}
|
|
196
202
|
|
|
197
203
|
&__item-title {
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
align-items: center;
|
|
7
7
|
gap: var(--gd-spacing-5px);
|
|
8
8
|
width: 100%;
|
|
9
|
+
// The horizontal padding must come out of the 100% width, not be added on top of it: without
|
|
10
|
+
// this the header renders wider than the menu that contains it and juts out of the panel in any
|
|
11
|
+
// app that does not carry a global border-box reset.
|
|
12
|
+
box-sizing: border-box;
|
|
9
13
|
color: var(--gd-palette-complementary-6, #94a1ad);
|
|
10
14
|
background: var(--gd-palette-complementary-2, #ebeff4);
|
|
11
15
|
|
|
@@ -23,6 +27,17 @@
|
|
|
23
27
|
text-transform: uppercase;
|
|
24
28
|
}
|
|
25
29
|
|
|
30
|
+
&--small {
|
|
31
|
+
padding: 0 10px;
|
|
32
|
+
height: 35px;
|
|
33
|
+
min-height: 35px;
|
|
34
|
+
|
|
35
|
+
h3.gd-ui-kit-submenu-header__title-text {
|
|
36
|
+
font-size: 11px;
|
|
37
|
+
line-height: normal;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
26
41
|
&--medium {
|
|
27
42
|
padding: 0 10px;
|
|
28
43
|
height: 36px;
|
package/src/@ui/index.scss
CHANGED
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
@use "./UiPermissionMenu/UiPermissionMenu.scss";
|
|
52
52
|
@use "./UiGranteeRowControls/UiGranteeRowControls.scss";
|
|
53
53
|
@use "./UiToast/UiToast.scss";
|
|
54
|
+
@use "./UiConfigEditor/UiConfigEditor.scss";
|
|
54
55
|
|
|
55
56
|
// `--gd-font-family` is a `:root` variable only; there is no global `body` font
|
|
56
57
|
// declaration. Apply it once to every kit root so standalone components don't
|
package/styles/css/main.css
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
1
2
|
:root {
|
|
2
3
|
--gd-palette-error-base: #e54d42;
|
|
3
4
|
--gd-palette-info-base: var(--gd-palette-primary-base, #14b2e2);
|
|
@@ -2000,6 +2001,9 @@
|
|
|
2000
2001
|
.gd-ui-kit-menu__item > :not(.gd-ui-kit-menu__item-title) {
|
|
2001
2002
|
flex: none;
|
|
2002
2003
|
}
|
|
2004
|
+
.gd-ui-kit-menu__item .gd-icon-navigateright {
|
|
2005
|
+
color: var(--gd-palette-complementary-5);
|
|
2006
|
+
}
|
|
2003
2007
|
.gd-ui-kit-menu__item-title {
|
|
2004
2008
|
width: 100%;
|
|
2005
2009
|
min-width: 0;
|
|
@@ -3363,6 +3367,7 @@
|
|
|
3363
3367
|
align-items: center;
|
|
3364
3368
|
gap: var(--gd-spacing-5px);
|
|
3365
3369
|
width: 100%;
|
|
3370
|
+
box-sizing: border-box;
|
|
3366
3371
|
color: var(--gd-palette-complementary-6, #94a1ad);
|
|
3367
3372
|
background: var(--gd-palette-complementary-2, #ebeff4);
|
|
3368
3373
|
}
|
|
@@ -3378,6 +3383,15 @@
|
|
|
3378
3383
|
font-family: var(--gd-font-family, gdcustomfont, Avenir, "Helvetica Neue", arial, sans-serif);
|
|
3379
3384
|
text-transform: uppercase;
|
|
3380
3385
|
}
|
|
3386
|
+
.gd-ui-kit-submenu-header--small {
|
|
3387
|
+
padding: 0 10px;
|
|
3388
|
+
height: 35px;
|
|
3389
|
+
min-height: 35px;
|
|
3390
|
+
}
|
|
3391
|
+
.gd-ui-kit-submenu-header--small h3.gd-ui-kit-submenu-header__title-text {
|
|
3392
|
+
font-size: 11px;
|
|
3393
|
+
line-height: normal;
|
|
3394
|
+
}
|
|
3381
3395
|
.gd-ui-kit-submenu-header--medium {
|
|
3382
3396
|
padding: 0 10px;
|
|
3383
3397
|
height: 36px;
|
|
@@ -4223,6 +4237,119 @@
|
|
|
4223
4237
|
outline-offset: 2px;
|
|
4224
4238
|
}
|
|
4225
4239
|
|
|
4240
|
+
.gd-ui-kit-config-editor {
|
|
4241
|
+
--config-editor-line-height: 1.5;
|
|
4242
|
+
display: flex;
|
|
4243
|
+
flex: 1;
|
|
4244
|
+
flex-direction: column;
|
|
4245
|
+
min-height: 0;
|
|
4246
|
+
border: 1px solid var(--gd-palette-complementary-4);
|
|
4247
|
+
border-radius: 3px;
|
|
4248
|
+
overflow: hidden;
|
|
4249
|
+
/**
|
|
4250
|
+
* The shared syntax-highlighting input renders its own wrapper between this element and
|
|
4251
|
+
* `.cm-editor`, and that wrapper is a plain block. Without making it part of the flex column the
|
|
4252
|
+
* `flex` on `.cm-editor` below is inert, so a long document grows the editor without bound and
|
|
4253
|
+
* the surrounding dialog scrolls instead of the editor scrolling inside itself.
|
|
4254
|
+
*/
|
|
4255
|
+
/**
|
|
4256
|
+
* The shared syntax-highlighting input ships a fixed `height: 100px` on `.cm-editor`, scoped
|
|
4257
|
+
* under its own `.gd-input-syntax-highlighting-input` class. That stylesheet is bundled after
|
|
4258
|
+
* this one, so at equal specificity it would win — hence the repeated block class, which buys a
|
|
4259
|
+
* third class without changing what is matched.
|
|
4260
|
+
*
|
|
4261
|
+
* Height comes from `rows`, while still growing to fill a taller parent, so the editor works
|
|
4262
|
+
* both standalone and as a field in a fixed-height dialog.
|
|
4263
|
+
*
|
|
4264
|
+
* `--config-editor-rows` is deliberately outside the `--gd-` namespace: that prefix is reserved
|
|
4265
|
+
* for theme variables, each of which needs a specification in sdk-ui-theme-provider. This one
|
|
4266
|
+
* only carries the `rows` prop into the stylesheet and is not something a theme should set.
|
|
4267
|
+
*/
|
|
4268
|
+
/**
|
|
4269
|
+
* The design draws no gutter chrome at all: the line numbers sit on the editor's own surface,
|
|
4270
|
+
* with no fill and no divider. Making it transparent (rather than a colour) also keeps it
|
|
4271
|
+
* correct on a dark theme, where CodeMirror's built-in light-variant gutter would otherwise
|
|
4272
|
+
* paint a pale strip — whatever themed background the editor has simply shows through.
|
|
4273
|
+
*
|
|
4274
|
+
* The repeated block class is for specificity: CodeMirror's own rule is `.cm-editor.cm-light
|
|
4275
|
+
* .cm-gutters`, which would otherwise win.
|
|
4276
|
+
*/
|
|
4277
|
+
}
|
|
4278
|
+
.gd-ui-kit-config-editor__toolbar {
|
|
4279
|
+
display: flex;
|
|
4280
|
+
flex: 0 0 auto;
|
|
4281
|
+
align-items: center;
|
|
4282
|
+
justify-content: space-between;
|
|
4283
|
+
gap: var(--gd-spacing-10px);
|
|
4284
|
+
box-sizing: border-box;
|
|
4285
|
+
height: 37px;
|
|
4286
|
+
padding-left: var(--gd-spacing-10px);
|
|
4287
|
+
border-bottom: 1px solid var(--gd-palette-complementary-4);
|
|
4288
|
+
}
|
|
4289
|
+
.gd-ui-kit-config-editor__languages {
|
|
4290
|
+
display: flex;
|
|
4291
|
+
align-items: center;
|
|
4292
|
+
gap: var(--gd-spacing-10px);
|
|
4293
|
+
}
|
|
4294
|
+
.gd-ui-kit-config-editor__actions {
|
|
4295
|
+
display: flex;
|
|
4296
|
+
align-items: center;
|
|
4297
|
+
gap: var(--gd-spacing-10px);
|
|
4298
|
+
margin-left: auto;
|
|
4299
|
+
padding-right: var(--gd-spacing-10px);
|
|
4300
|
+
}
|
|
4301
|
+
.gd-ui-kit-config-editor__actions--withMenu {
|
|
4302
|
+
padding-right: 0;
|
|
4303
|
+
}
|
|
4304
|
+
.gd-ui-kit-config-editor__editor {
|
|
4305
|
+
display: flex;
|
|
4306
|
+
flex: 1;
|
|
4307
|
+
flex-direction: column;
|
|
4308
|
+
min-height: 0;
|
|
4309
|
+
}
|
|
4310
|
+
.gd-ui-kit-config-editor__editor > * {
|
|
4311
|
+
display: flex;
|
|
4312
|
+
flex: 1;
|
|
4313
|
+
flex-direction: column;
|
|
4314
|
+
min-height: 0;
|
|
4315
|
+
}
|
|
4316
|
+
.gd-ui-kit-config-editor.gd-ui-kit-config-editor .gd-ui-kit-config-editor__editor .cm-editor {
|
|
4317
|
+
height: calc(var(--config-editor-rows, 12) * var(--config-editor-line-height) * 1em + 8px);
|
|
4318
|
+
flex: 1 1 auto;
|
|
4319
|
+
min-height: 0;
|
|
4320
|
+
border: none;
|
|
4321
|
+
border-radius: 0;
|
|
4322
|
+
box-shadow: inset 0 1px 2px 0 rgba(31, 53, 74, 0.15);
|
|
4323
|
+
}
|
|
4324
|
+
.gd-ui-kit-config-editor.gd-ui-kit-config-editor:has(.cm-editor.cm-focused) {
|
|
4325
|
+
border-color: var(--gd-palette-primary-base);
|
|
4326
|
+
}
|
|
4327
|
+
.gd-ui-kit-config-editor__editor .cm-content {
|
|
4328
|
+
line-height: var(--config-editor-line-height);
|
|
4329
|
+
}
|
|
4330
|
+
.gd-ui-kit-config-editor__editor .cm-scroller {
|
|
4331
|
+
overflow: auto;
|
|
4332
|
+
overscroll-behavior: contain;
|
|
4333
|
+
}
|
|
4334
|
+
.gd-ui-kit-config-editor.gd-ui-kit-config-editor .gd-ui-kit-config-editor__editor .cm-gutters {
|
|
4335
|
+
border-right: none;
|
|
4336
|
+
background: transparent;
|
|
4337
|
+
color: var(--gd-palette-complementary-6);
|
|
4338
|
+
}
|
|
4339
|
+
.gd-ui-kit-config-editor.gd-ui-kit-config-editor .gd-ui-kit-config-editor__editor .cm-activeLineGutter {
|
|
4340
|
+
background: transparent;
|
|
4341
|
+
color: var(--gd-palette-complementary-7);
|
|
4342
|
+
}
|
|
4343
|
+
.gd-ui-kit-config-editor--disabled, .gd-ui-kit-config-editor--readOnly {
|
|
4344
|
+
background: var(--gd-palette-complementary-1);
|
|
4345
|
+
}
|
|
4346
|
+
.gd-ui-kit-config-editor--disabled .cm-editor, .gd-ui-kit-config-editor--readOnly .cm-editor {
|
|
4347
|
+
background: transparent;
|
|
4348
|
+
}
|
|
4349
|
+
.gd-ui-kit-config-editor--disabled {
|
|
4350
|
+
opacity: 0.7;
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4226
4353
|
[class^=gd-ui-kit-],
|
|
4227
4354
|
[class*=" gd-ui-kit-"] {
|
|
4228
4355
|
font-family: var(--gd-font-family);
|
|
@@ -12847,6 +12974,11 @@ button.gd-button-primary.gd-upsell-button:active {
|
|
|
12847
12974
|
color: var(--gd-palette-complementary-7, #6d7680);
|
|
12848
12975
|
margin-top: 20px;
|
|
12849
12976
|
}
|
|
12977
|
+
.gd-styling-editor-dialog-content-form-textarea > div {
|
|
12978
|
+
flex: 1;
|
|
12979
|
+
min-height: 0;
|
|
12980
|
+
margin-bottom: 20px;
|
|
12981
|
+
}
|
|
12850
12982
|
.gd-styling-editor-dialog-content-form-textarea textarea {
|
|
12851
12983
|
resize: none;
|
|
12852
12984
|
flex: 1;
|