diff --git a/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx b/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx index ac3ac11aec6..570257c27b5 100644 --- a/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx @@ -1,4 +1,4 @@ -import { HTMLProps, ReactNode, useEffect, useRef, useState } from 'react'; +import { HTMLProps, ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/CodeEditor/code-editor'; import fileUploadStyles from '@patternfly/react-styles/css/components/FileUpload/file-upload'; @@ -157,6 +157,8 @@ export interface CodeEditorProps extends Omit, 'onChan isCopyEnabled?: boolean; /** Flag indicating the editor is styled using monaco's dark theme. */ isDarkTheme?: boolean; + /** Flag indicating the editor is styled using a high contrast theme. When combined with isDarkTheme, uses monaco's 'hc-black' theme; otherwise uses 'hc-light'. */ + isHighContrast?: boolean; /** Flag that enables component to consume the available height of its container. If `height` prop is set to 100%, this will also become enabled. */ isFullHeight?: boolean; /** Flag indicating the editor has a plain header. */ @@ -286,6 +288,7 @@ export const CodeEditor = ({ height, isCopyEnabled = false, isDarkTheme = false, + isHighContrast = false, isDownloadEnabled = false, isFullHeight = false, isHeaderPlain = false, @@ -462,6 +465,19 @@ export const CodeEditor = ({ headerMainContent || !!shortcutsPopoverProps.bodyContent; + const theme = useMemo(() => { + if (isDarkTheme && isHighContrast) { + return 'hc-black'; + } + if (isHighContrast) { + return 'hc-light'; + } + if (isDarkTheme) { + return 'pf-v6-theme-dark'; + } + return 'pf-v6-theme-light'; + }, [isDarkTheme, isHighContrast]); + return ( {({ getRootProps, getInputProps, isDragActive, open }) => { @@ -579,7 +595,7 @@ export const CodeEditor = ({ onChange={onModelChange} onMount={editorDidMount} loading={loading} - theme={isDarkTheme ? 'pf-v6-theme-dark' : 'pf-v6-theme-light'} + theme={theme} {...editorProps} beforeMount={editorBeforeMount} /> diff --git a/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx b/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx index d6b7d21fe10..81243121a8a 100644 --- a/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx @@ -2,7 +2,9 @@ import { render, screen, act } from '@testing-library/react'; import { CodeEditor, Language } from '../CodeEditor'; import styles from '@patternfly/react-styles/css/components/CodeEditor/code-editor'; -jest.mock('@monaco-editor/react', () => jest.fn(() =>
)); +jest.mock('@monaco-editor/react', () => + jest.fn((props: any) =>
) +); test('Matches snapshot without props', () => { const { asFragment } = render(); @@ -72,3 +74,23 @@ test(`Renders with shortcuts when shortcutsPopoverButtonText is passed`, () => { }); expect(screen.getByText('shortcuts')).toBeInTheDocument(); }); + +test('Uses pf-v6-theme-light by default', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'pf-v6-theme-light'); +}); + +test('Uses pf-v6-theme-dark when isDarkTheme is true', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'pf-v6-theme-dark'); +}); + +test('Uses hc-light when isHighContrast is true', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'hc-light'); +}); + +test('Uses hc-black when both isHighContrast and isDarkTheme are true', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'hc-black'); +}); diff --git a/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap b/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap index 463c7e4e9f8..fd1515c08ab 100644 --- a/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap +++ b/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap @@ -164,6 +164,7 @@ exports[`Matches snapshot with control buttons enabled 1`] = ` >
@@ -196,6 +197,7 @@ exports[`Matches snapshot without props 1`] = ` >
diff --git a/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorBasic.tsx b/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorBasic.tsx index b31bc694360..7e1646295e3 100644 --- a/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorBasic.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorBasic.tsx @@ -4,6 +4,7 @@ import { Checkbox } from '@patternfly/react-core'; export const CodeEditorBasic: React.FunctionComponent = () => { const [isDarkTheme, setIsDarkTheme] = useState(false); + const [isHighContrast, setIsHighContrast] = useState(false); const [isLineNumbersVisible, setIsLineNumbersVisible] = useState(true); const [isReadOnly, setIsReadOnly] = useState(false); const [isMinimapVisible, setIsMinimapVisible] = useState(false); @@ -11,6 +12,9 @@ export const CodeEditorBasic: React.FunctionComponent = () => { const toggleDarkTheme = (checked) => { setIsDarkTheme(checked); }; + const toggleHighContrast = (checked) => { + setIsHighContrast(checked); + }; const toggleLineNumbers = (checked) => { setIsLineNumbersVisible(checked); @@ -43,6 +47,14 @@ export const CodeEditorBasic: React.FunctionComponent = () => { id="toggle-theme" name="toggle-theme" /> + toggleHighContrast(checked)} + aria-label="high contrast checkbox" + id="toggle-high-contrast" + name="toggle-high-contrast" + /> { /> { + this.setState({ + isHighContrast: checked + }); + }; + toggleLineNumbers = (checked: boolean) => { this.setState({ isLineNumbersVisible: checked @@ -70,7 +78,7 @@ export class CodeEditorDemo extends Component + this.toggleHighContrast(checked)} + aria-label="high contrast checkbox" + id="toggle-high-contrast" + name="toggle-high-contrast" + />