Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -157,6 +157,8 @@ export interface CodeEditorProps extends Omit<HTMLProps<HTMLDivElement>, '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. */
Expand Down Expand Up @@ -286,6 +288,7 @@ export const CodeEditor = ({
height,
isCopyEnabled = false,
isDarkTheme = false,
isHighContrast = false,
isDownloadEnabled = false,
isFullHeight = false,
isHeaderPlain = false,
Expand Down Expand Up @@ -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 (
<Dropzone multiple={false} onDropAccepted={onDropAccepted} onDropRejected={onDropRejected}>
{({ getRootProps, getInputProps, isDragActive, open }) => {
Expand Down Expand Up @@ -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}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => <div data-testid="mock-editor"></div>));
jest.mock('@monaco-editor/react', () =>
jest.fn((props: any) => <div data-testid="mock-editor" data-theme={props.theme}></div>)
);

test('Matches snapshot without props', () => {
const { asFragment } = render(<CodeEditor code="test" />);
Expand Down Expand Up @@ -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(<CodeEditor code="test" />);
expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'pf-v6-theme-light');
});

test('Uses pf-v6-theme-dark when isDarkTheme is true', () => {
render(<CodeEditor isDarkTheme code="test" />);
expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'pf-v6-theme-dark');
});

test('Uses hc-light when isHighContrast is true', () => {
render(<CodeEditor isHighContrast code="test" />);
expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'hc-light');
});

test('Uses hc-black when both isHighContrast and isDarkTheme are true', () => {
render(<CodeEditor isHighContrast isDarkTheme code="test" />);
expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'hc-black');
});
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ exports[`Matches snapshot with control buttons enabled 1`] = `
>
<div
data-testid="mock-editor"
data-theme="pf-v6-theme-light"
/>
</div>
</div>
Expand Down Expand Up @@ -196,6 +197,7 @@ exports[`Matches snapshot without props 1`] = `
>
<div
data-testid="mock-editor"
data-theme="pf-v6-theme-light"
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ 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);

const toggleDarkTheme = (checked) => {
setIsDarkTheme(checked);
};
const toggleHighContrast = (checked) => {
setIsHighContrast(checked);
};

const toggleLineNumbers = (checked) => {
setIsLineNumbersVisible(checked);
Expand Down Expand Up @@ -43,6 +47,14 @@ export const CodeEditorBasic: React.FunctionComponent = () => {
id="toggle-theme"
name="toggle-theme"
/>
<Checkbox
label="High contrast"
isChecked={isHighContrast}
onChange={(_event, checked) => toggleHighContrast(checked)}
aria-label="high contrast checkbox"
id="toggle-high-contrast"
name="toggle-high-contrast"
/>
<Checkbox
label="Line numbers"
isChecked={isLineNumbersVisible}
Expand All @@ -69,6 +81,7 @@ export const CodeEditorBasic: React.FunctionComponent = () => {
/>
<CodeEditor
isDarkTheme={isDarkTheme}
isHighContrast={isHighContrast}
isLineNumbersVisible={isLineNumbersVisible}
isReadOnly={isReadOnly}
isMinimapVisible={isMinimapVisible}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import PlayIcon from '@patternfly/react-icons/dist/esm/icons/play-icon';

interface CodeEditorDemoState {
isDarkTheme: boolean;
isHighContrast: boolean;
isLineNumbersVisible: boolean;
isReadOnly: boolean;
isMinimapVisible: boolean;
Expand All @@ -17,6 +18,7 @@ export class CodeEditorDemo extends Component<CodeEditorProps, CodeEditorDemoSta
super(props);
this.state = {
isDarkTheme: false,
isHighContrast: false,
isLineNumbersVisible: true,
isReadOnly: false,
isMinimapVisible: true,
Expand All @@ -30,6 +32,12 @@ export class CodeEditorDemo extends Component<CodeEditorProps, CodeEditorDemoSta
});
};

toggleHighContrast = (checked: boolean) => {
this.setState({
isHighContrast: checked
});
};

toggleLineNumbers = (checked: boolean) => {
this.setState({
isLineNumbersVisible: checked
Expand Down Expand Up @@ -70,7 +78,7 @@ export class CodeEditorDemo extends Component<CodeEditorProps, CodeEditorDemoSta
};

render() {
const { isDarkTheme, isLineNumbersVisible, isReadOnly, isMinimapVisible, code } = this.state;
const { isDarkTheme, isHighContrast, isLineNumbersVisible, isReadOnly, isMinimapVisible, code } = this.state;

const customControl = (
<CodeEditorControl
Expand All @@ -91,6 +99,14 @@ export class CodeEditorDemo extends Component<CodeEditorProps, CodeEditorDemoSta
id="toggle-theme"
name="toggle-theme"
/>
<Checkbox
label="High contrast"
isChecked={isHighContrast}
onChange={(_event, checked) => this.toggleHighContrast(checked)}
aria-label="high contrast checkbox"
id="toggle-high-contrast"
name="toggle-high-contrast"
/>
<Checkbox
label="Line numbers"
isChecked={isLineNumbersVisible}
Expand Down Expand Up @@ -120,6 +136,7 @@ export class CodeEditorDemo extends Component<CodeEditorProps, CodeEditorDemoSta
</Button>
<CodeEditor
isDarkTheme={isDarkTheme}
isHighContrast={isHighContrast}
isLineNumbersVisible={isLineNumbersVisible}
isReadOnly={isReadOnly}
isMinimapVisible={isMinimapVisible}
Expand Down
Loading