diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f6a8d79..ab6366ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Added + +- `` + - Add `intent` property. + ### Fixed - `` diff --git a/src/components/AutoSuggestion/AutoSuggestion.tsx b/src/components/AutoSuggestion/AutoSuggestion.tsx index 057164e2..73783d55 100644 --- a/src/components/AutoSuggestion/AutoSuggestion.tsx +++ b/src/components/AutoSuggestion/AutoSuggestion.tsx @@ -4,6 +4,7 @@ import { Classes as BlueprintClassNames } from "@blueprintjs/core"; import { EditorView, Rect } from "@codemirror/view"; import { debounce } from "lodash"; +import { IntentTypes } from "../../common/Intent"; import { CLASSPREFIX as eccgui } from "../../configuration/constants"; import { SupportedCodeEditorModes } from "../../extensions/codemirror/hooks/useCodemirrorModeExtension.hooks"; @@ -154,6 +155,8 @@ export interface CodeAutocompleteFieldProps { readOnly?: boolean; /** Properties that should be added to the outer div container. */ outerDivAttributes?: Omit, "id" | "data-test-id">; + /** Intent state of the input field. Validation errors override this. */ + intent?: IntentTypes; } // Meta data regarding a request @@ -192,6 +195,7 @@ export const CodeAutocompleteField = ({ height, readOnly, outerDivAttributes, + intent, }: CodeAutocompleteFieldProps) => { const value = React.useRef(initialValue); const cursorPosition = React.useRef(0); @@ -630,6 +634,14 @@ export const CodeAutocompleteField = ({ [] ); + const hasError = !!value.current && !pathIsValid && !pathValidationPending; + const effectiveIntent = hasError ? "danger" : intent; + const blueprintIntent = + effectiveIntent && !["info", "accent", "neutral"].includes(effectiveIntent) + ? effectiveIntent + : undefined; + const inputIntentClass = effectiveIntent ? ` ${eccgui}-intent--${effectiveIntent}` : ""; + const codeEditor = React.useMemo(() => { return ( ); }, [ @@ -661,9 +676,8 @@ export const CodeAutocompleteField = ({ multiline, handleInputMouseDown, readOnly, + effectiveIntent, ]); - - const hasError = !!value.current && !pathIsValid && !pathValidationPending; const autoSuggestionInput = (
), }} - intent={hasError ? "danger" : undefined} + intent={effectiveIntent} messageText={hasError ? validationErrorText : undefined} > {withRightElement} diff --git a/src/extensions/codemirror/CodeMirror.tsx b/src/extensions/codemirror/CodeMirror.tsx index 0e58642f..8d1adbff 100644 --- a/src/extensions/codemirror/CodeMirror.tsx +++ b/src/extensions/codemirror/CodeMirror.tsx @@ -326,6 +326,20 @@ export const CodeEditor = ({ ]; } + const syncIntentClass = React.useCallback((editorView: EditorView | undefined, nextIntent?: CodeEditorProps["intent"]) => { + if (!editorView?.dom) { + return; + } + + Array.from(editorView.dom.classList) + .filter((className) => className.startsWith(`${eccgui}-intent--`)) + .forEach((className) => editorView.dom.classList.remove(className)); + + if (nextIntent) { + editorView.dom.classList.add(`${eccgui}-intent--${nextIntent}`); + } + }, []); + React.useEffect(() => { const domEventHandlers = { ...addHandlersFor(!!onScroll, "scroll", onScroll), @@ -360,7 +374,7 @@ export const CodeEditor = ({ onSelection(v.state.selection.ranges.filter((r) => !r.empty).map(({ from, to }) => ({ from, to }))); if (onFocusChange && currentIntent.current && !v.view.dom.classList?.contains(`${eccgui}-intent--${currentIntent.current}`)) { - v.view.dom.classList.add(`${eccgui}-intent--${currentIntent.current}`); + syncIntentClass(v.view, currentIntent.current); } if (onCursorChange) { @@ -410,9 +424,7 @@ export const CodeEditor = ({ view.dom.classList.add(`${eccgui}-disabled`); } - if (currentIntent.current) { - view.dom.className += ` ${eccgui}-intent--${currentIntent.current}`; - } + syncIntentClass(view, currentIntent.current); if (autoFocus) { view.focus(); @@ -472,6 +484,10 @@ export const CodeEditor = ({ } }, [disabled]) + React.useEffect(() => { + syncIntentClass(view, intent); + }, [intent, view, syncIntentClass]); + React.useEffect(() => { setEditorAppearance({ ...editorAppearance,