Skip to content

Commit 0cdf0e5

Browse files
authored
docs(CodeEditor): add configuration example from OCP (#12026)
1 parent 286de49 commit 0cdf0e5

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

packages/react-code-editor/src/components/CodeEditor/examples/CodeEditor.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Note: Code editor lives in its own package at [@patternfly/react-code-editor](ht
99

1010
import { Fragment, useState } from 'react';
1111
import { CodeEditor, CodeEditorControl, Language } from '@patternfly/react-code-editor';
12+
import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon';
13+
import HashtagIcon from '@patternfly/react-icons/dist/esm/icons/hashtag-icon';
14+
import MapIcon from '@patternfly/react-icons/dist/esm/icons/map-icon';
15+
import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon';
1216
import PlayIcon from '@patternfly/react-icons/dist/esm/icons/play-icon';
1317

1418
## Examples
@@ -50,3 +54,9 @@ These examples below are the shortcuts that we recommend describing in the popov
5054
```ts file="CodeEditorCustomControl.tsx"
5155

5256
```
57+
58+
### With configuration modal
59+
60+
```ts file="CodeEditorConfigurationModal.tsx"
61+
62+
```
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon';
2+
import MapIcon from '@patternfly/react-icons/dist/esm/icons/map-icon';
3+
import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon';
4+
import HashtagIcon from '@patternfly/react-icons/dist/esm/icons/hashtag-icon';
5+
import { CodeEditor, CodeEditorControl } from '@patternfly/react-code-editor';
6+
import { Flex, FlexItem, Icon, Modal, ModalBody, ModalHeader, Switch, SwitchProps } from '@patternfly/react-core';
7+
import { useState } from 'react';
8+
9+
interface ConfigModalItemProps {
10+
/** Icon rendered inside the configuration modal. */
11+
icon?: React.ReactNode;
12+
/** Description of the configuration option. */
13+
description: string;
14+
/** Flag indicating whether the option is enabled or disabled. */
15+
isChecked?: SwitchProps['isChecked'];
16+
/** onChange handler for the switch. */
17+
onChange?: SwitchProps['onChange'];
18+
/** Title of the configuration option. We assume that titles are unique. */
19+
title: string;
20+
/** Labels for the enabled and disabled states of the switch. */
21+
labels?: {
22+
enabled: string;
23+
disabled: string;
24+
};
25+
/** Optional OUIA ID of the configuration option. Also used as a prefix for the ids of inner elements. */
26+
ouiaId?: string;
27+
}
28+
29+
const ConfigModalItem: React.FunctionComponent<ConfigModalItemProps> = ({
30+
icon = <CogIcon />,
31+
description,
32+
isChecked = false,
33+
labels = { enabled: undefined, disabled: undefined },
34+
onChange,
35+
title,
36+
ouiaId
37+
}) => (
38+
<Flex
39+
alignItems={{ default: 'alignItemsCenter' }}
40+
justifyContent={{ default: 'justifyContentSpaceBetween' }}
41+
spaceItems={{ default: 'spaceItemsMd' }}
42+
>
43+
<FlexItem flex={{ default: 'flex_1' }}>
44+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
45+
<Icon isInline>{icon}</Icon>
46+
<strong id={`${ouiaId}-title`} className="pf-v6-u-font-weight-bold">
47+
{title}
48+
</strong>
49+
</Flex>
50+
51+
<div id={`${ouiaId}-description`}>{description}</div>
52+
</FlexItem>
53+
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>
54+
<Switch
55+
aria-labelledby={`${ouiaId}-title`}
56+
aria-describedby={`${ouiaId}-description`}
57+
ouiaId={`${ouiaId}-switch`}
58+
isChecked={isChecked}
59+
isReversed
60+
label={isChecked ? labels.enabled : labels.disabled}
61+
onChange={onChange}
62+
/>
63+
</FlexItem>
64+
</Flex>
65+
);
66+
67+
interface ConfigModalControlProps {
68+
/** Array of configuration controls to be rendered inside the modal. */
69+
controls: ConfigModalItemProps[];
70+
/** Title of the configuration modal. */
71+
title?: string;
72+
/** Description of the configuration modal. */
73+
description?: string;
74+
/** Optional OUIA ID of the configuration modal. Also used as a prefix for the ids of inner elements. */
75+
ouiaId?: string;
76+
}
77+
78+
const ConfigModalControl: React.FunctionComponent<ConfigModalControlProps> = ({
79+
controls,
80+
title = 'Editor settings',
81+
description = 'Settings will be applied immediately',
82+
ouiaId = 'CodeEditorConfigurationModal'
83+
}) => {
84+
const [isModalOpen, setIsModalOpen] = useState(false);
85+
86+
return (
87+
<>
88+
<Modal
89+
aria-describedby={`${ouiaId}-body`}
90+
aria-labelledby={`${ouiaId}-title`}
91+
isOpen={isModalOpen}
92+
onClose={() => setIsModalOpen(!isModalOpen)}
93+
ouiaId={ouiaId}
94+
variant="small"
95+
>
96+
<ModalHeader title={title} description={description} labelId={`${ouiaId}-title`} />
97+
<ModalBody id={`${ouiaId}-body`}>
98+
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsMd' }}>
99+
{controls.map((control) => (
100+
<ConfigModalItem
101+
key={control.title}
102+
ouiaId={`${ouiaId}-${control.title.replace(/\s+/g, '-').toLowerCase()}`}
103+
{...control}
104+
/>
105+
))}
106+
</Flex>
107+
</ModalBody>
108+
</Modal>
109+
<CodeEditorControl
110+
aria-label={title}
111+
aria-haspopup="dialog"
112+
icon={<CogIcon />}
113+
onClick={() => setIsModalOpen(true)}
114+
tooltipProps={{ content: title, ariaLive: 'off' }}
115+
/>
116+
</>
117+
);
118+
};
119+
120+
export const CodeEditorConfigurationModal: React.FunctionComponent = () => {
121+
const [code, setCode] = useState('Some example content');
122+
123+
const [isMinimapVisible, setIsMinimapVisible] = useState(true);
124+
const [isDarkTheme, setIsDarkTheme] = useState(false);
125+
const [isLineNumbersVisible, setIsLineNumbersVisible] = useState(true);
126+
127+
const onChange = (code: string) => {
128+
setCode(code);
129+
};
130+
131+
const customControl = (
132+
<ConfigModalControl
133+
controls={[
134+
{
135+
title: 'Minimap',
136+
description: 'Show a preview of the full code on the side of the editor',
137+
isChecked: isMinimapVisible,
138+
onChange: (_e, checked) => setIsMinimapVisible(checked),
139+
icon: <MapIcon />
140+
},
141+
{
142+
title: 'Dark theme',
143+
description: 'Switch the editor to a dark color theme',
144+
isChecked: isDarkTheme,
145+
onChange: (_e, checked) => setIsDarkTheme(checked),
146+
icon: <MoonIcon />
147+
},
148+
{
149+
title: 'Line numbers',
150+
description: 'Show line numbers to the left of each line of code',
151+
isChecked: isLineNumbersVisible,
152+
onChange: (_e, checked) => setIsLineNumbersVisible(checked),
153+
icon: <HashtagIcon />
154+
}
155+
]}
156+
/>
157+
);
158+
159+
return (
160+
<CodeEditor
161+
code={code}
162+
customControls={customControl}
163+
height="400px"
164+
isDarkTheme={isDarkTheme}
165+
isLineNumbersVisible={isLineNumbersVisible}
166+
isMinimapVisible={isMinimapVisible}
167+
onChange={onChange}
168+
/>
169+
);
170+
};

0 commit comments

Comments
 (0)