Skip to content

Commit 9f6fb56

Browse files
committed
feat: add font size control to CodeEditorConfigurationModal example
1 parent 9127294 commit 9f6fb56

File tree

2 files changed

+109
-53
lines changed

2 files changed

+109
-53
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import HashtagIcon from '@patternfly/react-icons/dist/esm/icons/hashtag-icon';
1414
import MapIcon from '@patternfly/react-icons/dist/esm/icons/map-icon';
1515
import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon';
1616
import PlayIcon from '@patternfly/react-icons/dist/esm/icons/play-icon';
17+
import FontIcon from '@patternfly/react-icons/dist/esm/icons/font-icon';
1718

1819
## Examples
1920

packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorConfigurationModal.tsx

Lines changed: 108 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,47 @@ import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon';
22
import MapIcon from '@patternfly/react-icons/dist/esm/icons/map-icon';
33
import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon';
44
import HashtagIcon from '@patternfly/react-icons/dist/esm/icons/hashtag-icon';
5+
import FontIcon from '@patternfly/react-icons/dist/esm/icons/font-icon';
56
import { CodeEditor, CodeEditorControl } from '@patternfly/react-code-editor';
6-
import { Flex, FlexItem, Icon, Modal, ModalBody, ModalHeader, Switch, SwitchProps } from '@patternfly/react-core';
7+
import {
8+
Flex,
9+
FlexItem,
10+
Icon,
11+
Modal,
12+
ModalBody,
13+
ModalHeader,
14+
NumberInput,
15+
Switch,
16+
SwitchProps
17+
} from '@patternfly/react-core';
718
import { useState } from 'react';
819

920
interface ConfigModalItemProps {
1021
/** Icon rendered inside the configuration modal. */
1122
icon?: React.ReactNode;
1223
/** Description of the configuration option. */
1324
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'];
1825
/** Title of the configuration option. We assume that titles are unique. */
1926
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. */
27+
/**
28+
* Optional OUIA ID of the configuration option. Also used as a prefix for the ids of inner elements.
29+
* - `${ouiaId}-title` for the element which contains the title
30+
* - `${ouiaId}-description` for the element which contains the description
31+
*/
2632
ouiaId?: string;
33+
/**
34+
* Slot to render inside the configuration modal. Remember to add `aria-labelledby` and `aria-describedby` props
35+
* to the control inside the slot, pointing to the title and description ids respectively.
36+
*/
37+
slot?: React.ReactNode;
2738
}
2839

2940
const ConfigModalItem: React.FunctionComponent<ConfigModalItemProps> = ({
3041
icon = <CogIcon />,
3142
description,
32-
isChecked = false,
33-
labels = { enabled: undefined, disabled: undefined },
34-
onChange,
3543
title,
36-
ouiaId
44+
ouiaId = `ConfigModalItem-${title.replace(/\s+/g, '-').toLowerCase()}`,
45+
slot
3746
}) => (
3847
<Flex
3948
alignItems={{ default: 'alignItemsCenter' }}
@@ -50,7 +59,37 @@ const ConfigModalItem: React.FunctionComponent<ConfigModalItemProps> = ({
5059

5160
<div id={`${ouiaId}-description`}>{description}</div>
5261
</FlexItem>
53-
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>
62+
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>{slot}</FlexItem>
63+
</Flex>
64+
);
65+
66+
interface ConfigModalSwitchProps extends Omit<ConfigModalItemProps, 'slot'> {
67+
/** Flag indicating whether the option is enabled or disabled. */
68+
isChecked?: SwitchProps['isChecked'];
69+
/** onChange handler for the switch. */
70+
onChange?: SwitchProps['onChange'];
71+
/** Labels for the enabled and disabled states of the switch. */
72+
labels?: {
73+
enabled: string;
74+
disabled: string;
75+
};
76+
}
77+
78+
const ConfigModalSwitch: React.FunctionComponent<ConfigModalSwitchProps> = ({
79+
icon = <CogIcon />,
80+
description,
81+
title,
82+
ouiaId = `ConfigModalSwitch-${title.replace(/\s+/g, '-').toLowerCase()}`,
83+
isChecked = false,
84+
onChange,
85+
labels = { enabled: undefined, disabled: undefined }
86+
}) => (
87+
<ConfigModalItem
88+
icon={icon}
89+
description={description}
90+
title={title}
91+
ouiaId={ouiaId}
92+
slot={
5493
<Switch
5594
aria-labelledby={`${ouiaId}-title`}
5695
aria-describedby={`${ouiaId}-description`}
@@ -60,13 +99,13 @@ const ConfigModalItem: React.FunctionComponent<ConfigModalItemProps> = ({
6099
label={isChecked ? labels.enabled : labels.disabled}
61100
onChange={onChange}
62101
/>
63-
</FlexItem>
64-
</Flex>
102+
}
103+
/>
65104
);
66105

67106
interface ConfigModalControlProps {
68-
/** Array of configuration controls to be rendered inside the modal. */
69-
controls: ConfigModalItemProps[];
107+
/** Controls to be rendered inside the configuration modal. */
108+
children: React.ReactNode;
70109
/** Title of the configuration modal. */
71110
title?: string;
72111
/** Description of the configuration modal. */
@@ -76,11 +115,11 @@ interface ConfigModalControlProps {
76115
}
77116

78117
const ConfigModalControl: React.FunctionComponent<ConfigModalControlProps> = ({
79-
controls,
118+
children,
80119
title = 'Editor settings',
81120
description = 'Settings will be applied immediately',
82121
ouiaId = 'CodeEditorConfigurationModal'
83-
}) => {
122+
}: ConfigModalControlProps) => {
84123
const [isModalOpen, setIsModalOpen] = useState(false);
85124

86125
return (
@@ -96,13 +135,7 @@ const ConfigModalControl: React.FunctionComponent<ConfigModalControlProps> = ({
96135
<ModalHeader title={title} description={description} labelId={`${ouiaId}-title`} />
97136
<ModalBody id={`${ouiaId}-body`}>
98137
<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-
))}
138+
{children}
106139
</Flex>
107140
</ModalBody>
108141
</Modal>
@@ -123,37 +156,58 @@ export const CodeEditorConfigurationModal: React.FunctionComponent = () => {
123156
const [isMinimapVisible, setIsMinimapVisible] = useState(true);
124157
const [isDarkTheme, setIsDarkTheme] = useState(false);
125158
const [isLineNumbersVisible, setIsLineNumbersVisible] = useState(true);
159+
const [fontSize, setFontSize] = useState(14);
126160

127161
const onChange = (code: string) => {
128162
setCode(code);
129163
};
130164

131165
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 />
166+
<ConfigModalControl>
167+
<ConfigModalSwitch
168+
key="minimap-switch"
169+
title="Minimap"
170+
description="Show a preview of the full code on the side of the editor"
171+
isChecked={isMinimapVisible}
172+
onChange={(_e, checked) => setIsMinimapVisible(checked)}
173+
icon={<MapIcon />}
174+
/>
175+
<ConfigModalSwitch
176+
key="dark-theme-switch"
177+
title="Dark theme"
178+
description="Switch the editor to a dark color theme"
179+
isChecked={isDarkTheme}
180+
onChange={(_e, checked) => setIsDarkTheme(checked)}
181+
icon={<MoonIcon />}
182+
/>
183+
<ConfigModalSwitch
184+
key="line-numbers-switch"
185+
title="Line numbers"
186+
description="Show line numbers to the left of each line of code"
187+
isChecked={isLineNumbersVisible}
188+
onChange={(_e, checked) => setIsLineNumbersVisible(checked)}
189+
icon={<HashtagIcon />}
190+
/>
191+
<ConfigModalItem
192+
key="font-size"
193+
title="Font size"
194+
description="Adjust the font size of the code editor"
195+
ouia-id="font-size"
196+
icon={<FontIcon />}
197+
slot={
198+
<NumberInput
199+
aria-labelledby="font-size-title"
200+
aria-describedby="font-size-description"
201+
value={fontSize}
202+
min={5}
203+
onMinus={() => setFontSize((size) => Math.max(5, size - 1))}
204+
onChange={(event) => setFontSize(Number((event.target as HTMLInputElement).value))}
205+
onPlus={() => setFontSize((size) => size + 1)}
206+
widthChars={2}
207+
/>
154208
}
155-
]}
156-
/>
209+
/>
210+
</ConfigModalControl>
157211
);
158212

159213
return (
@@ -165,6 +219,7 @@ export const CodeEditorConfigurationModal: React.FunctionComponent = () => {
165219
isLineNumbersVisible={isLineNumbersVisible}
166220
isMinimapVisible={isMinimapVisible}
167221
onChange={onChange}
222+
options={{ fontSize }}
168223
/>
169224
);
170225
};

0 commit comments

Comments
 (0)