Skip to content

Commit d24769c

Browse files
committed
feat: add font size control to CodeEditorConfigurationModal example
1 parent b1ae7eb commit d24769c

File tree

2 files changed

+121
-61
lines changed

2 files changed

+121
-61
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: 120 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,85 +2,125 @@ 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. */
26-
ouiaId?: string;
27+
/**
28+
* Optional ID of the configuration option. Also used as a prefix for the ids of inner elements and the OUIA id.
29+
* - `${ouiaId}-title` for the element which contains the title
30+
* - `${ouiaId}-description` for the element which contains the description
31+
*/
32+
id?: 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+
id = `ConfigModalItem-${title.replace(/\s+/g, '-').toLowerCase()}`,
45+
slot
3746
}) => (
3847
<Flex
3948
alignItems={{ default: 'alignItemsCenter' }}
4049
justifyContent={{ default: 'justifyContentSpaceBetween' }}
4150
spaceItems={{ default: 'spaceItemsMd' }}
51+
id={id}
4252
>
4353
<FlexItem flex={{ default: 'flex_1' }}>
4454
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
4555
<Icon isInline>{icon}</Icon>
46-
<strong id={`${ouiaId}-title`} className="pf-v6-u-font-weight-bold">
56+
<strong id={`${id}-title`} className="pf-v6-u-font-weight-bold">
4757
{title}
4858
</strong>
4959
</Flex>
5060

51-
<div id={`${ouiaId}-description`}>{description}</div>
61+
<div id={`${id}-description`}>{description}</div>
5262
</FlexItem>
53-
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>
63+
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>{slot}</FlexItem>
64+
</Flex>
65+
);
66+
67+
interface ConfigModalSwitchProps extends Omit<ConfigModalItemProps, 'slot'> {
68+
/** Flag indicating whether the option is enabled or disabled. */
69+
isChecked?: SwitchProps['isChecked'];
70+
/** onChange handler for the switch. */
71+
onChange?: SwitchProps['onChange'];
72+
/** Labels for the enabled and disabled states of the switch. */
73+
labels?: {
74+
enabled: string;
75+
disabled: string;
76+
};
77+
}
78+
79+
const ConfigModalSwitch: React.FunctionComponent<ConfigModalSwitchProps> = ({
80+
icon = <CogIcon />,
81+
description,
82+
title,
83+
id = `ConfigModalSwitch-${title.replace(/\s+/g, '-').toLowerCase()}`,
84+
isChecked = false,
85+
onChange,
86+
labels = { enabled: undefined, disabled: undefined }
87+
}) => (
88+
<ConfigModalItem
89+
icon={icon}
90+
description={description}
91+
title={title}
92+
id={id}
93+
slot={
5494
<Switch
55-
aria-labelledby={`${ouiaId}-title`}
56-
aria-describedby={`${ouiaId}-description`}
57-
ouiaId={`${ouiaId}-switch`}
95+
aria-labelledby={`${id}-title`}
96+
aria-describedby={`${id}-description`}
97+
ouiaId={`${id}-switch`}
5898
isChecked={isChecked}
5999
isReversed
60100
label={isChecked ? labels.enabled : labels.disabled}
61101
onChange={onChange}
62102
/>
63-
</FlexItem>
64-
</Flex>
103+
}
104+
/>
65105
);
66106

67107
interface ConfigModalControlProps {
68-
/** Array of configuration controls to be rendered inside the modal. */
69-
controls: ConfigModalItemProps[];
108+
/** Controls to be rendered inside the configuration modal. */
109+
children: React.ReactNode;
70110
/** Title of the configuration modal. */
71111
title?: string;
72112
/** Description of the configuration modal. */
73113
description?: string;
74-
/** Optional OUIA ID of the configuration modal. Also used as a prefix for the ids of inner elements. */
114+
/** OptionalID of the configuration modal. Also used as a prefix for the ids of inner elements and the OUIA id. */
75115
ouiaId?: string;
76116
}
77117

78118
const ConfigModalControl: React.FunctionComponent<ConfigModalControlProps> = ({
79-
controls,
119+
children,
80120
title = 'Editor settings',
81121
description = 'Settings will be applied immediately',
82122
ouiaId = 'CodeEditorConfigurationModal'
83-
}) => {
123+
}: ConfigModalControlProps) => {
84124
const [isModalOpen, setIsModalOpen] = useState(false);
85125

86126
return (
@@ -96,20 +136,14 @@ const ConfigModalControl: React.FunctionComponent<ConfigModalControlProps> = ({
96136
<ModalHeader title={title} description={description} labelId={`${ouiaId}-title`} />
97137
<ModalBody id={`${ouiaId}-body`}>
98138
<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-
))}
139+
{children}
106140
</Flex>
107141
</ModalBody>
108142
</Modal>
109143
<CodeEditorControl
110144
aria-label={title}
111145
aria-haspopup="dialog"
112-
icon={<CogIcon />}
146+
isSettings
113147
onClick={() => setIsModalOpen(true)}
114148
tooltipProps={{ content: title, ariaLive: 'off' }}
115149
/>
@@ -123,37 +157,61 @@ export const CodeEditorConfigurationModal: React.FunctionComponent = () => {
123157
const [isMinimapVisible, setIsMinimapVisible] = useState(true);
124158
const [isDarkTheme, setIsDarkTheme] = useState(false);
125159
const [isLineNumbersVisible, setIsLineNumbersVisible] = useState(true);
160+
const [fontSize, setFontSize] = useState(14);
126161

127162
const onChange = (code: string) => {
128163
setCode(code);
129164
};
130165

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

159217
return (
@@ -165,6 +223,7 @@ export const CodeEditorConfigurationModal: React.FunctionComponent = () => {
165223
isLineNumbersVisible={isLineNumbersVisible}
166224
isMinimapVisible={isMinimapVisible}
167225
onChange={onChange}
226+
options={{ fontSize }}
168227
/>
169228
);
170229
};

0 commit comments

Comments
 (0)