diff --git a/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditor.md b/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditor.md index 0c3d3681b5d..7fe074cf68c 100644 --- a/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditor.md +++ b/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditor.md @@ -14,6 +14,7 @@ import HashtagIcon from '@patternfly/react-icons/dist/esm/icons/hashtag-icon'; import MapIcon from '@patternfly/react-icons/dist/esm/icons/map-icon'; import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon'; import PlayIcon from '@patternfly/react-icons/dist/esm/icons/play-icon'; +import FontIcon from '@patternfly/react-icons/dist/esm/icons/font-icon'; ## Examples diff --git a/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorConfigurationModal.tsx b/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorConfigurationModal.tsx index 1f5cc3d7bca..d6c4dcf00c3 100644 --- a/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorConfigurationModal.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/examples/CodeEditorConfigurationModal.tsx @@ -2,8 +2,19 @@ import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon'; import MapIcon from '@patternfly/react-icons/dist/esm/icons/map-icon'; import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon'; import HashtagIcon from '@patternfly/react-icons/dist/esm/icons/hashtag-icon'; +import FontIcon from '@patternfly/react-icons/dist/esm/icons/font-icon'; import { CodeEditor, CodeEditorControl } from '@patternfly/react-code-editor'; -import { Flex, FlexItem, Icon, Modal, ModalBody, ModalHeader, Switch, SwitchProps } from '@patternfly/react-core'; +import { + Flex, + FlexItem, + Icon, + Modal, + ModalBody, + ModalHeader, + NumberInput, + Switch, + SwitchProps +} from '@patternfly/react-core'; import { useState } from 'react'; interface ConfigModalItemProps { @@ -11,76 +22,105 @@ interface ConfigModalItemProps { icon?: React.ReactNode; /** Description of the configuration option. */ description: string; - /** Flag indicating whether the option is enabled or disabled. */ - isChecked?: SwitchProps['isChecked']; - /** onChange handler for the switch. */ - onChange?: SwitchProps['onChange']; /** Title of the configuration option. We assume that titles are unique. */ title: string; - /** Labels for the enabled and disabled states of the switch. */ - labels?: { - enabled: string; - disabled: string; - }; - /** Optional OUIA ID of the configuration option. Also used as a prefix for the ids of inner elements. */ - ouiaId?: string; + /** + * Optional ID of the configuration option. Also used as a prefix for the ids of inner elements and the OUIA id. + * - `${ouiaId}-title` for the element which contains the title + * - `${ouiaId}-description` for the element which contains the description + */ + id?: string; + /** + * Slot to render inside the configuration modal. Remember to add `aria-labelledby` and `aria-describedby` props + * to the control inside the slot, pointing to the title and description ids respectively. + */ + slot?: React.ReactNode; } const ConfigModalItem: React.FunctionComponent = ({ icon = , description, - isChecked = false, - labels = { enabled: undefined, disabled: undefined }, - onChange, title, - ouiaId + id = `ConfigModalItem-${title.replace(/\s+/g, '-').toLowerCase()}`, + slot }) => ( {icon} - + {title} -
{description}
+
{description}
- + {slot} +
+); + +interface ConfigModalSwitchProps extends Omit { + /** Flag indicating whether the option is enabled or disabled. */ + isChecked?: SwitchProps['isChecked']; + /** onChange handler for the switch. */ + onChange?: SwitchProps['onChange']; + /** Labels for the enabled and disabled states of the switch. */ + labels?: { + enabled: string; + disabled: string; + }; +} + +const ConfigModalSwitch: React.FunctionComponent = ({ + icon = , + description, + title, + id = `ConfigModalSwitch-${title.replace(/\s+/g, '-').toLowerCase()}`, + isChecked = false, + onChange, + labels = { enabled: undefined, disabled: undefined } +}) => ( + - - + } + /> ); interface ConfigModalControlProps { - /** Array of configuration controls to be rendered inside the modal. */ - controls: ConfigModalItemProps[]; + /** Controls to be rendered inside the configuration modal. */ + children: React.ReactNode; /** Title of the configuration modal. */ title?: string; /** Description of the configuration modal. */ description?: string; - /** Optional OUIA ID of the configuration modal. Also used as a prefix for the ids of inner elements. */ + /** OptionalID of the configuration modal. Also used as a prefix for the ids of inner elements and the OUIA id. */ ouiaId?: string; } const ConfigModalControl: React.FunctionComponent = ({ - controls, + children, title = 'Editor settings', description = 'Settings will be applied immediately', ouiaId = 'CodeEditorConfigurationModal' -}) => { +}: ConfigModalControlProps) => { const [isModalOpen, setIsModalOpen] = useState(false); return ( @@ -96,20 +136,14 @@ const ConfigModalControl: React.FunctionComponent = ({ - {controls.map((control) => ( - - ))} + {children} } + isSettings onClick={() => setIsModalOpen(true)} tooltipProps={{ content: title, ariaLive: 'off' }} /> @@ -123,37 +157,62 @@ export const CodeEditorConfigurationModal: React.FunctionComponent = () => { const [isMinimapVisible, setIsMinimapVisible] = useState(true); const [isDarkTheme, setIsDarkTheme] = useState(false); const [isLineNumbersVisible, setIsLineNumbersVisible] = useState(true); + const [fontSize, setFontSize] = useState(14); const onChange = (code: string) => { setCode(code); }; const customControl = ( - setIsMinimapVisible(checked), - icon: - }, - { - title: 'Dark theme', - description: 'Switch the editor to a dark color theme', - isChecked: isDarkTheme, - onChange: (_e, checked) => setIsDarkTheme(checked), - icon: - }, - { - title: 'Line numbers', - description: 'Show line numbers to the left of each line of code', - isChecked: isLineNumbersVisible, - onChange: (_e, checked) => setIsLineNumbersVisible(checked), - icon: + + setIsMinimapVisible(checked)} + icon={} + /> + setIsDarkTheme(checked)} + icon={} + /> + setIsLineNumbersVisible(checked)} + icon={} + /> + } + slot={ + setFontSize((size) => Math.max(5, size - 1))} + onChange={(event) => setFontSize(Number((event.target as HTMLInputElement).value))} + onPlus={() => setFontSize((size) => size + 1)} + widthChars={2} + /> } - ]} - /> + /> + ); return ( @@ -165,6 +224,7 @@ export const CodeEditorConfigurationModal: React.FunctionComponent = () => { isLineNumbersVisible={isLineNumbersVisible} isMinimapVisible={isMinimapVisible} onChange={onChange} + options={{ fontSize }} /> ); };