diff --git a/packages/react-core/src/components/AboutModal/AboutModal.tsx b/packages/react-core/src/components/AboutModal/AboutModal.tsx index d75aaec82f3..e254f889a04 100644 --- a/packages/react-core/src/components/AboutModal/AboutModal.tsx +++ b/packages/react-core/src/components/AboutModal/AboutModal.tsx @@ -6,7 +6,7 @@ import { AboutModalBoxHeader } from './AboutModalBoxHeader'; import { AboutModalBoxBrand } from './AboutModalBoxBrand'; import { AboutModalBoxCloseButton } from './AboutModalBoxCloseButton'; import { AboutModalBox } from './AboutModalBox'; -import { Modal, ModalVariant } from '../Modal'; +import { Modal, ModalVariant } from '../../deprecated/components/Modal'; import { GenerateId } from '../../helpers/GenerateId/GenerateId'; export interface AboutModalProps extends React.HTMLProps { diff --git a/packages/react-core/src/components/Label/examples/LabelGroupEditableAddModal.tsx b/packages/react-core/src/components/Label/examples/LabelGroupEditableAddModal.tsx index 364b596d25b..afa96fd0259 100644 --- a/packages/react-core/src/components/Label/examples/LabelGroupEditableAddModal.tsx +++ b/packages/react-core/src/components/Label/examples/LabelGroupEditableAddModal.tsx @@ -2,8 +2,6 @@ import React from 'react'; import { LabelGroup, Label, - Modal, - ModalVariant, Button, Form, FormGroup, @@ -16,6 +14,7 @@ import { Radio, Popper } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; export const LabelGroupEditableAddModal: React.FunctionComponent = () => { @@ -255,8 +254,8 @@ export const LabelGroupEditableAddModal: React.FunctionComponent = () => { ))} - { /> - + ); }; diff --git a/packages/react-core/src/components/Modal/Modal.tsx b/packages/react-core/src/components/Modal/Modal.tsx index ba198da5ff7..6e8a9760c91 100644 --- a/packages/react-core/src/components/Modal/Modal.tsx +++ b/packages/react-core/src/components/Modal/Modal.tsx @@ -7,53 +7,29 @@ import { ModalContent } from './ModalContent'; import { OUIAProps, getDefaultOUIAId } from '../../helpers'; export interface ModalProps extends React.HTMLProps, OUIAProps { - /** Action buttons to add to the standard modal footer. Ignored if the footer property - * is passed in. - */ - actions?: any; /** The parent container to append the modal to. Defaults to "document.body". */ appendTo?: HTMLElement | (() => HTMLElement); - /** Id to use for the modal box descriptor. */ + /** Id to use for the modal box description. This should match the ModalHeader labelId or descriptorId. */ 'aria-describedby'?: string; - /** Accessible descriptor of the modal. */ + /** Adds an accessible name to the modal when there is no title in the ModalHeader. */ 'aria-label'?: string; - /** Id to use for the modal box label. */ + /** Id to use for the modal box label. This should include the ModalHeader labelId. */ 'aria-labelledby'?: string; - /** Accessible label applied to the modal box body. This should be used to communicate - * important information about the modal box body div element if needed, such as that it - * is scrollable. - */ - bodyAriaLabel?: string; - /** Accessible role applied to the modal box body. This will default to "region" if the - * bodyAriaLabel property is passed in. Set to a more appropriate role as applicable - * based on the modal content and context. - */ - bodyAriaRole?: string; /** Content rendered inside the modal. */ children: React.ReactNode; /** Additional classes added to the modal. */ className?: string; - /** Description of the modal. */ - description?: React.ReactNode; /** Flag to disable focus trap. */ disableFocusTrap?: boolean; /** The element to focus when the modal opens. By default the first * focusable element will receive focus. */ elementToFocus?: HTMLElement | SVGElement | string; - /** Custom footer. */ - footer?: React.ReactNode; - /** Flag indicating if modal content should be placed in a modal box body wrapper. */ - hasNoBodyWrapper?: boolean; - /** Complex header (more than just text), supersedes the title property for header content. */ - header?: React.ReactNode; - /** Optional help section for the modal header. */ - help?: React.ReactNode; /** An id to use for the modal box container. */ id?: string; /** Flag to show the modal. */ isOpen?: boolean; - /** A callback for when the close button is clicked. */ + /** Add callback for when the close button is clicked. This prop needs to be passed to render the close button */ onClose?: (event: KeyboardEvent | React.MouseEvent) => void; /** Modal handles pressing of the escape key and closes the modal. If you want to handle * this yourself you can use this callback function. */ @@ -62,16 +38,6 @@ export interface ModalProps extends React.HTMLProps, OUIAProps { position?: 'default' | 'top'; /** Offset from alternate position. Can be any valid CSS length/percentage. */ positionOffset?: string; - /** Flag to show the close button in the header area of the modal. */ - showClose?: boolean; - /** Simple text content of the modal header. Also used for the aria-label on the body. */ - title?: string; - /** Optional alert icon (or other) to show before the title of the modal header. When the - * predefined alert types are used the default styling will be automatically applied. - */ - titleIconVariant?: 'success' | 'danger' | 'warning' | 'info' | 'custom' | React.ComponentType; - /** Optional title label text for screen readers. */ - titleLabel?: string; /** Variant of the modal. */ variant?: 'small' | 'medium' | 'large' | 'default'; /** Default width of the modal. */ @@ -100,24 +66,10 @@ class Modal extends React.Component { static displayName = 'Modal'; static currentId = 0; boxId = ''; - labelId = ''; - descriptorId = ''; static defaultProps: PickOptional = { - className: '', isOpen: false, - title: '', - titleIconVariant: null, - titleLabel: '', - 'aria-label': '', - showClose: true, - 'aria-describedby': '', - 'aria-labelledby': '', - id: undefined, - actions: [] as any[], - onClose: () => undefined as any, variant: 'default', - hasNoBodyWrapper: false, appendTo: () => document.body, ouiaSafe: true, position: 'default' @@ -126,11 +78,7 @@ class Modal extends React.Component { constructor(props: ModalProps) { super(props); const boxIdNum = Modal.currentId++; - const labelIdNum = boxIdNum + 1; - const descriptorIdNum = boxIdNum + 2; this.boxId = props.id || `pf-modal-part-${boxIdNum}`; - this.labelId = `pf-modal-part-${labelIdNum}`; - this.descriptorId = `pf-modal-part-${descriptorIdNum}`; this.state = { container: undefined, @@ -168,11 +116,9 @@ class Modal extends React.Component { componentDidMount() { const { appendTo, - title, + 'aria-describedby': ariaDescribedby, 'aria-label': ariaLabel, - 'aria-labelledby': ariaLabelledby, - hasNoBodyWrapper, - header + 'aria-labelledby': ariaLabelledby } = this.props; const target: HTMLElement = this.getElement(appendTo); const container = document.createElement('div'); @@ -186,16 +132,9 @@ class Modal extends React.Component { target.classList.remove(css(styles.backdropOpen)); } - if (this.isEmpty(title) && this.isEmpty(ariaLabel) && this.isEmpty(ariaLabelledby)) { + if (!ariaDescribedby && !ariaLabel && !ariaLabelledby) { // eslint-disable-next-line no-console - console.error('Modal: Specify at least one of: title, aria-label, aria-labelledby.'); - } - - if (this.isEmpty(ariaLabel) && this.isEmpty(ariaLabelledby) && (hasNoBodyWrapper || header)) { - // eslint-disable-next-line no-console - console.error( - 'Modal: When using hasNoBodyWrapper or setting a custom header, ensure you assign an accessible name to the the modal container with aria-label or aria-labelledby.' - ); + console.error('Modal: Specify at least one of: aria-describedby, aria-label, aria-labelledby.'); } } @@ -231,11 +170,6 @@ class Modal extends React.Component { 'aria-labelledby': ariaLabelledby, 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, - bodyAriaLabel, - bodyAriaRole, - title, - titleIconVariant, - titleLabel, ouiaId, ouiaSafe, position, @@ -250,22 +184,15 @@ class Modal extends React.Component { return ReactDOM.createPortal( , container ) as React.ReactElement; diff --git a/packages/react-core/src/next/components/Modal/ModalBody.tsx b/packages/react-core/src/components/Modal/ModalBody.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/ModalBody.tsx rename to packages/react-core/src/components/Modal/ModalBody.tsx diff --git a/packages/react-core/src/components/Modal/ModalBox.tsx b/packages/react-core/src/components/Modal/ModalBox.tsx index 8f9158876d0..b52a9660ece 100644 --- a/packages/react-core/src/components/Modal/ModalBox.tsx +++ b/packages/react-core/src/components/Modal/ModalBox.tsx @@ -4,9 +4,9 @@ import styles from '@patternfly/react-styles/css/components/ModalBox/modal-box'; import topSpacer from '@patternfly/react-tokens/dist/esm/c_modal_box_m_align_top_spacer'; export interface ModalBoxProps extends React.HTMLProps { - /** Id to use for the modal box description. */ - 'aria-describedby': string; - /** Accessible descriptor of the modal. */ + /** Id to use for the modal box description. This should match the ModalHeader labelId or descriptorId */ + 'aria-describedby'?: string; + /** Adds an accessible name to the modal when there is no title in the ModalHeader. */ 'aria-label'?: string; /** Id to use for the modal box label. */ 'aria-labelledby'?: string; @@ -24,12 +24,12 @@ export interface ModalBoxProps extends React.HTMLProps { export const ModalBox: React.FunctionComponent = ({ children, - className = '', + className, variant = 'default', position, positionOffset, 'aria-labelledby': ariaLabelledby, - 'aria-label': ariaLabel = '', + 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, style, ...props @@ -40,7 +40,6 @@ export const ModalBox: React.FunctionComponent = ({ } return (
= ({ variant === 'medium' && styles.modifiers.md )} style={style} + {...props} > {children}
diff --git a/packages/react-core/src/components/Modal/ModalBoxCloseButton.tsx b/packages/react-core/src/components/Modal/ModalBoxCloseButton.tsx index bf0310fd3fa..945281202a2 100644 --- a/packages/react-core/src/components/Modal/ModalBoxCloseButton.tsx +++ b/packages/react-core/src/components/Modal/ModalBoxCloseButton.tsx @@ -18,7 +18,7 @@ export interface ModalBoxCloseButtonProps extends OUIAProps { export const ModalBoxCloseButton: React.FunctionComponent = ({ className, - onClose = () => undefined as any, + onClose, 'aria-label': ariaLabel = 'Close', ouiaId, ...props diff --git a/packages/react-core/src/components/Modal/ModalBoxTitle.tsx b/packages/react-core/src/components/Modal/ModalBoxTitle.tsx index d91bf01773f..6c23e0e599d 100644 --- a/packages/react-core/src/components/Modal/ModalBoxTitle.tsx +++ b/packages/react-core/src/components/Modal/ModalBoxTitle.tsx @@ -17,27 +17,29 @@ export interface ModalBoxTitleProps { /** Additional classes added to the modal box title. */ className?: string; /** Id of the modal box title. */ - id: string; + id?: string; /** Content rendered inside the modal box title. */ title: React.ReactNode; /** Optional alert icon (or other) to show before the title. When the predefined alert types * are used the default styling will be automatically applied. */ titleIconVariant?: 'success' | 'danger' | 'warning' | 'info' | 'custom' | React.ComponentType; /** Optional title label text for screen readers. */ - titleLabel?: string; + titleScreenReaderText?: string; } export const ModalBoxTitle: React.FunctionComponent = ({ - className = '', + className, id, title, titleIconVariant, - titleLabel = '', + titleScreenReaderText, ...props }: ModalBoxTitleProps) => { const [hasTooltip, setHasTooltip] = React.useState(false); const h1 = React.useRef(null); - const label = titleLabel || (isVariantIcon(titleIconVariant) ? `${capitalize(titleIconVariant)} alert:` : titleLabel); + const label = + titleScreenReaderText || + (isVariantIcon(titleIconVariant) ? `${capitalize(titleIconVariant)} alert:` : titleScreenReaderText); const variantIcons = { success: , danger: , diff --git a/packages/react-core/src/components/Modal/ModalContent.tsx b/packages/react-core/src/components/Modal/ModalContent.tsx index b58b1608f70..0f75bd6ebcf 100644 --- a/packages/react-core/src/components/Modal/ModalContent.tsx +++ b/packages/react-core/src/components/Modal/ModalContent.tsx @@ -1,84 +1,39 @@ import * as React from 'react'; import { FocusTrap } from '../../helpers'; -import modalStyles from '@patternfly/react-styles/css/components/ModalBox/modal-box'; import bullsEyeStyles from '@patternfly/react-styles/css/layouts/Bullseye/bullseye'; import { css } from '@patternfly/react-styles'; import { getOUIAProps, OUIAProps } from '../../helpers'; - -import { Backdrop } from '../Backdrop/Backdrop'; -import { ModalBoxBody } from './ModalBoxBody'; +import { Backdrop } from '../Backdrop'; import { ModalBoxCloseButton } from './ModalBoxCloseButton'; import { ModalBox } from './ModalBox'; -import { ModalBoxFooter } from './ModalBoxFooter'; -import { ModalBoxDescription } from './ModalBoxDescription'; -import { ModalBoxHeader } from './ModalBoxHeader'; -import { ModalBoxTitle, isVariantIcon } from './ModalBoxTitle'; export interface ModalContentProps extends OUIAProps { - /** Action buttons to add to the standard modal footer. Ignored if the footer property - * is passed in. - */ - actions?: any; - /** Id to use for the modal box descriptor. */ + /** Id to use for the modal box description. This should match the ModalHeader labelId or descriptorId. */ 'aria-describedby'?: string; /** Accessible descriptor of the modal. */ 'aria-label'?: string; - /** Id to use for the modal box label. */ - 'aria-labelledby'?: string | null; - /** Accessible label applied to the modal box body. This should be used to communicate - * important information about the modal box body div element if needed, such as that it - * is scrollable. - */ - bodyAriaLabel?: string; - /** Accessible role applied to the modal box body. This will default to "region" if the - * bodyAriaLabel property is passed in. Set to a more appropriate role as applicable - * based on the modal content and context. - */ - bodyAriaRole?: string; + /** Id to use for the modal box label. This should include the ModalHeader labelId. */ + 'aria-labelledby'?: string; /** Id of the modal box container. */ boxId: string; /** Content rendered inside the modal. */ children: React.ReactNode; /** Additional classes added to the modal box. */ className?: string; - /** Description of the modal. */ - description?: React.ReactNode; - /** Id of the modal box description. */ - descriptorId: string; /** Flag to disable focus trap. */ disableFocusTrap?: boolean; /** The element to focus when the modal opens. By default the first * focusable element will receive focus. */ elementToFocus?: HTMLElement | SVGElement | string; - /** Custom footer. */ - footer?: React.ReactNode; - /** Flag indicating if modal content should be placed in a modal box body wrapper. */ - hasNoBodyWrapper?: boolean; - /** Complex header (more than just text), supersedes the title property for header content. */ - header?: React.ReactNode; - /** Optional help section for the modal header. */ - help?: React.ReactNode; /** Flag to show the modal. */ isOpen?: boolean; - /** Id of the modal box title. */ - labelId: string; /** A callback for when the close button is clicked. */ onClose?: (event: KeyboardEvent | React.MouseEvent) => void; /** Position of the modal. By default a modal will be positioned vertically and horizontally centered. */ position?: 'default' | 'top'; /** Offset from alternate position. Can be any valid CSS length/percentage. */ positionOffset?: string; - /** Flag to show the close button in the header area of the modal. */ - showClose?: boolean; - /** Simple text content of the modal header. Also used for the aria-label on the body. */ - title?: string; - /** Optional alert icon (or other) to show before the title of the modal header. When the - * predefined alert types are used the default styling will be automatically applied. - */ - titleIconVariant?: 'success' | 'danger' | 'warning' | 'info' | 'custom' | React.ComponentType; - /** Optional title label text for screen readers. */ - titleLabel?: string; /** Variant of the modal. */ variant?: 'small' | 'medium' | 'large' | 'default'; /** Default width of the modal. */ @@ -93,33 +48,19 @@ export interface ModalContentProps extends OUIAProps { export const ModalContent: React.FunctionComponent = ({ children, - className = '', + className, isOpen = false, - header = null, - help = null, - description = null, - title = '', - titleIconVariant = null, - titleLabel = '', - 'aria-label': ariaLabel = '', + 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby, - bodyAriaLabel, - bodyAriaRole, - showClose = true, - footer = null, - actions = [], - onClose = () => undefined as any, + onClose, variant = 'default', position, positionOffset, width, maxWidth, boxId, - labelId, - descriptorId, disableFocusTrap = false, - hasNoBodyWrapper = false, ouiaId, ouiaSafe = true, elementToFocus, @@ -129,62 +70,30 @@ export const ModalContent: React.FunctionComponent = ({ return null; } - const modalBoxHeader = header ? ( - {header} - ) : ( - title && ( - - - {description && {description}} - - ) - ); - - const modalBoxFooter = footer ? ( - {footer} - ) : ( - actions.length > 0 && {actions} - ); - - const defaultModalBodyAriaRole = bodyAriaLabel ? 'region' : undefined; - - const hasNoDescription = !description && !ariaDescribedby; - const id = hasNoDescription ? descriptorId : undefined; - - const modalBody = hasNoBodyWrapper ? ( - children - ) : ( - - {children} - - ); - const ariaLabelledbyFormatted = (): null | string => { - if (ariaLabelledby === null) { - return null; - } + const ariaLabelledbyFormatted = (): string => { const idRefList: string[] = []; - if ((ariaLabel && boxId) !== '') { + if (ariaLabel && boxId) { idRefList.push(ariaLabel && boxId); } if (ariaLabelledby) { idRefList.push(ariaLabelledby); } - if (title) { - idRefList.push(labelId); + if (idRefList.length === 0) { + return undefined; + } else { + return idRefList.join(' '); } - return idRefList.join(' '); }; const modalBox = ( = ({ }) } as React.CSSProperties } + {...props} + id={boxId} > - {showClose && onClose(event)} ouiaId={ouiaId} />} - {modalBoxHeader} - {modalBody} - {modalBoxFooter} + {onClose && onClose(event)} ouiaId={ouiaId} />} + {children} ); return ( diff --git a/packages/react-core/src/next/components/Modal/ModalFooter.tsx b/packages/react-core/src/components/Modal/ModalFooter.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/ModalFooter.tsx rename to packages/react-core/src/components/Modal/ModalFooter.tsx diff --git a/packages/react-core/src/next/components/Modal/ModalHeader.tsx b/packages/react-core/src/components/Modal/ModalHeader.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/ModalHeader.tsx rename to packages/react-core/src/components/Modal/ModalHeader.tsx diff --git a/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx b/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx index d55aa48925a..ab76e90d819 100644 --- a/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx +++ b/packages/react-core/src/components/Modal/__tests__/Modal.test.tsx @@ -7,13 +7,12 @@ import { css } from '../../../../../react-styles/dist/js'; import styles from '@patternfly/react-styles/css/components/Backdrop/backdrop'; import { Modal } from '../Modal'; -import { KeyTypes } from '../../../helpers'; +import { KeyTypes } from '../../../../helpers'; jest.spyOn(document, 'createElement'); jest.spyOn(document.body, 'addEventListener'); const props = { - title: 'Modal', onClose: jest.fn(), isOpen: false, children: 'modal content' @@ -48,9 +47,9 @@ describe('Modal', () => { test('modal closes with escape', async () => { const user = userEvent.setup(); - render(); + render(); - await user.type(screen.getByText(props.title), `{${KeyTypes.Escape}}`); + await user.type(screen.getByLabelText('modal-div'), `{${KeyTypes.Escape}}`); expect(props.onClose).toHaveBeenCalled(); }); @@ -70,13 +69,17 @@ describe('Modal', () => { expect(document.body).not.toHaveClass(css(styles.backdropOpen)); }); - test('modal shows the close button when showClose is true (true by default)', () => { + test('modal shows the close button when onClose prop is passed (true by default)', () => { render(); expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument(); }); - test('modal does not show the close button when showClose is false', () => { - render(); + test('modal does not show the close button when onClose not passed', () => { + render( + + No close button{' '} + + ); expect(screen.queryByRole('button', { name: 'Close' })).toBeNull(); }); @@ -94,21 +97,6 @@ describe('Modal', () => { expect(consoleErrorMock).toHaveBeenCalled(); }); - test('modal generates console warning when conflicting accessible name strategies are provided', () => { - const props = { - hasNoBodyWrapper: true, - onClose: jest.fn(), - isOpen: true, - children: 'modal content' - }; - const consoleErrorMock = jest.fn(); - global.console = { error: consoleErrorMock } as any; - - render(); - - expect(consoleErrorMock).toHaveBeenCalled(); - }); - test('modal adds aria-hidden attribute to its siblings when open', () => { render(, { container: document.body.appendChild(target) }); @@ -154,59 +142,4 @@ describe('Modal', () => { expect(asideSibling).not.toHaveAttribute('aria-hidden'); expect(articleSibling).not.toHaveAttribute('aria-hidden'); }); - test('The modalBoxBody has no aria-label when bodyAriaLabel is not passed', () => { - const props = { - isOpen: true - }; - - render(This is a ModalBox); - - const modalBoxBody = screen.getByText('This is a ModalBox'); - expect(modalBoxBody).not.toHaveAccessibleName('modal box body aria label'); - }); - - test('The modalBoxBody has the expected aria-label when bodyAriaLabel is passed', () => { - const props = { - isOpen: true - }; - - render( - - This is a ModalBox - - ); - - const modalBoxBody = screen.getByText('This is a ModalBox'); - expect(modalBoxBody).toHaveAccessibleName('modal box body aria label'); - }); - - test('The modalBoxBody has the expected aria role when bodyAriaLabel is passed and bodyAriaRole is not', () => { - const props = { - isOpen: true - }; - - render( - - This is a ModalBox - - ); - - const modalBoxBody = screen.getByRole('region', { name: 'modal box body aria label' }); - expect(modalBoxBody).toBeInTheDocument(); - }); - - test('The modalBoxBody has the expected aria role when bodyAriaRole is passed', () => { - const props = { - isOpen: true - }; - - render( - - This is a ModalBox - - ); - - const modalBoxBody = screen.getByRole('article', { name: 'modal box body aria label' }); - expect(modalBoxBody).toBeInTheDocument(); - }); }); diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalBody.test.tsx b/packages/react-core/src/components/Modal/__tests__/ModalBody.test.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/ModalBody.test.tsx rename to packages/react-core/src/components/Modal/__tests__/ModalBody.test.tsx diff --git a/packages/react-core/src/components/Modal/__tests__/ModalBoxHeader.test.tsx b/packages/react-core/src/components/Modal/__tests__/ModalBoxHeader.test.tsx index 943230d05cb..5c724c9c1c3 100644 --- a/packages/react-core/src/components/Modal/__tests__/ModalBoxHeader.test.tsx +++ b/packages/react-core/src/components/Modal/__tests__/ModalBoxHeader.test.tsx @@ -1,14 +1,21 @@ import * as React from 'react'; import { render } from '@testing-library/react'; -import { ModalBoxHeader } from '../ModalBoxHeader'; +import { ModalHeader } from '../ModalHeader'; -test('ModalBoxHeader Test', () => { - const { asFragment } = render(This is a ModalBox header); +test('ModalHeader Test', () => { + const { asFragment } = render(This is a ModalBox header); expect(asFragment()).toMatchSnapshot(); }); -test('ModalBoxHeader help renders', () => { - const { asFragment } = render(test}>This is a ModalBox header); +test('ModalHeader help renders', () => { + const { asFragment } = render(test}>This is a ModalBox header); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Test with custom header', () => { + const header = TEST; + + const { asFragment } = render({header}); expect(asFragment()).toMatchSnapshot(); }); diff --git a/packages/react-core/src/components/Modal/__tests__/ModalBoxTitle.test.tsx b/packages/react-core/src/components/Modal/__tests__/ModalBoxTitle.test.tsx index 84e7c3f1e20..269d784695d 100644 --- a/packages/react-core/src/components/Modal/__tests__/ModalBoxTitle.test.tsx +++ b/packages/react-core/src/components/Modal/__tests__/ModalBoxTitle.test.tsx @@ -5,55 +5,33 @@ import { ModalBoxTitle } from '../ModalBoxTitle'; import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; test('ModalBoxTitle alert variant', () => { - const { asFragment } = render( - - content - - ); + const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle info variant', () => { - const { asFragment } = render( - - content - - ); + const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle danger variant', () => { - const { asFragment } = render( - - content - - ); + const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle custom variant', () => { - const { asFragment } = render( - - content - - ); + const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle success variant', () => { - const { asFragment } = render( - - content - - ); + const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle custom icon variant', () => { const { asFragment } = render( - - content - + ); expect(asFragment()).toMatchSnapshot(); }); diff --git a/packages/react-core/src/components/Modal/__tests__/ModalContent.test.tsx b/packages/react-core/src/components/Modal/__tests__/ModalContent.test.tsx index c7d4b0fac95..a3419ee83e0 100644 --- a/packages/react-core/src/components/Modal/__tests__/ModalContent.test.tsx +++ b/packages/react-core/src/components/Modal/__tests__/ModalContent.test.tsx @@ -6,11 +6,12 @@ import { ModalContent } from '../ModalContent'; const modalContentProps = { boxId: 'boxId', labelId: 'labelId', - descriptorId: 'descriptorId' + descriptorId: 'descriptorId', + disableFocusTrap: true }; test('Modal Content Test only body', () => { const { asFragment } = render( - + This is a ModalBox header ); @@ -19,7 +20,7 @@ test('Modal Content Test only body', () => { test('Modal Content Test isOpen', () => { const { asFragment } = render( - + This is a ModalBox header ); @@ -28,30 +29,7 @@ test('Modal Content Test isOpen', () => { test('Modal Content Test description', () => { const { asFragment } = render( - - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Content Test with footer', () => { - const { asFragment } = render( - - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Content test without footer', () => { - const { asFragment } = render( - + This is a ModalBox header ); @@ -60,51 +38,7 @@ test('Modal Content test without footer', () => { test('Modal Content Test with onclose', () => { const { asFragment } = render( - undefined} - isOpen - {...modalContentProps} - > - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Test with custom header', () => { - const header = TEST; - - const { asFragment } = render( - undefined} - isOpen - {...modalContentProps} - > - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Test with custom footer', () => { - const footer = TEST; - - const { asFragment } = render( - undefined} - isOpen - {...modalContentProps} - > + undefined} isOpen {...modalContentProps}> This is a ModalBox header ); diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalFooter.test.tsx b/packages/react-core/src/components/Modal/__tests__/ModalFooter.test.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/ModalFooter.test.tsx rename to packages/react-core/src/components/Modal/__tests__/ModalFooter.test.tsx diff --git a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBody.test.tsx.snap b/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBody.test.tsx.snap similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBody.test.tsx.snap rename to packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBody.test.tsx.snap diff --git a/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap b/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap index 3ad4ea4de22..ff53d0efef5 100644 --- a/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap +++ b/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap @@ -1,6 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ModalBoxHeader Test 1`] = ` +exports[`Modal Test with custom header 1`] = ` + +
+ + TEST + +
+
+`; + +exports[`ModalHeader Test 1`] = `
`; -exports[`ModalBoxHeader help renders 1`] = ` +exports[`ModalHeader help renders 1`] = `
@@ -85,62 +34,16 @@ exports[`Modal Content Test isOpen 1`] = ` class="pf-v6-l-bullseye" > @@ -156,138 +59,16 @@ exports[`Modal Content Test only body 1`] = ` class="pf-v6-l-bullseye" > - - - -`; - -exports[`Modal Content Test with footer 1`] = ` - -
-
-
@@ -303,13 +84,13 @@ exports[`Modal Content Test with onclose 1`] = ` class="pf-v6-l-bullseye" > - - -
-`; - -exports[`Modal Content test without footer 1`] = ` - -
-
- -
-
-
-`; - -exports[`Modal Test with custom footer 1`] = ` - -
-
- -
-
-
-`; - -exports[`Modal Test with custom header 1`] = ` - -
-
-
diff --git a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalFooter.test.tsx.snap b/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalFooter.test.tsx.snap similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalFooter.test.tsx.snap rename to packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalFooter.test.tsx.snap diff --git a/packages/react-core/src/components/Modal/examples/Modal.md b/packages/react-core/src/components/Modal/examples/Modal.md index 2f135afe708..c5b75813e96 100644 --- a/packages/react-core/src/components/Modal/examples/Modal.md +++ b/packages/react-core/src/components/Modal/examples/Modal.md @@ -2,22 +2,26 @@ id: Modal section: components cssPrefix: pf-v5-c-modal-box -propComponents: ['Modal'] +propComponents: ['Modal', 'ModalBody', 'ModalHeader', 'ModalFooter'] ouia: true +beta: true --- import WarningTriangleIcon from '@patternfly/react-icons/dist/esm/icons/warning-triangle-icon'; import CaretDownIcon from '@patternfly/react-icons/dist/esm/icons/caret-down-icon'; import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; -import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; import formStyles from '@patternfly/react-styles/css/components/Form/form'; ## Examples ### Basic modals -Basic modals give users the option to either confirm or cancel an action. To flag an open modal, use the `isOpen` property. To execute a callback when a modal is closed, use the `onClose` property. +Basic modals give users the option to either confirm or cancel an action. + +To flag an open modal, use the `isOpen` property. To execute a callback when a modal is closed, use the `onClose` property. + +A modal must have a ``, containing the main content of the modal. The `` and `` components are not required, but are typically used to display the modal title and any button actions, respectively. ```ts file="./ModalBasic.tsx" @@ -25,7 +29,7 @@ Basic modals give users the option to either confirm or cancel an action. To fla ### Scrollable modals -To enable keyboard-accessible scrolling of a modal’s content, pass `tabIndex={0}` to the ``. +To enable keyboard-accessible scrolling of a modal’s content, pass `tabIndex={0}` to the ``. ```ts file="ModalWithOverflowingContent.tsx" @@ -47,29 +51,13 @@ To override a modal's default center alignment, use the `position` property. In ``` -### Small modal +### Modal sizes To adjust the size of a modal, use the `variant` property. Modal variants include "small", "medium", "large", and "default". -The following example displays a "small" modal by passing in `variant={ModalVariant.small}`. - -```ts file="./ModalSmall.tsx" - -``` - -### Medium modal - -The following example displays a "medium" modal by passing in `variant={ModalVariant.medium}`. +In the following example, you can display each modal size option. To launch a modal with a specific size, first select the respective radio button, followed by the "Show modal" button. -```ts file="./ModalMedium.tsx" - -``` - -### Large modal - -The following example displays a "large" modal by passing in `variant={ModalVariant.large}`. - -```ts file="./ModalLarge.tsx" +```ts file="./ModalSize.tsx" ``` @@ -81,17 +69,19 @@ To choose a specific width for a modal, use the `width` property. The following ``` -### Custom header and footer +### Custom header -To add a custom header and footer to a modal, set the `header` and `footer` properties to a custom implementation. The following example passes title components into both the header and the footer and also passes an icon to the footer. +To add a custom header to a modal, your custom content must be passed as a child of the `` component. Do not pass the `title` property to `` when using a custom header. -```ts file="./ModalCustomHeaderFooter.tsx" +```ts file="./ModalCustomHeader.tsx" ``` ### No header or footer -To exclusively present information in a modal, remove the `header` and/or `footer`. +To exclusively present information in a modal, remove the header and/or footer. + +When a modal has no header or footer, make sure to add an `aria-label` explicitly stating this, so that those using assistive technologies can understand this context. ```ts file="./ModalNoHeaderFooter.tsx" @@ -99,7 +89,7 @@ To exclusively present information in a modal, remove the `header` and/or `foote ### Title icon -To add an icon before a modal’s title, use the `titleIconVariant`, which can be set to one of the predefined variants -- "success", "danger", "warning", "info", and "custom" -- or to an imported custom icon. The following example uses a "warning" variant. +To add an icon before a modal’s title, use the `titleIconVariant` property, which can be set to a "success", "danger", "warning", or "info" variant. The following example uses a "warning" variant. ```ts file="./ModalTitleIcon.tsx" @@ -123,7 +113,9 @@ To guide users through a series of steps in a modal, you can add a [wizard](/com ### With dropdown -To present a menu of actions or links to a user, you can add a [dropdown](/components/dropdown) to a modal. To allow the dropdown to visually break out of the modal container, set the `menuAppendTo` property to “parent”. Handle the modal’s closing behavior by listening to the `onEscapePress` callback on the `` component. This allows the "escape" key to collapse the dropdown without closing the entire modal. +To present a menu of actions or links to a user, you can add a [dropdown](/components/menus/dropdown) to a modal. + +To allow the dropdown to visually break out of the modal container, set the `menuAppendTo` property to “parent”. Handle the modal’s closing behavior by listening to the `onEscapePress` callback on the `` component. This allows the "escape" key to collapse the dropdown without closing the entire modal. ```ts file="./ModalWithDropdown.tsx" @@ -139,9 +131,9 @@ To help simplify and explain complex models, add a help [popover](/components/po ### With form -To collect user input within a modal, you can add a [form](/components/form). +To collect user input within a modal, you can add a [form](/components/forms/form). -To submit the form from a button in the modal's footer (outside of the `
`), set the button's `form` property equal to the form's id. +To enable form submission from a button in the modal's footer (outside of the ``), set the button's `form` property equal to the form's id. ```ts file="ModalWithForm.tsx" @@ -149,7 +141,7 @@ To submit the form from a button in the modal's footer (outside of the ``) ### Custom focus -Use the `elementToFocus` property to customize which element inside the Modal receives focus when initially opened. +To customize which element inside the modal receives focus when initially opened, use the `elementToFocus` property`. ```ts file="./ModalCustomFocus.tsx" diff --git a/packages/react-core/src/components/Modal/examples/ModalBasic.tsx b/packages/react-core/src/components/Modal/examples/ModalBasic.tsx index ee3b3743740..ddcb9f5c60e 100644 --- a/packages/react-core/src/components/Modal/examples/ModalBasic.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalBasic.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core'; export const ModalBasic: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -14,24 +14,28 @@ export const ModalBasic: React.FunctionComponent = () => { Show basic modal + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + , + - ]} - ouiaId="BasicModal" - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + ); diff --git a/packages/react-core/src/components/Modal/examples/ModalCustomFocus.tsx b/packages/react-core/src/components/Modal/examples/ModalCustomFocus.tsx index eb797f7e167..6c4cc85e49d 100644 --- a/packages/react-core/src/components/Modal/examples/ModalCustomFocus.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalCustomFocus.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core'; export const ModalCustomFocus: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -15,23 +15,27 @@ export const ModalCustomFocus: React.FunctionComponent = () => { - Confirm - , - - ]} + aria-labelledby="custom-focus-modal-title" + aria-describedby="modal-box-body-custom-focus" > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + + + + ); diff --git a/packages/react-core/src/next/components/Modal/examples/ModalCustomHeader.tsx b/packages/react-core/src/components/Modal/examples/ModalCustomHeader.tsx similarity index 92% rename from packages/react-core/src/next/components/Modal/examples/ModalCustomHeader.tsx rename to packages/react-core/src/components/Modal/examples/ModalCustomHeader.tsx index 0236a1e6105..ba7783e954e 100644 --- a/packages/react-core/src/next/components/Modal/examples/ModalCustomHeader.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalCustomHeader.tsx @@ -1,6 +1,16 @@ import React from 'react'; -import { Button, Title, TitleSizes, TextContent, Flex } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant } from '@patternfly/react-core/next'; +import { + Button, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + ModalVariant, + Title, + TitleSizes, + TextContent, + Flex +} from '@patternfly/react-core'; import WarningTriangleIcon from '@patternfly/react-icons/dist/esm/icons/warning-triangle-icon'; diff --git a/packages/react-core/src/components/Modal/examples/ModalCustomTitleIcon.tsx b/packages/react-core/src/components/Modal/examples/ModalCustomTitleIcon.tsx index 59d6906d435..121da226fef 100644 --- a/packages/react-core/src/components/Modal/examples/ModalCustomTitleIcon.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalCustomTitleIcon.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core'; import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; export const ModalCustomTitleIcon: React.FunctionComponent = () => { @@ -15,31 +15,37 @@ export const ModalCustomTitleIcon: React.FunctionComponent = () => { Show custom title icon modal + + + + When static text describing the modal is available outside of the modal header, it can be given an ID that + is then passed in as the modal's aria-describedby value. + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. +
+ , + - ]} - > - - When static text describing the modal is available outside of the modal header, it can be given an ID that is - then passed in as the modal's aria-describedby value. - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. +
); diff --git a/packages/react-core/src/components/Modal/examples/ModalCustomWidth.tsx b/packages/react-core/src/components/Modal/examples/ModalCustomWidth.tsx index 22246cda212..4d59cfa991f 100644 --- a/packages/react-core/src/components/Modal/examples/ModalCustomWidth.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalCustomWidth.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core'; export const ModalCustomWidth: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -15,23 +15,27 @@ export const ModalCustomWidth: React.FunctionComponent = () => { + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + , + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + ); diff --git a/packages/react-core/src/components/Modal/examples/ModalNoHeaderFooter.tsx b/packages/react-core/src/components/Modal/examples/ModalNoHeaderFooter.tsx index 6c8da740e54..3db47bad2da 100644 --- a/packages/react-core/src/components/Modal/examples/ModalNoHeaderFooter.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalNoHeaderFooter.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, ModalVariant, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalVariant } from '@patternfly/react-core'; export const ModalNoHeaderFooter: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -20,17 +20,19 @@ export const ModalNoHeaderFooter: React.FunctionComponent = () => { aria-describedby="modal-no-header-description" onClose={handleModalToggle} > - - When static text describing the modal is available outside of the modal header, it can be given an ID that is - then passed in as the modal's aria-describedby value. - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + + When static text describing the modal is available outside of the modal header, it can be given an ID that + is then passed in as the modal's aria-describedby value. + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. +
); diff --git a/packages/react-core/src/next/components/Modal/examples/ModalSize.tsx b/packages/react-core/src/components/Modal/examples/ModalSize.tsx similarity index 93% rename from packages/react-core/src/next/components/Modal/examples/ModalSize.tsx rename to packages/react-core/src/components/Modal/examples/ModalSize.tsx index faf5196ba93..7b41438c25c 100644 --- a/packages/react-core/src/next/components/Modal/examples/ModalSize.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalSize.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { Button, Radio } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant } from '@patternfly/react-core/next'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant, Radio } from '@patternfly/react-core'; export const ModalSize: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); diff --git a/packages/react-core/src/components/Modal/examples/ModalTitleIcon.tsx b/packages/react-core/src/components/Modal/examples/ModalTitleIcon.tsx index bf57be4b499..2e43cc60e0a 100644 --- a/packages/react-core/src/components/Modal/examples/ModalTitleIcon.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalTitleIcon.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core'; export const ModalTitleIcon: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -14,31 +14,33 @@ export const ModalTitleIcon: React.FunctionComponent = () => { Show title icon modal + + + + When static text describing the modal is available outside of the modal header, it can be given an ID that + is then passed in as the modal's aria-describedby value. + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. +
+ , + - ]} - > - - When static text describing the modal is available outside of the modal header, it can be given an ID that is - then passed in as the modal's aria-describedby value. - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. +
); diff --git a/packages/react-core/src/components/Modal/examples/ModalTopAligned.tsx b/packages/react-core/src/components/Modal/examples/ModalTopAligned.tsx index fa0b580907f..02f9177bbd8 100644 --- a/packages/react-core/src/components/Modal/examples/ModalTopAligned.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalTopAligned.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core'; export const ModalTopAligned: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -15,23 +15,27 @@ export const ModalTopAligned: React.FunctionComponent = () => { + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + , + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + ); diff --git a/packages/react-core/src/components/Modal/examples/ModalWithDescription.tsx b/packages/react-core/src/components/Modal/examples/ModalWithDescription.tsx index 51684f7e142..99faec812ce 100644 --- a/packages/react-core/src/components/Modal/examples/ModalWithDescription.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalWithDescription.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalHeader, ModalFooter, ModalVariant } from '@patternfly/react-core'; export const ModalWithDescription: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -14,24 +14,65 @@ export const ModalWithDescription: React.FunctionComponent = () => { Show modal with description + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Semper auctor neque vitae + tempus. Diam donec adipiscing tristique risus. Augue eget arcu dictum varius duis. Ut enim blandit volutpat + maecenas volutpat blandit aliquam. Sit amet mauris commodo quis imperdiet massa tincidunt. Habitant morbi + tristique senectus et netus. Fames ac turpis egestas sed tempus urna. Neque laoreet suspendisse interdum + consectetur libero id. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Porta nibh venenatis cras + sed felis eget velit. Nullam non nisi est sit amet facilisis. Nunc mi ipsum faucibus vitae. Lorem sed risus + ultricies tristique nulla aliquet enim tortor at. Egestas sed tempus urna et pharetra pharetra massa massa + ultricies. Lacinia quis vel eros donec ac odio tempor orci. Malesuada fames ac turpis egestas integer eget + aliquet. +
+
+ Neque aliquam vestibulum morbi blandit cursus risus at ultrices. Molestie at elementum eu facilisis sed odio + morbi. Elit pellentesque habitant morbi tristique. Consequat nisl vel pretium lectus quam id leo in vitae. + Quis varius quam quisque id diam vel quam elementum. Viverra nam libero justo laoreet sit amet cursus. + Sollicitudin tempor id eu nisl nunc. Orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim enim + sit amet venenatis urna cursus eget. Iaculis at erat pellentesque adipiscing commodo elit. Faucibus pulvinar + elementum integer enim neque volutpat. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Nunc mattis + enim ut tellus elementum sagittis vitae. Blandit cursus risus at ultrices. Tellus mauris a diam maecenas sed + enim. Non diam phasellus vestibulum lorem sed risus ultricies tristique nulla. +
+
+ Nulla pharetra diam sit amet nisl suscipit adipiscing. Ac tortor vitae purus faucibus ornare suspendisse sed + nisi. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt tortor aliquam nulla facilisi cras + fermentum. Volutpat est velit egestas dui id ornare arcu odio. Pharetra magna ac placerat vestibulum. Ultrices + sagittis orci a scelerisque purus semper eget duis at. Nisi est sit amet facilisis magna etiam tempor orci eu. + Convallis tellus id interdum velit. Facilisis sed odio morbi quis commodo odio aenean sed. +
+
+ Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Facilisi etiam dignissim diam quis enim + lobortis scelerisque fermentum. Eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada. Magna + etiam tempor orci eu lobortis elementum. Quis auctor elit sed vulputate mi sit. Eleifend quam adipiscing vitae + proin sagittis nisl rhoncus mattis rhoncus. Erat velit scelerisque in dictum non. Sit amet nulla facilisi + morbi tempus iaculis urna. Enim ut tellus elementum sagittis vitae et leo duis ut. Lectus arcu bibendum at + varius vel pharetra vel turpis. Morbi tristique senectus et netus et. Eget aliquet nibh praesent tristique + magna sit amet purus gravida. Nisl purus in mollis nunc sed id semper risus. Id neque aliquam vestibulum + morbi. Mauris a diam maecenas sed enim ut sem. Egestas tellus rutrum tellus pellentesque. +
+ , + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. +
); diff --git a/packages/react-core/src/components/Modal/examples/ModalWithDropdown.tsx b/packages/react-core/src/components/Modal/examples/ModalWithDropdown.tsx index 12051fef113..53779a8af77 100644 --- a/packages/react-core/src/components/Modal/examples/ModalWithDropdown.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalWithDropdown.tsx @@ -1,13 +1,16 @@ import React from 'react'; import { - Modal, - ModalVariant, Button, Dropdown, DropdownList, DropdownItem, MenuToggle, - MenuToggleElement + MenuToggleElement, + Modal, + ModalBody, + ModalHeader, + ModalFooter, + ModalVariant } from '@patternfly/react-core'; export const ModalWithDropdown: React.FunctionComponent = () => { @@ -48,60 +51,64 @@ export const ModalWithDropdown: React.FunctionComponent = () => { Show dropdown modal + + +
+ Set the dropdown menuAppendTo prop to parent in order to allow the dropdown menu + break out of the modal container. You'll also want to handle closing of the modal yourself, by listening to + the onEscapePress callback on the Modal component, so you can close the Dropdown first if + it's open without closing the entire modal. +
+
+
+ setIsDropdownOpen(isOpen)} + toggle={(toggleRef: React.Ref) => ( + + Dropdown + + )} + > + + + Action + + ev.preventDefault()} + > + Link + + + Disabled Action + + + Disabled Link + + + +
+
+ , + - ]} - onEscapePress={onEscapePress} - > -
- Set the dropdown menuAppendTo prop to parent in order to allow the dropdown menu - break out of the modal container. You'll also want to handle closing of the modal yourself, by listening to - the onEscapePress callback on the Modal component, so you can close the Dropdown first if - it's open without closing the entire modal. -
-
-
- setIsDropdownOpen(isOpen)} - toggle={(toggleRef: React.Ref) => ( - - Dropdown - - )} - > - - - Action - - ev.preventDefault()} - > - Link - - - Disabled Action - - - Disabled Link - - - -
+
); diff --git a/packages/react-core/src/components/Modal/examples/ModalWithForm.tsx b/packages/react-core/src/components/Modal/examples/ModalWithForm.tsx index a257a414d95..4995ffd558e 100644 --- a/packages/react-core/src/components/Modal/examples/ModalWithForm.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalWithForm.tsx @@ -1,11 +1,14 @@ import React from 'react'; import { - Modal, - ModalVariant, Button, Form, FormGroup, FormGroupLabelHelp, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + ModalVariant, Popover, TextInput } from '@patternfly/react-core'; @@ -41,150 +44,158 @@ export const ModalWithForm: React.FunctionComponent = () => { + + + + + The + + name + + of a + + Person + + + } + bodyContent={ +
+ Often composed of + + givenName + + and + + familyName + + . +
+ } + > + + + } + isRequired + fieldId="modal-with-form-form-name" + > + +
+ + The + + e-mail + + of a + + person + + + } + bodyContent={ +
+ Valid + + e-mail + + address. +
+ } + > + + + } + isRequired + fieldId="modal-with-form-form-email" + > + +
+ + The + + adress + + of a + + person + + + } + bodyContent={ + + } + > + + + } + isRequired + fieldId="modal-with-form-form-address" + > + + + +
+ , + - ]} - > - +
); diff --git a/packages/react-core/src/components/Modal/examples/ModalWithHelp.tsx b/packages/react-core/src/components/Modal/examples/ModalWithHelp.tsx index 00816e3a820..d73367e6cec 100644 --- a/packages/react-core/src/components/Modal/examples/ModalWithHelp.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalWithHelp.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, Button, Popover } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader, Popover } from '@patternfly/react-core'; import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; export const ModalWithHelp: React.FunctionComponent = () => { @@ -16,38 +16,46 @@ export const ModalWithHelp: React.FunctionComponent = () => { Help Popover} - bodyContent={ -
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis. -
- } - footerContent="Popover Footer" - > - - - } isOpen={isModalOpen} onClose={handleModalToggle} - actions={[ + aria-labelledby="with-help-modal-title" + aria-describedby="modal-box-body-with-help" + > + Help Popover} + bodyContent={ +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla + turpis. +
+ } + footerContent="Popover Footer" + > + + + } + /> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + , + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. +
); diff --git a/packages/react-core/src/components/Modal/examples/ModalWithOverflowingContent.tsx b/packages/react-core/src/components/Modal/examples/ModalWithOverflowingContent.tsx index f435649e1a2..243bcde9327 100644 --- a/packages/react-core/src/components/Modal/examples/ModalWithOverflowingContent.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalWithOverflowingContent.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, ModalVariant, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalHeader, ModalFooter, ModalVariant } from '@patternfly/react-core'; export const ModalWithOverflowingContent: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -14,57 +14,60 @@ export const ModalWithOverflowingContent: React.FunctionComponent = () => { Show modal + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Semper auctor neque vitae + tempus. Diam donec adipiscing tristique risus. Augue eget arcu dictum varius duis. Ut enim blandit volutpat + maecenas volutpat blandit aliquam. Sit amet mauris commodo quis imperdiet massa tincidunt. Habitant morbi + tristique senectus et netus. Fames ac turpis egestas sed tempus urna. Neque laoreet suspendisse interdum + consectetur libero id. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Porta nibh venenatis cras + sed felis eget velit. Nullam non nisi est sit amet facilisis. Nunc mi ipsum faucibus vitae. Lorem sed risus + ultricies tristique nulla aliquet enim tortor at. Egestas sed tempus urna et pharetra pharetra massa massa + ultricies. Lacinia quis vel eros donec ac odio tempor orci. Malesuada fames ac turpis egestas integer eget + aliquet. +
+
+ Neque aliquam vestibulum morbi blandit cursus risus at ultrices. Molestie at elementum eu facilisis sed odio + morbi. Elit pellentesque habitant morbi tristique. Consequat nisl vel pretium lectus quam id leo in vitae. + Quis varius quam quisque id diam vel quam elementum. Viverra nam libero justo laoreet sit amet cursus. + Sollicitudin tempor id eu nisl nunc. Orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim enim + sit amet venenatis urna cursus eget. Iaculis at erat pellentesque adipiscing commodo elit. Faucibus pulvinar + elementum integer enim neque volutpat. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Nunc mattis + enim ut tellus elementum sagittis vitae. Blandit cursus risus at ultrices. Tellus mauris a diam maecenas sed + enim. Non diam phasellus vestibulum lorem sed risus ultricies tristique nulla. +
+
+ Nulla pharetra diam sit amet nisl suscipit adipiscing. Ac tortor vitae purus faucibus ornare suspendisse sed + nisi. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt tortor aliquam nulla facilisi cras + fermentum. Volutpat est velit egestas dui id ornare arcu odio. Pharetra magna ac placerat vestibulum. Ultrices + sagittis orci a scelerisque purus semper eget duis at. Nisi est sit amet facilisis magna etiam tempor orci eu. + Convallis tellus id interdum velit. Facilisis sed odio morbi quis commodo odio aenean sed. +
+
+ Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Facilisi etiam dignissim diam quis enim + lobortis scelerisque fermentum. Eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada. Magna + etiam tempor orci eu lobortis elementum. Quis auctor elit sed vulputate mi sit. Eleifend quam adipiscing vitae + proin sagittis nisl rhoncus mattis rhoncus. Erat velit scelerisque in dictum non. Sit amet nulla facilisi + morbi tempus iaculis urna. Enim ut tellus elementum sagittis vitae et leo duis ut. Lectus arcu bibendum at + varius vel pharetra vel turpis. Morbi tristique senectus et netus et. Eget aliquet nibh praesent tristique + magna sit amet purus gravida. Nisl purus in mollis nunc sed id semper risus. Id neque aliquam vestibulum + morbi. Mauris a diam maecenas sed enim ut sem. Egestas tellus rutrum tellus pellentesque. +
+ , + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Semper auctor neque vitae tempus. - Diam donec adipiscing tristique risus. Augue eget arcu dictum varius duis. Ut enim blandit volutpat maecenas - volutpat blandit aliquam. Sit amet mauris commodo quis imperdiet massa tincidunt. Habitant morbi tristique - senectus et netus. Fames ac turpis egestas sed tempus urna. Neque laoreet suspendisse interdum consectetur - libero id. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Porta nibh venenatis cras sed felis eget - velit. Nullam non nisi est sit amet facilisis. Nunc mi ipsum faucibus vitae. Lorem sed risus ultricies tristique - nulla aliquet enim tortor at. Egestas sed tempus urna et pharetra pharetra massa massa ultricies. Lacinia quis - vel eros donec ac odio tempor orci. Malesuada fames ac turpis egestas integer eget aliquet. -
-
- Neque aliquam vestibulum morbi blandit cursus risus at ultrices. Molestie at elementum eu facilisis sed odio - morbi. Elit pellentesque habitant morbi tristique. Consequat nisl vel pretium lectus quam id leo in vitae. Quis - varius quam quisque id diam vel quam elementum. Viverra nam libero justo laoreet sit amet cursus. Sollicitudin - tempor id eu nisl nunc. Orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim enim sit amet - venenatis urna cursus eget. Iaculis at erat pellentesque adipiscing commodo elit. Faucibus pulvinar elementum - integer enim neque volutpat. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Nunc mattis enim ut tellus - elementum sagittis vitae. Blandit cursus risus at ultrices. Tellus mauris a diam maecenas sed enim. Non diam - phasellus vestibulum lorem sed risus ultricies tristique nulla. -
-
- Nulla pharetra diam sit amet nisl suscipit adipiscing. Ac tortor vitae purus faucibus ornare suspendisse sed - nisi. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt tortor aliquam nulla facilisi cras - fermentum. Volutpat est velit egestas dui id ornare arcu odio. Pharetra magna ac placerat vestibulum. Ultrices - sagittis orci a scelerisque purus semper eget duis at. Nisi est sit amet facilisis magna etiam tempor orci eu. - Convallis tellus id interdum velit. Facilisis sed odio morbi quis commodo odio aenean sed. -
-
- Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Facilisi etiam dignissim diam quis enim - lobortis scelerisque fermentum. Eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada. Magna - etiam tempor orci eu lobortis elementum. Quis auctor elit sed vulputate mi sit. Eleifend quam adipiscing vitae - proin sagittis nisl rhoncus mattis rhoncus. Erat velit scelerisque in dictum non. Sit amet nulla facilisi morbi - tempus iaculis urna. Enim ut tellus elementum sagittis vitae et leo duis ut. Lectus arcu bibendum at varius vel - pharetra vel turpis. Morbi tristique senectus et netus et. Eget aliquet nibh praesent tristique magna sit amet - purus gravida. Nisl purus in mollis nunc sed id semper risus. Id neque aliquam vestibulum morbi. Mauris a diam - maecenas sed enim ut sem. Egestas tellus rutrum tellus pellentesque. +
); diff --git a/packages/react-core/src/components/Modal/examples/ModalWithWizard.tsx b/packages/react-core/src/components/Modal/examples/ModalWithWizard.tsx index 0dab445663b..4e030dd91f7 100644 --- a/packages/react-core/src/components/Modal/examples/ModalWithWizard.tsx +++ b/packages/react-core/src/components/Modal/examples/ModalWithWizard.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Modal, ModalVariant, Button, Wizard, WizardHeader, WizardStep } from '@patternfly/react-core'; +import { Button, Modal, ModalVariant, Wizard, WizardHeader, WizardStep } from '@patternfly/react-core'; export const ModalWithWizard: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -25,12 +25,9 @@ export const ModalWithWizard: React.FunctionComponent = () => { { title="Wizard modal" titleId="modal-wizard-label" description="This is a wizard inside of a modal." + descriptionId="modal-wizard-description" onClose={handleWizardToggle} closeButtonAriaLabel="Close wizard" /> diff --git a/packages/react-core/src/components/Modal/index.ts b/packages/react-core/src/components/Modal/index.ts index d671375de62..14ff043038d 100644 --- a/packages/react-core/src/components/Modal/index.ts +++ b/packages/react-core/src/components/Modal/index.ts @@ -1,7 +1,4 @@ export * from './Modal'; -export * from './ModalBox'; -export * from './ModalBoxBody'; -export * from './ModalBoxCloseButton'; -export * from './ModalBoxHeader'; -export * from './ModalBoxFooter'; -export * from './ModalContent'; +export * from './ModalBody'; +export * from './ModalHeader'; +export * from './ModalFooter'; diff --git a/packages/react-core/src/components/Wizard/examples/Wizard.md b/packages/react-core/src/components/Wizard/examples/Wizard.md index 1dd41237c17..0b3b9b1bd8d 100644 --- a/packages/react-core/src/components/Wizard/examples/Wizard.md +++ b/packages/react-core/src/components/Wizard/examples/Wizard.md @@ -46,6 +46,7 @@ WizardNavItem, WizardNav, WizardHeader } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon'; import SlackHashIcon from '@patternfly/react-icons/dist/esm/icons/slack-hash-icon'; import CogsIcon from '@patternfly/react-icons/dist/esm/icons/cogs-icon'; diff --git a/packages/react-core/src/components/Wizard/examples/WizardWithinModal.tsx b/packages/react-core/src/components/Wizard/examples/WizardWithinModal.tsx index d07121d0820..41289391e65 100644 --- a/packages/react-core/src/components/Wizard/examples/WizardWithinModal.tsx +++ b/packages/react-core/src/components/Wizard/examples/WizardWithinModal.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Button, Modal, ModalVariant, Wizard, WizardStep, WizardHeader } from '@patternfly/react-core'; +import { Button, Wizard, WizardStep, WizardHeader } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; export const WizardWithinModal = () => { const [isModelOpen, setIsModalOpen] = React.useState(false); @@ -8,13 +9,13 @@ export const WizardWithinModal = () => { <> - setIsModalOpen(false)} - variant={ModalVariant.medium} + variant={ModalVariantDeprecated.medium} > { Review step content - + ); }; diff --git a/packages/react-core/src/demos/DatePicker/DatePicker.md b/packages/react-core/src/demos/DatePicker/DatePicker.md index 3f4582330c3..70806dad901 100644 --- a/packages/react-core/src/demos/DatePicker/DatePicker.md +++ b/packages/react-core/src/demos/DatePicker/DatePicker.md @@ -4,6 +4,8 @@ section: components subsection: date-and-time --- +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; + ## Demos ### Date range picker @@ -58,8 +60,6 @@ DateRangePicker = () => { }; ``` - - ### Date and time pickers in modal Modals trap focus and watch a few document level events. In order to place a date picker in a modal: diff --git a/packages/react-core/src/demos/DatePicker/examples/DateTimePickerInModal.tsx b/packages/react-core/src/demos/DatePicker/examples/DateTimePickerInModal.tsx index 1d2893e0480..a9eff532449 100644 --- a/packages/react-core/src/demos/DatePicker/examples/DateTimePickerInModal.tsx +++ b/packages/react-core/src/demos/DatePicker/examples/DateTimePickerInModal.tsx @@ -1,13 +1,6 @@ import React from 'react'; -import { - DatePicker, - Modal, - ModalVariant, - Button, - TimePicker, - InputGroup, - InputGroupItem -} from '@patternfly/react-core'; +import { DatePicker, Button, TimePicker, InputGroup, InputGroupItem } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; export const SimpleModal = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -33,9 +26,9 @@ export const SimpleModal = () => { - { - + ); }; diff --git a/packages/react-core/src/demos/LabelGroupDemos.md b/packages/react-core/src/demos/LabelGroupDemos.md index 1adee78a719..85997ce7cd1 100644 --- a/packages/react-core/src/demos/LabelGroupDemos.md +++ b/packages/react-core/src/demos/LabelGroupDemos.md @@ -3,6 +3,7 @@ id: Label section: components --- +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; ## Demos @@ -10,9 +11,11 @@ import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-i ### Editable labels with add dropdown ```ts file="../components/Label/examples/LabelGroupEditableAddDropdown.tsx" + ``` ### Editable labels with add modal ```ts file="../components/Label/examples/LabelGroupEditableAddModal.tsx" + ``` diff --git a/packages/react-core/src/demos/MultipleFileUploadDemos.md b/packages/react-core/src/demos/MultipleFileUploadDemos.md index ebf61fcaac6..711dfbfdbed 100644 --- a/packages/react-core/src/demos/MultipleFileUploadDemos.md +++ b/packages/react-core/src/demos/MultipleFileUploadDemos.md @@ -4,6 +4,7 @@ section: components subsection: file-upload --- +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon'; ## Demos @@ -13,4 +14,5 @@ import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon'; This demo shows how to add a modal to alert users that the file(s) they attempted to drop was of a non-acceptable type. ```ts file="./examples/MultipleFileUpload/MultipleFileUploadRejectedFile.tsx" + ``` diff --git a/packages/react-core/src/demos/examples/MultipleFileUpload/MultipleFileUploadRejectedFile.tsx b/packages/react-core/src/demos/examples/MultipleFileUpload/MultipleFileUploadRejectedFile.tsx index c4fc4c65393..2013044df0b 100644 --- a/packages/react-core/src/demos/examples/MultipleFileUpload/MultipleFileUploadRejectedFile.tsx +++ b/packages/react-core/src/demos/examples/MultipleFileUpload/MultipleFileUploadRejectedFile.tsx @@ -5,10 +5,10 @@ import { MultipleFileUploadMain, MultipleFileUploadStatus, MultipleFileUploadStatusItem, - Modal, Checkbox, DropEvent } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon'; interface readFile { @@ -135,7 +135,7 @@ export const MultipleFileUploadBasic: React.FunctionComponent = () => { ))} )} - { onClose={() => setModalText('')} > {modalText} - + , OUIAProps { + /** Action buttons to add to the standard modal footer. Ignored if the footer property + * is passed in. + */ + actions?: any; /** The parent container to append the modal to. Defaults to "document.body". */ appendTo?: HTMLElement | (() => HTMLElement); - /** Id to use for the modal box description. This should match the ModalHeader labelId or descriptorId. */ + /** Id to use for the modal box descriptor. */ 'aria-describedby'?: string; - /** Adds an accessible name to the modal when there is no title in the ModalHeader. */ + /** Accessible descriptor of the modal. */ 'aria-label'?: string; - /** Id to use for the modal box label. This should include the ModalHeader labelId. */ + /** Id to use for the modal box label. */ 'aria-labelledby'?: string; + /** Accessible label applied to the modal box body. This should be used to communicate + * important information about the modal box body div element if needed, such as that it + * is scrollable. + */ + bodyAriaLabel?: string; + /** Accessible role applied to the modal box body. This will default to "region" if the + * bodyAriaLabel property is passed in. Set to a more appropriate role as applicable + * based on the modal content and context. + */ + bodyAriaRole?: string; /** Content rendered inside the modal. */ children: React.ReactNode; /** Additional classes added to the modal. */ className?: string; + /** Description of the modal. */ + description?: React.ReactNode; /** Flag to disable focus trap. */ disableFocusTrap?: boolean; /** The element to focus when the modal opens. By default the first * focusable element will receive focus. */ elementToFocus?: HTMLElement | SVGElement | string; + /** Custom footer. */ + footer?: React.ReactNode; + /** Flag indicating if modal content should be placed in a modal box body wrapper. */ + hasNoBodyWrapper?: boolean; + /** Complex header (more than just text), supersedes the title property for header content. */ + header?: React.ReactNode; + /** Optional help section for the modal header. */ + help?: React.ReactNode; /** An id to use for the modal box container. */ id?: string; /** Flag to show the modal. */ isOpen?: boolean; - /** Add callback for when the close button is clicked. This prop needs to be passed to render the close button */ + /** A callback for when the close button is clicked. */ onClose?: (event: KeyboardEvent | React.MouseEvent) => void; /** Modal handles pressing of the escape key and closes the modal. If you want to handle * this yourself you can use this callback function. */ @@ -38,6 +62,16 @@ export interface ModalProps extends React.HTMLProps, OUIAProps { position?: 'default' | 'top'; /** Offset from alternate position. Can be any valid CSS length/percentage. */ positionOffset?: string; + /** Flag to show the close button in the header area of the modal. */ + showClose?: boolean; + /** Simple text content of the modal header. Also used for the aria-label on the body. */ + title?: string; + /** Optional alert icon (or other) to show before the title of the modal header. When the + * predefined alert types are used the default styling will be automatically applied. + */ + titleIconVariant?: 'success' | 'danger' | 'warning' | 'info' | 'custom' | React.ComponentType; + /** Optional title label text for screen readers. */ + titleLabel?: string; /** Variant of the modal. */ variant?: 'small' | 'medium' | 'large' | 'default'; /** Default width of the modal. */ @@ -66,10 +100,24 @@ class Modal extends React.Component { static displayName = 'Modal'; static currentId = 0; boxId = ''; + labelId = ''; + descriptorId = ''; static defaultProps: PickOptional = { + className: '', isOpen: false, + title: '', + titleIconVariant: null, + titleLabel: '', + 'aria-label': '', + showClose: true, + 'aria-describedby': '', + 'aria-labelledby': '', + id: undefined, + actions: [] as any[], + onClose: () => undefined as any, variant: 'default', + hasNoBodyWrapper: false, appendTo: () => document.body, ouiaSafe: true, position: 'default' @@ -78,7 +126,11 @@ class Modal extends React.Component { constructor(props: ModalProps) { super(props); const boxIdNum = Modal.currentId++; + const labelIdNum = boxIdNum + 1; + const descriptorIdNum = boxIdNum + 2; this.boxId = props.id || `pf-modal-part-${boxIdNum}`; + this.labelId = `pf-modal-part-${labelIdNum}`; + this.descriptorId = `pf-modal-part-${descriptorIdNum}`; this.state = { container: undefined, @@ -116,9 +168,11 @@ class Modal extends React.Component { componentDidMount() { const { appendTo, - 'aria-describedby': ariaDescribedby, + title, 'aria-label': ariaLabel, - 'aria-labelledby': ariaLabelledby + 'aria-labelledby': ariaLabelledby, + hasNoBodyWrapper, + header } = this.props; const target: HTMLElement = this.getElement(appendTo); const container = document.createElement('div'); @@ -132,9 +186,16 @@ class Modal extends React.Component { target.classList.remove(css(styles.backdropOpen)); } - if (!ariaDescribedby && !ariaLabel && !ariaLabelledby) { + if (this.isEmpty(title) && this.isEmpty(ariaLabel) && this.isEmpty(ariaLabelledby)) { // eslint-disable-next-line no-console - console.error('Modal: Specify at least one of: aria-describedby, aria-label, aria-labelledby.'); + console.error('Modal: Specify at least one of: title, aria-label, aria-labelledby.'); + } + + if (this.isEmpty(ariaLabel) && this.isEmpty(ariaLabelledby) && (hasNoBodyWrapper || header)) { + // eslint-disable-next-line no-console + console.error( + 'Modal: When using hasNoBodyWrapper or setting a custom header, ensure you assign an accessible name to the the modal container with aria-label or aria-labelledby.' + ); } } @@ -170,6 +231,11 @@ class Modal extends React.Component { 'aria-labelledby': ariaLabelledby, 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, + bodyAriaLabel, + bodyAriaRole, + title, + titleIconVariant, + titleLabel, ouiaId, ouiaSafe, position, @@ -184,15 +250,22 @@ class Modal extends React.Component { return ReactDOM.createPortal( , container ) as React.ReactElement; diff --git a/packages/react-core/src/next/components/Modal/ModalBox.tsx b/packages/react-core/src/deprecated/components/Modal/ModalBox.tsx similarity index 87% rename from packages/react-core/src/next/components/Modal/ModalBox.tsx rename to packages/react-core/src/deprecated/components/Modal/ModalBox.tsx index b52a9660ece..8f9158876d0 100644 --- a/packages/react-core/src/next/components/Modal/ModalBox.tsx +++ b/packages/react-core/src/deprecated/components/Modal/ModalBox.tsx @@ -4,9 +4,9 @@ import styles from '@patternfly/react-styles/css/components/ModalBox/modal-box'; import topSpacer from '@patternfly/react-tokens/dist/esm/c_modal_box_m_align_top_spacer'; export interface ModalBoxProps extends React.HTMLProps { - /** Id to use for the modal box description. This should match the ModalHeader labelId or descriptorId */ - 'aria-describedby'?: string; - /** Adds an accessible name to the modal when there is no title in the ModalHeader. */ + /** Id to use for the modal box description. */ + 'aria-describedby': string; + /** Accessible descriptor of the modal. */ 'aria-label'?: string; /** Id to use for the modal box label. */ 'aria-labelledby'?: string; @@ -24,12 +24,12 @@ export interface ModalBoxProps extends React.HTMLProps { export const ModalBox: React.FunctionComponent = ({ children, - className, + className = '', variant = 'default', position, positionOffset, 'aria-labelledby': ariaLabelledby, - 'aria-label': ariaLabel, + 'aria-label': ariaLabel = '', 'aria-describedby': ariaDescribedby, style, ...props @@ -40,6 +40,7 @@ export const ModalBox: React.FunctionComponent = ({ } return (
= ({ variant === 'medium' && styles.modifiers.md )} style={style} - {...props} > {children}
diff --git a/packages/react-core/src/components/Modal/ModalBoxBody.tsx b/packages/react-core/src/deprecated/components/Modal/ModalBoxBody.tsx similarity index 100% rename from packages/react-core/src/components/Modal/ModalBoxBody.tsx rename to packages/react-core/src/deprecated/components/Modal/ModalBoxBody.tsx diff --git a/packages/react-core/src/next/components/Modal/ModalBoxCloseButton.tsx b/packages/react-core/src/deprecated/components/Modal/ModalBoxCloseButton.tsx similarity index 97% rename from packages/react-core/src/next/components/Modal/ModalBoxCloseButton.tsx rename to packages/react-core/src/deprecated/components/Modal/ModalBoxCloseButton.tsx index 54cd0c04006..a3549530fcf 100644 --- a/packages/react-core/src/next/components/Modal/ModalBoxCloseButton.tsx +++ b/packages/react-core/src/deprecated/components/Modal/ModalBoxCloseButton.tsx @@ -18,7 +18,7 @@ export interface ModalBoxCloseButtonProps extends OUIAProps { export const ModalBoxCloseButton: React.FunctionComponent = ({ className, - onClose, + onClose = () => undefined as any, 'aria-label': ariaLabel = 'Close', ouiaId, ...props diff --git a/packages/react-core/src/next/components/Modal/ModalBoxDescription.tsx b/packages/react-core/src/deprecated/components/Modal/ModalBoxDescription.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/ModalBoxDescription.tsx rename to packages/react-core/src/deprecated/components/Modal/ModalBoxDescription.tsx diff --git a/packages/react-core/src/components/Modal/ModalBoxFooter.tsx b/packages/react-core/src/deprecated/components/Modal/ModalBoxFooter.tsx similarity index 100% rename from packages/react-core/src/components/Modal/ModalBoxFooter.tsx rename to packages/react-core/src/deprecated/components/Modal/ModalBoxFooter.tsx diff --git a/packages/react-core/src/components/Modal/ModalBoxHeader.tsx b/packages/react-core/src/deprecated/components/Modal/ModalBoxHeader.tsx similarity index 100% rename from packages/react-core/src/components/Modal/ModalBoxHeader.tsx rename to packages/react-core/src/deprecated/components/Modal/ModalBoxHeader.tsx diff --git a/packages/react-core/src/next/components/Modal/ModalBoxTitle.tsx b/packages/react-core/src/deprecated/components/Modal/ModalBoxTitle.tsx similarity index 92% rename from packages/react-core/src/next/components/Modal/ModalBoxTitle.tsx rename to packages/react-core/src/deprecated/components/Modal/ModalBoxTitle.tsx index dcb565fe9ec..ccb286514ee 100644 --- a/packages/react-core/src/next/components/Modal/ModalBoxTitle.tsx +++ b/packages/react-core/src/deprecated/components/Modal/ModalBoxTitle.tsx @@ -17,29 +17,27 @@ export interface ModalBoxTitleProps { /** Additional classes added to the modal box title. */ className?: string; /** Id of the modal box title. */ - id?: string; + id: string; /** Content rendered inside the modal box title. */ title: React.ReactNode; /** Optional alert icon (or other) to show before the title. When the predefined alert types * are used the default styling will be automatically applied. */ titleIconVariant?: 'success' | 'danger' | 'warning' | 'info' | 'custom' | React.ComponentType; /** Optional title label text for screen readers. */ - titleScreenReaderText?: string; + titleLabel?: string; } export const ModalBoxTitle: React.FunctionComponent = ({ - className, + className = '', id, title, titleIconVariant, - titleScreenReaderText, + titleLabel = '', ...props }: ModalBoxTitleProps) => { const [hasTooltip, setHasTooltip] = React.useState(false); const h1 = React.useRef(null); - const label = - titleScreenReaderText || - (isVariantIcon(titleIconVariant) ? `${capitalize(titleIconVariant)} alert:` : titleScreenReaderText); + const label = titleLabel || (isVariantIcon(titleIconVariant) ? `${capitalize(titleIconVariant)} alert:` : titleLabel); const variantIcons = { success: , danger: , diff --git a/packages/react-core/src/deprecated/components/Modal/ModalContent.tsx b/packages/react-core/src/deprecated/components/Modal/ModalContent.tsx new file mode 100644 index 00000000000..26a070fec92 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/ModalContent.tsx @@ -0,0 +1,222 @@ +import * as React from 'react'; +import { FocusTrap } from '../../../helpers'; +import modalStyles from '@patternfly/react-styles/css/components/ModalBox/modal-box'; +import bullsEyeStyles from '@patternfly/react-styles/css/layouts/Bullseye/bullseye'; +import { css } from '@patternfly/react-styles'; +import { getOUIAProps, OUIAProps } from '../../../helpers'; + +import { Backdrop } from '../../../components/Backdrop/Backdrop'; +import { ModalBoxBody } from './ModalBoxBody'; +import { ModalBoxCloseButton } from './ModalBoxCloseButton'; +import { ModalBox } from './ModalBox'; +import { ModalBoxFooter } from './ModalBoxFooter'; +import { ModalBoxDescription } from './ModalBoxDescription'; +import { ModalBoxHeader } from './ModalBoxHeader'; +import { ModalBoxTitle, isVariantIcon } from './ModalBoxTitle'; + +export interface ModalContentProps extends OUIAProps { + /** Action buttons to add to the standard modal footer. Ignored if the footer property + * is passed in. + */ + actions?: any; + /** Id to use for the modal box descriptor. */ + 'aria-describedby'?: string; + /** Accessible descriptor of the modal. */ + 'aria-label'?: string; + /** Id to use for the modal box label. */ + 'aria-labelledby'?: string | null; + /** Accessible label applied to the modal box body. This should be used to communicate + * important information about the modal box body div element if needed, such as that it + * is scrollable. + */ + bodyAriaLabel?: string; + /** Accessible role applied to the modal box body. This will default to "region" if the + * bodyAriaLabel property is passed in. Set to a more appropriate role as applicable + * based on the modal content and context. + */ + bodyAriaRole?: string; + /** Id of the modal box container. */ + boxId: string; + /** Content rendered inside the modal. */ + children: React.ReactNode; + /** Additional classes added to the modal box. */ + className?: string; + /** Description of the modal. */ + description?: React.ReactNode; + /** Id of the modal box description. */ + descriptorId: string; + /** Flag to disable focus trap. */ + disableFocusTrap?: boolean; + /** The element to focus when the modal opens. By default the first + * focusable element will receive focus. + */ + elementToFocus?: HTMLElement | SVGElement | string; + /** Custom footer. */ + footer?: React.ReactNode; + /** Flag indicating if modal content should be placed in a modal box body wrapper. */ + hasNoBodyWrapper?: boolean; + /** Complex header (more than just text), supersedes the title property for header content. */ + header?: React.ReactNode; + /** Optional help section for the modal header. */ + help?: React.ReactNode; + /** Flag to show the modal. */ + isOpen?: boolean; + /** Id of the modal box title. */ + labelId: string; + /** A callback for when the close button is clicked. */ + onClose?: (event: KeyboardEvent | React.MouseEvent) => void; + /** Position of the modal. By default a modal will be positioned vertically and horizontally centered. */ + position?: 'default' | 'top'; + /** Offset from alternate position. Can be any valid CSS length/percentage. */ + positionOffset?: string; + /** Flag to show the close button in the header area of the modal. */ + showClose?: boolean; + /** Simple text content of the modal header. Also used for the aria-label on the body. */ + title?: string; + /** Optional alert icon (or other) to show before the title of the modal header. When the + * predefined alert types are used the default styling will be automatically applied. + */ + titleIconVariant?: 'success' | 'danger' | 'warning' | 'info' | 'custom' | React.ComponentType; + /** Optional title label text for screen readers. */ + titleLabel?: string; + /** Variant of the modal. */ + variant?: 'small' | 'medium' | 'large' | 'default'; + /** Default width of the modal. */ + width?: number | string; + /** Maximum width of the modal. */ + maxWidth?: number | string; + /** Value to overwrite the randomly generated data-ouia-component-id.*/ + ouiaId?: number | string; + /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ + ouiaSafe?: boolean; +} + +export const ModalContent: React.FunctionComponent = ({ + children, + className = '', + isOpen = false, + header = null, + help = null, + description = null, + title = '', + titleIconVariant = null, + titleLabel = '', + 'aria-label': ariaLabel = '', + 'aria-describedby': ariaDescribedby, + 'aria-labelledby': ariaLabelledby, + bodyAriaLabel, + bodyAriaRole, + showClose = true, + footer = null, + actions = [], + onClose = () => undefined as any, + variant = 'default', + position, + positionOffset, + width, + maxWidth, + boxId, + labelId, + descriptorId, + disableFocusTrap = false, + hasNoBodyWrapper = false, + ouiaId, + ouiaSafe = true, + elementToFocus, + ...props +}: ModalContentProps) => { + if (!isOpen) { + return null; + } + + const modalBoxHeader = header ? ( + {header} + ) : ( + title && ( + + + {description && {description}} + + ) + ); + + const modalBoxFooter = footer ? ( + {footer} + ) : ( + actions.length > 0 && {actions} + ); + + const defaultModalBodyAriaRole = bodyAriaLabel ? 'region' : undefined; + + const hasNoDescription = !description && !ariaDescribedby; + const id = hasNoDescription ? descriptorId : undefined; + + const modalBody = hasNoBodyWrapper ? ( + children + ) : ( + + {children} + + ); + const ariaLabelledbyFormatted = (): null | string => { + if (ariaLabelledby === null) { + return null; + } + const idRefList: string[] = []; + if ((ariaLabel && boxId) !== '') { + idRefList.push(ariaLabel && boxId); + } + if (ariaLabelledby) { + idRefList.push(ariaLabelledby); + } + if (title) { + idRefList.push(labelId); + } + return idRefList.join(' '); + }; + + const modalBox = ( + + {showClose && onClose(event)} ouiaId={ouiaId} />} + {modalBoxHeader} + {modalBody} + {modalBoxFooter} + + ); + return ( + + + {modalBox} + + + ); +}; +ModalContent.displayName = 'ModalContent'; diff --git a/packages/react-core/src/next/components/Modal/__tests__/Modal.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/Modal.test.tsx similarity index 65% rename from packages/react-core/src/next/components/Modal/__tests__/Modal.test.tsx rename to packages/react-core/src/deprecated/components/Modal/__tests__/Modal.test.tsx index ff0e1e09f34..44e11dd68f6 100644 --- a/packages/react-core/src/next/components/Modal/__tests__/Modal.test.tsx +++ b/packages/react-core/src/deprecated/components/Modal/__tests__/Modal.test.tsx @@ -13,6 +13,7 @@ jest.spyOn(document, 'createElement'); jest.spyOn(document.body, 'addEventListener'); const props = { + title: 'Modal', onClose: jest.fn(), isOpen: false, children: 'modal content' @@ -47,9 +48,9 @@ describe('Modal', () => { test('modal closes with escape', async () => { const user = userEvent.setup(); - render(); + render(); - await user.type(screen.getByLabelText('modal-div'), `{${KeyTypes.Escape}}`); + await user.type(screen.getByText(props.title), `{${KeyTypes.Escape}}`); expect(props.onClose).toHaveBeenCalled(); }); @@ -69,17 +70,13 @@ describe('Modal', () => { expect(document.body).not.toHaveClass(css(styles.backdropOpen)); }); - test('modal shows the close button when onClose prop is passed (true by default)', () => { + test('modal shows the close button when showClose is true (true by default)', () => { render(); expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument(); }); - test('modal does not show the close button when onClose not passed', () => { - render( - - No close button{' '} - - ); + test('modal does not show the close button when showClose is false', () => { + render(); expect(screen.queryByRole('button', { name: 'Close' })).toBeNull(); }); @@ -97,6 +94,21 @@ describe('Modal', () => { expect(consoleErrorMock).toHaveBeenCalled(); }); + test('modal generates console warning when conflicting accessible name strategies are provided', () => { + const props = { + hasNoBodyWrapper: true, + onClose: jest.fn(), + isOpen: true, + children: 'modal content' + }; + const consoleErrorMock = jest.fn(); + global.console = { error: consoleErrorMock } as any; + + render(); + + expect(consoleErrorMock).toHaveBeenCalled(); + }); + test('modal adds aria-hidden attribute to its siblings when open', () => { render(, { container: document.body.appendChild(target) }); @@ -142,4 +154,59 @@ describe('Modal', () => { expect(asideSibling).not.toHaveAttribute('aria-hidden'); expect(articleSibling).not.toHaveAttribute('aria-hidden'); }); + test('The modalBoxBody has no aria-label when bodyAriaLabel is not passed', () => { + const props = { + isOpen: true + }; + + render(This is a ModalBox); + + const modalBoxBody = screen.getByText('This is a ModalBox'); + expect(modalBoxBody).not.toHaveAccessibleName('modal box body aria label'); + }); + + test('The modalBoxBody has the expected aria-label when bodyAriaLabel is passed', () => { + const props = { + isOpen: true + }; + + render( + + This is a ModalBox + + ); + + const modalBoxBody = screen.getByText('This is a ModalBox'); + expect(modalBoxBody).toHaveAccessibleName('modal box body aria label'); + }); + + test('The modalBoxBody has the expected aria role when bodyAriaLabel is passed and bodyAriaRole is not', () => { + const props = { + isOpen: true + }; + + render( + + This is a ModalBox + + ); + + const modalBoxBody = screen.getByRole('region', { name: 'modal box body aria label' }); + expect(modalBoxBody).toBeInTheDocument(); + }); + + test('The modalBoxBody has the expected aria role when bodyAriaRole is passed', () => { + const props = { + isOpen: true + }; + + render( + + This is a ModalBox + + ); + + const modalBoxBody = screen.getByRole('article', { name: 'modal box body aria label' }); + expect(modalBoxBody).toBeInTheDocument(); + }); }); diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalBox.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBox.test.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/ModalBox.test.tsx rename to packages/react-core/src/deprecated/components/Modal/__tests__/ModalBox.test.tsx diff --git a/packages/react-core/src/components/Modal/__tests__/ModalBoxBody.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxBody.test.tsx similarity index 100% rename from packages/react-core/src/components/Modal/__tests__/ModalBoxBody.test.tsx rename to packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxBody.test.tsx diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalBoxCloseButton.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxCloseButton.test.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/ModalBoxCloseButton.test.tsx rename to packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxCloseButton.test.tsx diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalBoxDescription.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxDescription.test.tsx similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/ModalBoxDescription.test.tsx rename to packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxDescription.test.tsx diff --git a/packages/react-core/src/components/Modal/__tests__/ModalBoxFooter.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxFooter.test.tsx similarity index 100% rename from packages/react-core/src/components/Modal/__tests__/ModalBoxFooter.test.tsx rename to packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxFooter.test.tsx diff --git a/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxHeader.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxHeader.test.tsx new file mode 100644 index 00000000000..943230d05cb --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxHeader.test.tsx @@ -0,0 +1,14 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; + +import { ModalBoxHeader } from '../ModalBoxHeader'; + +test('ModalBoxHeader Test', () => { + const { asFragment } = render(This is a ModalBox header); + expect(asFragment()).toMatchSnapshot(); +}); + +test('ModalBoxHeader help renders', () => { + const { asFragment } = render(test}>This is a ModalBox header); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalBoxTitle.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxTitle.test.tsx similarity index 50% rename from packages/react-core/src/next/components/Modal/__tests__/ModalBoxTitle.test.tsx rename to packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxTitle.test.tsx index 269d784695d..84e7c3f1e20 100644 --- a/packages/react-core/src/next/components/Modal/__tests__/ModalBoxTitle.test.tsx +++ b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalBoxTitle.test.tsx @@ -5,33 +5,55 @@ import { ModalBoxTitle } from '../ModalBoxTitle'; import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; test('ModalBoxTitle alert variant', () => { - const { asFragment } = render(); + const { asFragment } = render( + + content + + ); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle info variant', () => { - const { asFragment } = render(); + const { asFragment } = render( + + content + + ); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle danger variant', () => { - const { asFragment } = render(); + const { asFragment } = render( + + content + + ); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle custom variant', () => { - const { asFragment } = render(); + const { asFragment } = render( + + content + + ); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle success variant', () => { - const { asFragment } = render(); + const { asFragment } = render( + + content + + ); expect(asFragment()).toMatchSnapshot(); }); test('ModalBoxTitle custom icon variant', () => { const { asFragment } = render( - + + content + ); expect(asFragment()).toMatchSnapshot(); }); diff --git a/packages/react-core/src/deprecated/components/Modal/__tests__/ModalContent.test.tsx b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalContent.test.tsx new file mode 100644 index 00000000000..c7d4b0fac95 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/__tests__/ModalContent.test.tsx @@ -0,0 +1,112 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; + +import { ModalContent } from '../ModalContent'; + +const modalContentProps = { + boxId: 'boxId', + labelId: 'labelId', + descriptorId: 'descriptorId' +}; +test('Modal Content Test only body', () => { + const { asFragment } = render( + + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Content Test isOpen', () => { + const { asFragment } = render( + + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Content Test description', () => { + const { asFragment } = render( + + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Content Test with footer', () => { + const { asFragment } = render( + + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Content test without footer', () => { + const { asFragment } = render( + + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Content Test with onclose', () => { + const { asFragment } = render( + undefined} + isOpen + {...modalContentProps} + > + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Test with custom header', () => { + const header = TEST; + + const { asFragment } = render( + undefined} + isOpen + {...modalContentProps} + > + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Modal Test with custom footer', () => { + const footer = TEST; + + const { asFragment } = render( + undefined} + isOpen + {...modalContentProps} + > + This is a ModalBox header + + ); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBox.test.tsx.snap b/packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBox.test.tsx.snap similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBox.test.tsx.snap rename to packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBox.test.tsx.snap diff --git a/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxBody.test.tsx.snap b/packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxBody.test.tsx.snap similarity index 100% rename from packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxBody.test.tsx.snap rename to packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxBody.test.tsx.snap diff --git a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBoxDescription.test.tsx.snap b/packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxDescription.test.tsx.snap similarity index 100% rename from packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBoxDescription.test.tsx.snap rename to packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxDescription.test.tsx.snap diff --git a/packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxFooter.test.tsx.snap b/packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxFooter.test.tsx.snap similarity index 100% rename from packages/react-core/src/components/Modal/__tests__/__snapshots__/ModalBoxFooter.test.tsx.snap rename to packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxFooter.test.tsx.snap diff --git a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap b/packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap similarity index 62% rename from packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap rename to packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap index ff53d0efef5..3ad4ea4de22 100644 --- a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap +++ b/packages/react-core/src/deprecated/components/Modal/__tests__/__snapshots__/ModalBoxHeader.test.tsx.snap @@ -1,20 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Modal Test with custom header 1`] = ` - -
- - TEST - -
-
-`; - -exports[`ModalHeader Test 1`] = ` +exports[`ModalBoxHeader Test 1`] = `
`; -exports[`ModalHeader help renders 1`] = ` +exports[`ModalBoxHeader help renders 1`] = `
+
+
+ +
+
+ +`; + +exports[`Modal Content Test isOpen 1`] = ` + +
+
+ +
+
+
+`; + +exports[`Modal Content Test only body 1`] = ` + +
+
+ +
+
+
+`; + +exports[`Modal Content Test with footer 1`] = ` + +
+
+ +
+
+
+`; + +exports[`Modal Content Test with onclose 1`] = ` + +
+
+ +
+
+
+`; + +exports[`Modal Content test without footer 1`] = ` + +
+
+ +
+
+
+`; + +exports[`Modal Test with custom footer 1`] = ` + +
+
+ +
+
+
+`; + +exports[`Modal Test with custom header 1`] = ` + +
+
+ +
+
+
+`; diff --git a/packages/react-core/src/next/components/Modal/examples/Modal.md b/packages/react-core/src/deprecated/components/Modal/examples/Modal.md similarity index 58% rename from packages/react-core/src/next/components/Modal/examples/Modal.md rename to packages/react-core/src/deprecated/components/Modal/examples/Modal.md index c5b75813e96..1d794be52ae 100644 --- a/packages/react-core/src/next/components/Modal/examples/Modal.md +++ b/packages/react-core/src/deprecated/components/Modal/examples/Modal.md @@ -2,26 +2,24 @@ id: Modal section: components cssPrefix: pf-v5-c-modal-box -propComponents: ['Modal', 'ModalBody', 'ModalHeader', 'ModalFooter'] +propComponents: ['Modal'] ouia: true -beta: true +deprecated: true --- +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; import WarningTriangleIcon from '@patternfly/react-icons/dist/esm/icons/warning-triangle-icon'; import CaretDownIcon from '@patternfly/react-icons/dist/esm/icons/caret-down-icon'; import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; +import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; import formStyles from '@patternfly/react-styles/css/components/Form/form'; ## Examples ### Basic modals -Basic modals give users the option to either confirm or cancel an action. - -To flag an open modal, use the `isOpen` property. To execute a callback when a modal is closed, use the `onClose` property. - -A modal must have a ``, containing the main content of the modal. The `` and `` components are not required, but are typically used to display the modal title and any button actions, respectively. +Basic modals give users the option to either confirm or cancel an action. To flag an open modal, use the `isOpen` property. To execute a callback when a modal is closed, use the `onClose` property. ```ts file="./ModalBasic.tsx" @@ -29,7 +27,7 @@ A modal must have a ``, containing the main content of the modal. The ### Scrollable modals -To enable keyboard-accessible scrolling of a modal’s content, pass `tabIndex={0}` to the ``. +To enable keyboard-accessible scrolling of a modal’s content, pass `tabIndex={0}` to the ``. ```ts file="ModalWithOverflowingContent.tsx" @@ -51,13 +49,29 @@ To override a modal's default center alignment, use the `position` property. In ``` -### Modal sizes +### Small modal To adjust the size of a modal, use the `variant` property. Modal variants include "small", "medium", "large", and "default". -In the following example, you can display each modal size option. To launch a modal with a specific size, first select the respective radio button, followed by the "Show modal" button. +The following example displays a "small" modal by passing in `variant={ModalVariant.small}`. + +```ts file="./ModalSmall.tsx" + +``` + +### Medium modal + +The following example displays a "medium" modal by passing in `variant={ModalVariant.medium}`. -```ts file="./ModalSize.tsx" +```ts file="./ModalMedium.tsx" + +``` + +### Large modal + +The following example displays a "large" modal by passing in `variant={ModalVariant.large}`. + +```ts file="./ModalLarge.tsx" ``` @@ -69,19 +83,17 @@ To choose a specific width for a modal, use the `width` property. The following ``` -### Custom header +### Custom header and footer -To add a custom header to a modal, your custom content must be passed as a child of the `` component. Do not pass the `title` property to `` when using a custom header. +To add a custom header and footer to a modal, set the `header` and `footer` properties to a custom implementation. The following example passes title components into both the header and the footer and also passes an icon to the footer. -```ts file="./ModalCustomHeader.tsx" +```ts file="./ModalCustomHeaderFooter.tsx" ``` ### No header or footer -To exclusively present information in a modal, remove the header and/or footer. - -When a modal has no header or footer, make sure to add an `aria-label` explicitly stating this, so that those using assistive technologies can understand this context. +To exclusively present information in a modal, remove the `header` and/or `footer`. ```ts file="./ModalNoHeaderFooter.tsx" @@ -89,7 +101,7 @@ When a modal has no header or footer, make sure to add an `aria-label` explicitl ### Title icon -To add an icon before a modal’s title, use the `titleIconVariant` property, which can be set to a "success", "danger", "warning", or "info" variant. The following example uses a "warning" variant. +To add an icon before a modal’s title, use the `titleIconVariant`, which can be set to one of the predefined variants -- "success", "danger", "warning", "info", and "custom" -- or to an imported custom icon. The following example uses a "warning" variant. ```ts file="./ModalTitleIcon.tsx" @@ -113,9 +125,7 @@ To guide users through a series of steps in a modal, you can add a [wizard](/com ### With dropdown -To present a menu of actions or links to a user, you can add a [dropdown](/components/menus/dropdown) to a modal. - -To allow the dropdown to visually break out of the modal container, set the `menuAppendTo` property to “parent”. Handle the modal’s closing behavior by listening to the `onEscapePress` callback on the `` component. This allows the "escape" key to collapse the dropdown without closing the entire modal. +To present a menu of actions or links to a user, you can add a [dropdown](/components/dropdown) to a modal. To allow the dropdown to visually break out of the modal container, set the `menuAppendTo` property to “parent”. Handle the modal’s closing behavior by listening to the `onEscapePress` callback on the `` component. This allows the "escape" key to collapse the dropdown without closing the entire modal. ```ts file="./ModalWithDropdown.tsx" @@ -131,9 +141,9 @@ To help simplify and explain complex models, add a help [popover](/components/po ### With form -To collect user input within a modal, you can add a [form](/components/forms/form). +To collect user input within a modal, you can add a [form](/components/form). -To enable form submission from a button in the modal's footer (outside of the `
`), set the button's `form` property equal to the form's id. +To submit the form from a button in the modal's footer (outside of the ``), set the button's `form` property equal to the form's id. ```ts file="ModalWithForm.tsx" @@ -141,7 +151,7 @@ To enable form submission from a button in the modal's footer (outside of the `< ### Custom focus -To customize which element inside the modal receives focus when initially opened, use the `elementToFocus` property`. +Use the `elementToFocus` property to customize which element inside the Modal receives focus when initially opened. ```ts file="./ModalCustomFocus.tsx" diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalBasic.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalBasic.tsx new file mode 100644 index 00000000000..8e7b5298bfe --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalBasic.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalBasic: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + ouiaId="BasicModal" + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + + + ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomFocus.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomFocus.tsx new file mode 100644 index 00000000000..7ca938b1fcd --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomFocus.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalCustomFocus: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + + + ); +}; diff --git a/packages/react-core/src/components/Modal/examples/ModalCustomHeaderFooter.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomHeaderFooter.tsx similarity index 88% rename from packages/react-core/src/components/Modal/examples/ModalCustomHeaderFooter.tsx rename to packages/react-core/src/deprecated/components/Modal/examples/ModalCustomHeaderFooter.tsx index 45339fafbad..74f01924750 100644 --- a/packages/react-core/src/components/Modal/examples/ModalCustomHeaderFooter.tsx +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomHeaderFooter.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Modal, ModalVariant, Button, Title, TitleSizes } from '@patternfly/react-core'; +import { Button, Title, TitleSizes } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; import WarningTriangleIcon from '@patternfly/react-icons/dist/esm/icons/warning-triangle-icon'; import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; @@ -31,8 +32,8 @@ export const ModalCustomHeaderFooter: React.FunctionComponent = () => { - { consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - + ); }; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomTitleIcon.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomTitleIcon.tsx new file mode 100644 index 00000000000..a01edd93e4f --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomTitleIcon.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; +import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; + +export const ModalCustomTitleIcon: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + > + + When static text describing the modal is available outside of the modal header, it can be given an ID that is + then passed in as the modal's aria-describedby value. + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. +
+
+ ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomWidth.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomWidth.tsx new file mode 100644 index 00000000000..18458649f7c --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalCustomWidth.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalCustomWidth: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + + + ); +}; diff --git a/packages/react-core/src/components/Modal/examples/ModalLarge.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalLarge.tsx similarity index 83% rename from packages/react-core/src/components/Modal/examples/ModalLarge.tsx rename to packages/react-core/src/deprecated/components/Modal/examples/ModalLarge.tsx index 6fd4c5ce24b..cf004f977cd 100644 --- a/packages/react-core/src/components/Modal/examples/ModalLarge.tsx +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalLarge.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Modal, ModalVariant, Button } from '@patternfly/react-core'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; export const ModalLarge: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -13,8 +14,8 @@ export const ModalLarge: React.FunctionComponent = () => { - { consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - + ); }; diff --git a/packages/react-core/src/components/Modal/examples/ModalMedium.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalMedium.tsx similarity index 83% rename from packages/react-core/src/components/Modal/examples/ModalMedium.tsx rename to packages/react-core/src/deprecated/components/Modal/examples/ModalMedium.tsx index 5be17eec2b1..d19cd26bf22 100644 --- a/packages/react-core/src/components/Modal/examples/ModalMedium.tsx +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalMedium.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Modal, ModalVariant, Button } from '@patternfly/react-core'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; export const ModalMedium: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -13,8 +14,8 @@ export const ModalMedium: React.FunctionComponent = () => { - { consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - + ); }; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalNoHeaderFooter.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalNoHeaderFooter.tsx new file mode 100644 index 00000000000..952e8349fb1 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalNoHeaderFooter.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalNoHeaderFooter: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + + When static text describing the modal is available outside of the modal header, it can be given an ID that is + then passed in as the modal's aria-describedby value. + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. +
+
+ ); +}; diff --git a/packages/react-core/src/components/Modal/examples/ModalSmall.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalSmall.tsx similarity index 83% rename from packages/react-core/src/components/Modal/examples/ModalSmall.tsx rename to packages/react-core/src/deprecated/components/Modal/examples/ModalSmall.tsx index 1bb9da550f3..09d21f96695 100644 --- a/packages/react-core/src/components/Modal/examples/ModalSmall.tsx +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalSmall.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Modal, ModalVariant, Button } from '@patternfly/react-core'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; export const ModalSmall: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -13,8 +14,8 @@ export const ModalSmall: React.FunctionComponent = () => { - { consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - + ); }; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalTitleIcon.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalTitleIcon.tsx new file mode 100644 index 00000000000..07310e4fa74 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalTitleIcon.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalTitleIcon: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + > + + When static text describing the modal is available outside of the modal header, it can be given an ID that is + then passed in as the modal's aria-describedby value. + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. +
+
+ ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalTopAligned.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalTopAligned.tsx new file mode 100644 index 00000000000..0aa93999e05 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalTopAligned.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalTopAligned: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + + + ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalWithDescription.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithDescription.tsx new file mode 100644 index 00000000000..7faa7f7c1f5 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithDescription.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalWithDescription: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + + + ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalWithDropdown.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithDropdown.tsx new file mode 100644 index 00000000000..bb6e2e84683 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithDropdown.tsx @@ -0,0 +1,100 @@ +import React from 'react'; +import { Button, Dropdown, DropdownList, DropdownItem, MenuToggle, MenuToggleElement } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalWithDropdown: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + const [isDropdownOpen, setIsDropdownOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + setIsDropdownOpen(false); + }; + + const handleDropdownToggle = () => { + setIsDropdownOpen(!isDropdownOpen); + }; + + const onSelect = () => { + setIsDropdownOpen(!isDropdownOpen); + onFocus(); + }; + + const onFocus = () => { + const element = document.getElementById('modal-dropdown-toggle'); + (element as HTMLElement).focus(); + }; + + const onEscapePress = (event: KeyboardEvent) => { + if (isDropdownOpen) { + setIsDropdownOpen(!isDropdownOpen); + onFocus(); + } else { + handleModalToggle(event); + } + }; + + return ( + + + + Confirm + , + + ]} + onEscapePress={onEscapePress} + > +
+ Set the dropdown menuAppendTo prop to parent in order to allow the dropdown menu + break out of the modal container. You'll also want to handle closing of the modal yourself, by listening to + the onEscapePress callback on the Modal component, so you can close the Dropdown first if + it's open without closing the entire modal. +
+
+
+ setIsDropdownOpen(isOpen)} + toggle={(toggleRef: React.Ref) => ( + + Dropdown + + )} + > + + + Action + + ev.preventDefault()} + > + Link + + + Disabled Action + + + Disabled Link + + + +
+
+
+ ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalWithForm.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithForm.tsx new file mode 100644 index 00000000000..90bd99720f9 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithForm.tsx @@ -0,0 +1,183 @@ +import React from 'react'; +import { Button, Form, FormGroup, FormGroupLabelHelp, Popover, TextInput } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalWithForm: React.FunctionComponent = () => { + const [isModalOpen, setModalOpen] = React.useState(false); + const [nameValue, setNameValue] = React.useState(''); + const [emailValue, setEmailValue] = React.useState(''); + const [addressValue, setAddressValue] = React.useState(''); + const nameLabelHelpRef = React.useRef(null); + const emailLabelHelpRef = React.useRef(null); + const addressLabelHelpRef = React.useRef(null); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setModalOpen(!isModalOpen); + }; + + const handleNameInputChange = (_event, value: string) => { + setNameValue(value); + }; + + const handleEmailInputChange = (_event, value: string) => { + setEmailValue(value); + }; + const handleAddressInputChange = (_event, value: string) => { + setAddressValue(value); + }; + + return ( + + + + Confirm + , + + ]} + > + + + The + + name + + of a + + Person + + + } + bodyContent={ +
+ Often composed of + + givenName + + and + + familyName + + . +
+ } + > + + + } + isRequired + fieldId="modal-with-form-form-name" + > + +
+ + The + + e-mail + + of a + + person + + + } + bodyContent={ +
+ Valid + + e-mail + + address. +
+ } + > + + + } + isRequired + fieldId="modal-with-form-form-email" + > + +
+ + The + + adress + + of a + + person + + + } + bodyContent={ + + } + > + + + } + isRequired + fieldId="modal-with-form-form-address" + > + + + +
+
+ ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalWithHelp.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithHelp.tsx new file mode 100644 index 00000000000..9a79cdbfe2d --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithHelp.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { Button, Popover } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + +import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; + +export const ModalWithHelp: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen(!isModalOpen); + }; + + return ( + + + Help Popover} + bodyContent={ +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis. +
+ } + footerContent="Popover Footer" + > + + + } + isOpen={isModalOpen} + onClose={handleModalToggle} + actions={[ + , + + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. +
+
+ ); +}; diff --git a/packages/react-core/src/deprecated/components/Modal/examples/ModalWithOverflowingContent.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithOverflowingContent.tsx new file mode 100644 index 00000000000..13ad2c54ac3 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithOverflowingContent.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { Button } from '@patternfly/react-core'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; + +export const ModalWithOverflowingContent: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + + const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen); + }; + + return ( + + + + Confirm + , + + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Semper auctor neque vitae tempus. + Diam donec adipiscing tristique risus. Augue eget arcu dictum varius duis. Ut enim blandit volutpat maecenas + volutpat blandit aliquam. Sit amet mauris commodo quis imperdiet massa tincidunt. Habitant morbi tristique + senectus et netus. Fames ac turpis egestas sed tempus urna. Neque laoreet suspendisse interdum consectetur + libero id. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Porta nibh venenatis cras sed felis eget + velit. Nullam non nisi est sit amet facilisis. Nunc mi ipsum faucibus vitae. Lorem sed risus ultricies tristique + nulla aliquet enim tortor at. Egestas sed tempus urna et pharetra pharetra massa massa ultricies. Lacinia quis + vel eros donec ac odio tempor orci. Malesuada fames ac turpis egestas integer eget aliquet. +
+
+ Neque aliquam vestibulum morbi blandit cursus risus at ultrices. Molestie at elementum eu facilisis sed odio + morbi. Elit pellentesque habitant morbi tristique. Consequat nisl vel pretium lectus quam id leo in vitae. Quis + varius quam quisque id diam vel quam elementum. Viverra nam libero justo laoreet sit amet cursus. Sollicitudin + tempor id eu nisl nunc. Orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim enim sit amet + venenatis urna cursus eget. Iaculis at erat pellentesque adipiscing commodo elit. Faucibus pulvinar elementum + integer enim neque volutpat. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Nunc mattis enim ut tellus + elementum sagittis vitae. Blandit cursus risus at ultrices. Tellus mauris a diam maecenas sed enim. Non diam + phasellus vestibulum lorem sed risus ultricies tristique nulla. +
+
+ Nulla pharetra diam sit amet nisl suscipit adipiscing. Ac tortor vitae purus faucibus ornare suspendisse sed + nisi. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt tortor aliquam nulla facilisi cras + fermentum. Volutpat est velit egestas dui id ornare arcu odio. Pharetra magna ac placerat vestibulum. Ultrices + sagittis orci a scelerisque purus semper eget duis at. Nisi est sit amet facilisis magna etiam tempor orci eu. + Convallis tellus id interdum velit. Facilisis sed odio morbi quis commodo odio aenean sed. +
+
+ Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Facilisi etiam dignissim diam quis enim + lobortis scelerisque fermentum. Eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada. Magna + etiam tempor orci eu lobortis elementum. Quis auctor elit sed vulputate mi sit. Eleifend quam adipiscing vitae + proin sagittis nisl rhoncus mattis rhoncus. Erat velit scelerisque in dictum non. Sit amet nulla facilisi morbi + tempus iaculis urna. Enim ut tellus elementum sagittis vitae et leo duis ut. Lectus arcu bibendum at varius vel + pharetra vel turpis. Morbi tristique senectus et netus et. Eget aliquet nibh praesent tristique magna sit amet + purus gravida. Nisl purus in mollis nunc sed id semper risus. Id neque aliquam vestibulum morbi. Mauris a diam + maecenas sed enim ut sem. Egestas tellus rutrum tellus pellentesque. +
+
+ ); +}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalWithWizard.tsx b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithWizard.tsx similarity index 84% rename from packages/react-core/src/next/components/Modal/examples/ModalWithWizard.tsx rename to packages/react-core/src/deprecated/components/Modal/examples/ModalWithWizard.tsx index f98c2410970..897fcb9dba0 100644 --- a/packages/react-core/src/next/components/Modal/examples/ModalWithWizard.tsx +++ b/packages/react-core/src/deprecated/components/Modal/examples/ModalWithWizard.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Button, Wizard, WizardHeader, WizardStep } from '@patternfly/react-core'; -import { Modal, ModalVariant } from '@patternfly/react-core/next'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; export const ModalWithWizard: React.FunctionComponent = () => { const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -24,11 +24,14 @@ export const ModalWithWizard: React.FunctionComponent = () => { - { title="Wizard modal" titleId="modal-wizard-label" description="This is a wizard inside of a modal." - descriptionId="modal-wizard-description" onClose={handleWizardToggle} closeButtonAriaLabel="Close wizard" /> @@ -53,7 +55,7 @@ export const ModalWithWizard: React.FunctionComponent = () => { Review step - + ); }; diff --git a/packages/react-core/src/deprecated/components/Modal/index.ts b/packages/react-core/src/deprecated/components/Modal/index.ts new file mode 100644 index 00000000000..d671375de62 --- /dev/null +++ b/packages/react-core/src/deprecated/components/Modal/index.ts @@ -0,0 +1,7 @@ +export * from './Modal'; +export * from './ModalBox'; +export * from './ModalBoxBody'; +export * from './ModalBoxCloseButton'; +export * from './ModalBoxHeader'; +export * from './ModalBoxFooter'; +export * from './ModalContent'; diff --git a/packages/react-core/src/deprecated/components/Wizard/Wizard.tsx b/packages/react-core/src/deprecated/components/Wizard/Wizard.tsx index 813cc6b2b41..8a5a3a71f2d 100644 --- a/packages/react-core/src/deprecated/components/Wizard/Wizard.tsx +++ b/packages/react-core/src/deprecated/components/Wizard/Wizard.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { KeyTypes } from '../../../helpers/constants'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Wizard/wizard'; -import { Modal, ModalVariant } from '../../../components/Modal'; +import { Modal, ModalVariant } from '../Modal'; import { WizardFooterInternal } from './WizardFooterInternal'; import { WizardToggle } from './WizardToggle'; import { WizardNav } from './WizardNav'; diff --git a/packages/react-core/src/deprecated/components/index.ts b/packages/react-core/src/deprecated/components/index.ts index 833cd9349dd..775bb6b3b27 100644 --- a/packages/react-core/src/deprecated/components/index.ts +++ b/packages/react-core/src/deprecated/components/index.ts @@ -1,3 +1,4 @@ export * from './Chip'; export * from './DragDrop'; +export * from './Modal'; export * from './Wizard'; diff --git a/packages/react-core/src/next/components/Modal/ModalContent.tsx b/packages/react-core/src/next/components/Modal/ModalContent.tsx deleted file mode 100644 index 5f8ff8831af..00000000000 --- a/packages/react-core/src/next/components/Modal/ModalContent.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import * as React from 'react'; -import { FocusTrap } from '../../../helpers'; -import bullsEyeStyles from '@patternfly/react-styles/css/layouts/Bullseye/bullseye'; -import { css } from '@patternfly/react-styles'; -import { getOUIAProps, OUIAProps } from '../../../helpers'; -import { Backdrop } from '../../../components/Backdrop'; -import { ModalBoxCloseButton } from './ModalBoxCloseButton'; -import { ModalBox } from './ModalBox'; - -export interface ModalContentProps extends OUIAProps { - /** Id to use for the modal box description. This should match the ModalHeader labelId or descriptorId. */ - 'aria-describedby'?: string; - /** Accessible descriptor of the modal. */ - 'aria-label'?: string; - /** Id to use for the modal box label. This should include the ModalHeader labelId. */ - 'aria-labelledby'?: string; - /** Id of the modal box container. */ - boxId: string; - /** Content rendered inside the modal. */ - children: React.ReactNode; - /** Additional classes added to the modal box. */ - className?: string; - /** Flag to disable focus trap. */ - disableFocusTrap?: boolean; - /** The element to focus when the modal opens. By default the first - * focusable element will receive focus. - */ - elementToFocus?: HTMLElement | SVGElement | string; - /** Flag to show the modal. */ - isOpen?: boolean; - /** A callback for when the close button is clicked. */ - onClose?: (event: KeyboardEvent | React.MouseEvent) => void; - /** Position of the modal. By default a modal will be positioned vertically and horizontally centered. */ - position?: 'default' | 'top'; - /** Offset from alternate position. Can be any valid CSS length/percentage. */ - positionOffset?: string; - /** Variant of the modal. */ - variant?: 'small' | 'medium' | 'large' | 'default'; - /** Default width of the modal. */ - width?: number | string; - /** Maximum width of the modal. */ - maxWidth?: number | string; - /** Value to overwrite the randomly generated data-ouia-component-id.*/ - ouiaId?: number | string; - /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ - ouiaSafe?: boolean; -} - -export const ModalContent: React.FunctionComponent = ({ - children, - className, - isOpen = false, - 'aria-label': ariaLabel, - 'aria-describedby': ariaDescribedby, - 'aria-labelledby': ariaLabelledby, - onClose, - variant = 'default', - position, - positionOffset, - width, - maxWidth, - boxId, - disableFocusTrap = false, - ouiaId, - ouiaSafe = true, - elementToFocus, - ...props -}: ModalContentProps) => { - if (!isOpen) { - return null; - } - - const ariaLabelledbyFormatted = (): string => { - const idRefList: string[] = []; - if (ariaLabel && boxId) { - idRefList.push(ariaLabel && boxId); - } - if (ariaLabelledby) { - idRefList.push(ariaLabelledby); - } - if (idRefList.length === 0) { - return undefined; - } else { - return idRefList.join(' '); - } - }; - - const modalBox = ( - - {onClose && onClose(event)} ouiaId={ouiaId} />} - {children} - - ); - return ( - - - {modalBox} - - - ); -}; -ModalContent.displayName = 'ModalContent'; diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalBoxHeader.test.tsx b/packages/react-core/src/next/components/Modal/__tests__/ModalBoxHeader.test.tsx deleted file mode 100644 index 5c724c9c1c3..00000000000 --- a/packages/react-core/src/next/components/Modal/__tests__/ModalBoxHeader.test.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from 'react'; -import { render } from '@testing-library/react'; - -import { ModalHeader } from '../ModalHeader'; - -test('ModalHeader Test', () => { - const { asFragment } = render(This is a ModalBox header); - expect(asFragment()).toMatchSnapshot(); -}); - -test('ModalHeader help renders', () => { - const { asFragment } = render(test}>This is a ModalBox header); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Test with custom header', () => { - const header = TEST; - - const { asFragment } = render({header}); - expect(asFragment()).toMatchSnapshot(); -}); diff --git a/packages/react-core/src/next/components/Modal/__tests__/ModalContent.test.tsx b/packages/react-core/src/next/components/Modal/__tests__/ModalContent.test.tsx deleted file mode 100644 index a3419ee83e0..00000000000 --- a/packages/react-core/src/next/components/Modal/__tests__/ModalContent.test.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import * as React from 'react'; -import { render } from '@testing-library/react'; - -import { ModalContent } from '../ModalContent'; - -const modalContentProps = { - boxId: 'boxId', - labelId: 'labelId', - descriptorId: 'descriptorId', - disableFocusTrap: true -}; -test('Modal Content Test only body', () => { - const { asFragment } = render( - - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Content Test isOpen', () => { - const { asFragment } = render( - - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Content Test description', () => { - const { asFragment } = render( - - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); - -test('Modal Content Test with onclose', () => { - const { asFragment } = render( - undefined} isOpen {...modalContentProps}> - This is a ModalBox header - - ); - expect(asFragment()).toMatchSnapshot(); -}); diff --git a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalContent.test.tsx.snap b/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalContent.test.tsx.snap deleted file mode 100644 index 0f3665d262f..00000000000 --- a/packages/react-core/src/next/components/Modal/__tests__/__snapshots__/ModalContent.test.tsx.snap +++ /dev/null @@ -1,128 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Modal Content Test description 1`] = ` - -
-
- -
-
-
-`; - -exports[`Modal Content Test isOpen 1`] = ` - -
-
- -
-
-
-`; - -exports[`Modal Content Test only body 1`] = ` - -
-
- -
-
-
-`; - -exports[`Modal Content Test with onclose 1`] = ` - -
-
- -
-
-
-`; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalBasic.tsx b/packages/react-core/src/next/components/Modal/examples/ModalBasic.tsx deleted file mode 100644 index 9b325381132..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalBasic.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/next'; - -export const ModalBasic: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - - - - - - - ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalCustomFocus.tsx b/packages/react-core/src/next/components/Modal/examples/ModalCustomFocus.tsx deleted file mode 100644 index 83c63796eb7..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalCustomFocus.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/next'; - -export const ModalCustomFocus: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - - - - - - - ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalCustomTitleIcon.tsx b/packages/react-core/src/next/components/Modal/examples/ModalCustomTitleIcon.tsx deleted file mode 100644 index c70c38ac052..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalCustomTitleIcon.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/next'; - -import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; - -export const ModalCustomTitleIcon: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - - When static text describing the modal is available outside of the modal header, it can be given an ID that - is then passed in as the modal's aria-describedby value. - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. -
- - - - -
-
- ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalCustomWidth.tsx b/packages/react-core/src/next/components/Modal/examples/ModalCustomWidth.tsx deleted file mode 100644 index b9cc3bdb9ad..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalCustomWidth.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/next'; - -export const ModalCustomWidth: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - - - - - - - ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalNoHeaderFooter.tsx b/packages/react-core/src/next/components/Modal/examples/ModalNoHeaderFooter.tsx deleted file mode 100644 index 17d07538cf1..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalNoHeaderFooter.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalVariant } from '@patternfly/react-core/next'; - -export const ModalNoHeaderFooter: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - When static text describing the modal is available outside of the modal header, it can be given an ID that - is then passed in as the modal's aria-describedby value. - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. -
-
-
- ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalTitleIcon.tsx b/packages/react-core/src/next/components/Modal/examples/ModalTitleIcon.tsx deleted file mode 100644 index 6c96a5c6ed6..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalTitleIcon.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/next'; - -export const ModalTitleIcon: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - - When static text describing the modal is available outside of the modal header, it can be given an ID that - is then passed in as the modal's aria-describedby value. - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. -
- - - - -
-
- ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalTopAligned.tsx b/packages/react-core/src/next/components/Modal/examples/ModalTopAligned.tsx deleted file mode 100644 index 551f36bc9a6..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalTopAligned.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/next'; - -export const ModalTopAligned: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - - - - - - - ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalWithDescription.tsx b/packages/react-core/src/next/components/Modal/examples/ModalWithDescription.tsx deleted file mode 100644 index 5de229d938a..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalWithDescription.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalHeader, ModalFooter, ModalVariant } from '@patternfly/react-core/next'; - -export const ModalWithDescription: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Semper auctor neque vitae - tempus. Diam donec adipiscing tristique risus. Augue eget arcu dictum varius duis. Ut enim blandit volutpat - maecenas volutpat blandit aliquam. Sit amet mauris commodo quis imperdiet massa tincidunt. Habitant morbi - tristique senectus et netus. Fames ac turpis egestas sed tempus urna. Neque laoreet suspendisse interdum - consectetur libero id. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Porta nibh venenatis cras - sed felis eget velit. Nullam non nisi est sit amet facilisis. Nunc mi ipsum faucibus vitae. Lorem sed risus - ultricies tristique nulla aliquet enim tortor at. Egestas sed tempus urna et pharetra pharetra massa massa - ultricies. Lacinia quis vel eros donec ac odio tempor orci. Malesuada fames ac turpis egestas integer eget - aliquet. -
-
- Neque aliquam vestibulum morbi blandit cursus risus at ultrices. Molestie at elementum eu facilisis sed odio - morbi. Elit pellentesque habitant morbi tristique. Consequat nisl vel pretium lectus quam id leo in vitae. - Quis varius quam quisque id diam vel quam elementum. Viverra nam libero justo laoreet sit amet cursus. - Sollicitudin tempor id eu nisl nunc. Orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim enim - sit amet venenatis urna cursus eget. Iaculis at erat pellentesque adipiscing commodo elit. Faucibus pulvinar - elementum integer enim neque volutpat. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Nunc mattis - enim ut tellus elementum sagittis vitae. Blandit cursus risus at ultrices. Tellus mauris a diam maecenas sed - enim. Non diam phasellus vestibulum lorem sed risus ultricies tristique nulla. -
-
- Nulla pharetra diam sit amet nisl suscipit adipiscing. Ac tortor vitae purus faucibus ornare suspendisse sed - nisi. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt tortor aliquam nulla facilisi cras - fermentum. Volutpat est velit egestas dui id ornare arcu odio. Pharetra magna ac placerat vestibulum. Ultrices - sagittis orci a scelerisque purus semper eget duis at. Nisi est sit amet facilisis magna etiam tempor orci eu. - Convallis tellus id interdum velit. Facilisis sed odio morbi quis commodo odio aenean sed. -
-
- Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Facilisi etiam dignissim diam quis enim - lobortis scelerisque fermentum. Eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada. Magna - etiam tempor orci eu lobortis elementum. Quis auctor elit sed vulputate mi sit. Eleifend quam adipiscing vitae - proin sagittis nisl rhoncus mattis rhoncus. Erat velit scelerisque in dictum non. Sit amet nulla facilisi - morbi tempus iaculis urna. Enim ut tellus elementum sagittis vitae et leo duis ut. Lectus arcu bibendum at - varius vel pharetra vel turpis. Morbi tristique senectus et netus et. Eget aliquet nibh praesent tristique - magna sit amet purus gravida. Nisl purus in mollis nunc sed id semper risus. Id neque aliquam vestibulum - morbi. Mauris a diam maecenas sed enim ut sem. Egestas tellus rutrum tellus pellentesque. -
- - - - -
-
- ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalWithDropdown.tsx b/packages/react-core/src/next/components/Modal/examples/ModalWithDropdown.tsx deleted file mode 100644 index 53be83c889d..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalWithDropdown.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react'; -import { Button, Dropdown, DropdownList, DropdownItem, MenuToggle, MenuToggleElement } from '@patternfly/react-core'; - -import { Modal, ModalBody, ModalHeader, ModalFooter, ModalVariant } from '@patternfly/react-core/next'; - -export const ModalWithDropdown: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - const [isDropdownOpen, setIsDropdownOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - setIsDropdownOpen(false); - }; - - const handleDropdownToggle = () => { - setIsDropdownOpen(!isDropdownOpen); - }; - - const onSelect = () => { - setIsDropdownOpen(!isDropdownOpen); - onFocus(); - }; - - const onFocus = () => { - const element = document.getElementById('modal-dropdown-toggle'); - (element as HTMLElement).focus(); - }; - - const onEscapePress = (event: KeyboardEvent) => { - if (isDropdownOpen) { - setIsDropdownOpen(!isDropdownOpen); - onFocus(); - } else { - handleModalToggle(event); - } - }; - - return ( - - - - - -
- Set the dropdown menuAppendTo prop to parent in order to allow the dropdown menu - break out of the modal container. You'll also want to handle closing of the modal yourself, by listening to - the onEscapePress callback on the Modal component, so you can close the Dropdown first if - it's open without closing the entire modal. -
-
-
- setIsDropdownOpen(isOpen)} - toggle={(toggleRef: React.Ref) => ( - - Dropdown - - )} - > - - - Action - - ev.preventDefault()} - > - Link - - - Disabled Action - - - Disabled Link - - - -
-
- - - - -
-
- ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalWithForm.tsx b/packages/react-core/src/next/components/Modal/examples/ModalWithForm.tsx deleted file mode 100644 index b5e23b1d7cc..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalWithForm.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import React from 'react'; -import { Button, Form, FormGroup, FormGroupLabelHelp, Popover, TextInput } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant } from '@patternfly/react-core/next'; - -export const ModalWithForm: React.FunctionComponent = () => { - const [isModalOpen, setModalOpen] = React.useState(false); - const [nameValue, setNameValue] = React.useState(''); - const [emailValue, setEmailValue] = React.useState(''); - const [addressValue, setAddressValue] = React.useState(''); - const nameLabelHelpRef = React.useRef(null); - const emailLabelHelpRef = React.useRef(null); - const addressLabelHelpRef = React.useRef(null); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setModalOpen(!isModalOpen); - }; - - const handleNameInputChange = (_event, value: string) => { - setNameValue(value); - }; - - const handleEmailInputChange = (_event, value: string) => { - setEmailValue(value); - }; - const handleAddressInputChange = (_event, value: string) => { - setAddressValue(value); - }; - - return ( - - - - - - - - - - - - - - ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalWithHelp.tsx b/packages/react-core/src/next/components/Modal/examples/ModalWithHelp.tsx deleted file mode 100644 index c9952f2ab2f..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalWithHelp.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react'; -import { Button, Popover } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/next'; -import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; - -export const ModalWithHelp: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen(!isModalOpen); - }; - - return ( - - - - Help Popover} - bodyContent={ -
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla - turpis. -
- } - footerContent="Popover Footer" - > - - - } - /> - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - - - - -
-
- ); -}; diff --git a/packages/react-core/src/next/components/Modal/examples/ModalWithOverflowingContent.tsx b/packages/react-core/src/next/components/Modal/examples/ModalWithOverflowingContent.tsx deleted file mode 100644 index 2a2808b34cd..00000000000 --- a/packages/react-core/src/next/components/Modal/examples/ModalWithOverflowingContent.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; -import { Button } from '@patternfly/react-core'; -import { Modal, ModalBody, ModalHeader, ModalFooter, ModalVariant } from '@patternfly/react-core/next'; - -export const ModalWithOverflowingContent: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); - - const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen); - }; - - return ( - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Semper auctor neque vitae - tempus. Diam donec adipiscing tristique risus. Augue eget arcu dictum varius duis. Ut enim blandit volutpat - maecenas volutpat blandit aliquam. Sit amet mauris commodo quis imperdiet massa tincidunt. Habitant morbi - tristique senectus et netus. Fames ac turpis egestas sed tempus urna. Neque laoreet suspendisse interdum - consectetur libero id. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Porta nibh venenatis cras - sed felis eget velit. Nullam non nisi est sit amet facilisis. Nunc mi ipsum faucibus vitae. Lorem sed risus - ultricies tristique nulla aliquet enim tortor at. Egestas sed tempus urna et pharetra pharetra massa massa - ultricies. Lacinia quis vel eros donec ac odio tempor orci. Malesuada fames ac turpis egestas integer eget - aliquet. -
-
- Neque aliquam vestibulum morbi blandit cursus risus at ultrices. Molestie at elementum eu facilisis sed odio - morbi. Elit pellentesque habitant morbi tristique. Consequat nisl vel pretium lectus quam id leo in vitae. - Quis varius quam quisque id diam vel quam elementum. Viverra nam libero justo laoreet sit amet cursus. - Sollicitudin tempor id eu nisl nunc. Orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim enim - sit amet venenatis urna cursus eget. Iaculis at erat pellentesque adipiscing commodo elit. Faucibus pulvinar - elementum integer enim neque volutpat. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Nunc mattis - enim ut tellus elementum sagittis vitae. Blandit cursus risus at ultrices. Tellus mauris a diam maecenas sed - enim. Non diam phasellus vestibulum lorem sed risus ultricies tristique nulla. -
-
- Nulla pharetra diam sit amet nisl suscipit adipiscing. Ac tortor vitae purus faucibus ornare suspendisse sed - nisi. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt tortor aliquam nulla facilisi cras - fermentum. Volutpat est velit egestas dui id ornare arcu odio. Pharetra magna ac placerat vestibulum. Ultrices - sagittis orci a scelerisque purus semper eget duis at. Nisi est sit amet facilisis magna etiam tempor orci eu. - Convallis tellus id interdum velit. Facilisis sed odio morbi quis commodo odio aenean sed. -
-
- Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Facilisi etiam dignissim diam quis enim - lobortis scelerisque fermentum. Eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada. Magna - etiam tempor orci eu lobortis elementum. Quis auctor elit sed vulputate mi sit. Eleifend quam adipiscing vitae - proin sagittis nisl rhoncus mattis rhoncus. Erat velit scelerisque in dictum non. Sit amet nulla facilisi - morbi tempus iaculis urna. Enim ut tellus elementum sagittis vitae et leo duis ut. Lectus arcu bibendum at - varius vel pharetra vel turpis. Morbi tristique senectus et netus et. Eget aliquet nibh praesent tristique - magna sit amet purus gravida. Nisl purus in mollis nunc sed id semper risus. Id neque aliquam vestibulum - morbi. Mauris a diam maecenas sed enim ut sem. Egestas tellus rutrum tellus pellentesque. -
- - - - -
-
- ); -}; diff --git a/packages/react-core/src/next/components/Modal/index.ts b/packages/react-core/src/next/components/Modal/index.ts deleted file mode 100644 index 14ff043038d..00000000000 --- a/packages/react-core/src/next/components/Modal/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './Modal'; -export * from './ModalBody'; -export * from './ModalHeader'; -export * from './ModalFooter'; diff --git a/packages/react-core/src/next/components/index.ts b/packages/react-core/src/next/components/index.ts index aca5eccab6c..00d4164b54b 100644 --- a/packages/react-core/src/next/components/index.ts +++ b/packages/react-core/src/next/components/index.ts @@ -1,2 +1 @@ -export * from './Modal'; export * from './DualListSelector'; diff --git a/packages/react-integration/cypress/integration/modalnext.spec.ts b/packages/react-integration/cypress/integration/modal-deprecated.spec.ts similarity index 97% rename from packages/react-integration/cypress/integration/modalnext.spec.ts rename to packages/react-integration/cypress/integration/modal-deprecated.spec.ts index 1fa47aebf0d..094db294560 100644 --- a/packages/react-integration/cypress/integration/modalnext.spec.ts +++ b/packages/react-integration/cypress/integration/modal-deprecated.spec.ts @@ -1,6 +1,6 @@ describe('Modal Test', () => { - it('Navigate to Modal next section', () => { - cy.visit('http://localhost:3000/modal-next-demo-nav-link'); + it('Navigate to Modal deprecated section', () => { + cy.visit('http://localhost:3000/modal-deprecated-demo-nav-link'); }); it('Verify Half Width Modal', () => { @@ -58,12 +58,12 @@ describe('Modal Test', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore cy.tab(); - cy.focused().should('have.attr', 'data-id', 'modal-01-confirm-btn'); + cy.focused().should('have.attr', 'data-id', 'modal-01-cancel-btn'); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore cy.tab(); - cy.focused().should('have.attr', 'data-id', 'modal-01-cancel-btn'); + cy.focused().should('have.attr', 'data-id', 'modal-01-confirm-btn'); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/packages/react-integration/cypress/integration/modal.spec.ts b/packages/react-integration/cypress/integration/modal.spec.ts index 728333af0bc..fc0f9ab67fa 100644 --- a/packages/react-integration/cypress/integration/modal.spec.ts +++ b/packages/react-integration/cypress/integration/modal.spec.ts @@ -58,12 +58,12 @@ describe('Modal Test', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore cy.tab(); - cy.focused().should('have.attr', 'data-id', 'modal-01-cancel-btn'); + cy.focused().should('have.attr', 'data-id', 'modal-01-confirm-btn'); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore cy.tab(); - cy.focused().should('have.attr', 'data-id', 'modal-01-confirm-btn'); + cy.focused().should('have.attr', 'data-id', 'modal-01-cancel-btn'); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/packages/react-integration/demo-app-ts/src/Demos.ts b/packages/react-integration/demo-app-ts/src/Demos.ts index d0a0ae8c558..3222738b3c3 100644 --- a/packages/react-integration/demo-app-ts/src/Demos.ts +++ b/packages/react-integration/demo-app-ts/src/Demos.ts @@ -228,14 +228,14 @@ export const Demos: DemoInterface[] = [ componentType: Examples.MenuDrilldownDemo }, { - id: 'modal-demo', + id: 'modal-deprecated-demo', name: 'Modal Demo', - componentType: Examples.ModalDemo + componentType: Examples.ModalDeprecatedDemo }, { - id: 'modal-next-demo', - name: 'Modal Next Demo', - componentType: Examples.ModalNextDemo + id: 'modal-demo', + name: 'Modal Demo', + componentType: Examples.ModalDemo }, { id: 'nav-demo', diff --git a/packages/react-integration/demo-app-ts/src/components/demos/ModalDemo/ModalDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/ModalDemo/ModalDemo.tsx index 2ed67c10aa6..0ce1a68b6b1 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/ModalDemo/ModalDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/ModalDemo/ModalDemo.tsx @@ -1,5 +1,14 @@ import React from 'react'; -import { Modal, ModalVariant, Button, Title, TitleSizes } from '@patternfly/react-core'; +import { + Button, + Modal, + ModalHeader, + ModalBody, + ModalFooter, + ModalVariant, + Title, + TitleSizes +} from '@patternfly/react-core'; import WarningTriangleIcon from '@patternfly/react-icons/dist/esm/icons/warning-triangle-icon'; import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; @@ -122,23 +131,27 @@ export class ModalDemo extends React.Component, return ( - Cancel - , + aria-labelledby="basic-modal-title" + aria-describedby="modal-box-body-basic" + > + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -148,26 +161,34 @@ export class ModalDemo extends React.Component, return ( + - Cancel - , + descriptorId="modal-box-with-description-descriptor" + /> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - id="test-modal-id" - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -179,23 +200,27 @@ export class ModalDemo extends React.Component, - Cancel - , + aria-labelledby="small-modal-title" + aria-describedby="modal-box-body-small" + > + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -206,23 +231,27 @@ export class ModalDemo extends React.Component, return ( - Cancel - , + aria-labelledby="medium-modal-title" + aria-describedby="modal-box-body-medium" + > + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -233,23 +262,27 @@ export class ModalDemo extends React.Component, return ( - Cancel - , + aria-labelledby="large-modal-title" + aria-describedby="modal-box-body-large" + > + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -260,23 +293,27 @@ export class ModalDemo extends React.Component, return ( - Cancel - , + aria-labelledby="half-width-modal-title" + aria-describedby="modal-box-body-half-width" + > + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -284,44 +321,38 @@ export class ModalDemo extends React.Component, renderCustomHeaderFooterModal() { const { isCustomHeaderFooterModalOpen } = this.state; - const header = ( - - - Custom Modal Header/Footer - -

- Allows for custom content in the header and/or footer by passing components. -

-
- ); - - const footer = ( - - <WarningTriangleIcon /> - <span className={spacing.plSm}>Custom modal footer.</span> - - ); - return ( - - When static text describing the modal is available, it can be wrapped with an ID referring to the modal's - aria-describedby value. - -
-
- Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis - aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint - occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + + + Custom Modal Header/Footer + +

+ Allows for custom content in the header and/or footer by passing components. +

+
+ + + When static text describing the modal is available, it can be wrapped with an ID referring to the modal's + aria-describedby value. + +
+
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +
+ + + <WarningTriangleIcon /> + <span className={spacing.plSm}>Custom modal footer.</span> + +
); } @@ -336,19 +367,21 @@ export class ModalDemo extends React.Component, isOpen={isNoHeaderModalOpen} aria-describedby="no-header-example" onClose={this.handleNoHeaderModalToggle} - actions={[ + > + + + When static text describing the modal is available, it can be wrapped with an ID referring to the modal's + aria-describedby value. + {' '} + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + + - ]} - > - - When static text describing the modal is available, it can be wrapped with an ID referring to the modal's - aria-describedby value. - {' '} - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis - aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint - occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +
); } @@ -358,25 +391,28 @@ export class ModalDemo extends React.Component, return ( - Cancel - , + onEscapePress={(event: any) => this.handleModalCustomEscapeToggle(event, true)} + aria-labelledby="custom-escape-modal-title" + > + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - onEscapePress={(event: any) => this.handleModalCustomEscapeToggle(event, true)} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -386,25 +422,27 @@ export class ModalDemo extends React.Component, return ( - Cancel - , + aria-describedby="modal-box-body-alert" + aria-labelledby="alert-modal-title" + > + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -415,25 +453,28 @@ export class ModalDemo extends React.Component, return ( Help} position="top" - title="Modal Header" isOpen={isHelpModalOpen} onClose={this.handleHelpModalToggle} - actions={[ - , + aria-describedby="modal-box-body-help" + aria-labelledby="help-modal-title" + > + Help} /> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + + ); } @@ -444,10 +485,24 @@ export class ModalDemo extends React.Component, return ( + Help} + /> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. + + , + - ]} - > - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. + ); } diff --git a/packages/react-integration/demo-app-ts/src/components/demos/ModalNextDemo/ModalNextDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/ModalDeprecatedDemo/ModalDeprecatedDemo.tsx similarity index 50% rename from packages/react-integration/demo-app-ts/src/components/demos/ModalNextDemo/ModalNextDemo.tsx rename to packages/react-integration/demo-app-ts/src/components/demos/ModalDeprecatedDemo/ModalDeprecatedDemo.tsx index e14b75efec0..aca2d85826a 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/ModalNextDemo/ModalNextDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/ModalDeprecatedDemo/ModalDeprecatedDemo.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Button, Title, TitleSizes } from '@patternfly/react-core'; -import { Modal, ModalHeader, ModalBody, ModalFooter, ModalVariant } from '@patternfly/react-core/next'; +import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated'; import WarningTriangleIcon from '@patternfly/react-icons/dist/esm/icons/warning-triangle-icon'; import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; @@ -21,7 +21,7 @@ interface ModalDemoState { } // eslint-disable-next-line patternfly-react/no-anonymous-functions -export class ModalNextDemo extends React.Component, ModalDemoState> { +export class ModalDeprecatedDemo extends React.Component, ModalDemoState> { static displayName = 'ModalDemo'; state = { @@ -122,29 +122,25 @@ export class ModalNextDemo extends React.Component - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - -
+ ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -152,36 +148,28 @@ export class ModalNextDemo extends React.Component - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - -
+ ]} + id="test-modal-id" + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -189,31 +177,27 @@ export class ModalNextDemo extends React.Component - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - - + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -221,30 +205,26 @@ export class ModalNextDemo extends React.Component - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - - + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -252,30 +232,26 @@ export class ModalNextDemo extends React.Component - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - - + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -283,69 +259,71 @@ export class ModalNextDemo extends React.Component - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - - + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } renderCustomHeaderFooterModal() { const { isCustomHeaderFooterModalOpen } = this.state; + const header = ( + + + Custom Modal Header/Footer + +

+ Allows for custom content in the header and/or footer by passing components. +

+
+ ); + + const footer = ( + + <WarningTriangleIcon /> + <span className={spacing.plSm}>Custom modal footer.</span> + + ); + return ( - - - - Custom Modal Header/Footer - -

- Allows for custom content in the header and/or footer by passing components. -

-
- - - When static text describing the modal is available, it can be wrapped with an ID referring to the modal's - aria-describedby value. - -
-
- Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -
- - - <WarningTriangleIcon /> - <span className={spacing.plSm}>Custom modal footer.</span> - - -
+ + When static text describing the modal is available, it can be wrapped with an ID referring to the modal's + aria-describedby value. + +
+
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis + aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + ); } @@ -353,28 +331,26 @@ export class ModalNextDemo extends React.Component - - - When static text describing the modal is available, it can be wrapped with an ID referring to the modal's - aria-describedby value. - {' '} - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - - + actions={[ - - + ]} + > + + When static text describing the modal is available, it can be wrapped with an ID referring to the modal's + aria-describedby value. + {' '} + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis + aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + ); } @@ -382,30 +358,27 @@ export class ModalNextDemo extends React.Component this.handleModalCustomEscapeToggle(event, true)} - aria-labelledby="custom-escape-modal-title" - > - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - - + ]} + onEscapePress={(event: any) => this.handleModalCustomEscapeToggle(event, true)} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -413,29 +386,27 @@ export class ModalNextDemo extends React.Component - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + aria-describedby="custom-escape-example" + actions={[ + , - - - + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -443,31 +414,28 @@ export class ModalNextDemo extends React.ComponentHelp} position="top" + title="Modal Header" isOpen={isHelpModalOpen} onClose={this.handleHelpModalToggle} - aria-describedby="modal-box-body-help" - aria-labelledby="help-modal-title" - > - Help} /> - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - - + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } @@ -475,26 +443,12 @@ export class ModalNextDemo extends React.Component - Help} - /> - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. - - + actions={[ + , - - + ]} + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + ); } diff --git a/packages/react-integration/demo-app-ts/src/components/demos/WizardDemo/WizardDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/WizardDemo/WizardDemo.tsx index 4f750e8bb69..2af9653cc84 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/WizardDemo/WizardDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/WizardDemo/WizardDemo.tsx @@ -1,5 +1,7 @@ import React from 'react'; -import { Button, Modal, Wizard, WizardHeader, WizardStep } from '@patternfly/react-core'; +import { Button, Wizard, WizardHeader, WizardStep } from '@patternfly/react-core'; +import { Modal as ModalDeprecated } from '@patternfly/react-core/deprecated'; + import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon'; import SlackHashIcon from '@patternfly/react-icons/dist/esm/icons/slack-hash-icon'; @@ -36,7 +38,7 @@ class WizardDemo extends React.Component, Wizard - + , Wizard

Step 5

-
+

@@ -239,7 +241,12 @@ class WizardDemo extends React.Component, Wizard - + , Wizard - + ); } diff --git a/packages/react-integration/demo-app-ts/src/components/demos/index.ts b/packages/react-integration/demo-app-ts/src/components/demos/index.ts index 08091dad472..64a7f6283bd 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/index.ts +++ b/packages/react-integration/demo-app-ts/src/components/demos/index.ts @@ -41,8 +41,8 @@ export * from './LoginPageDemo/LoginPageDemo'; export * from './MastheadDemo/MastheadDemo'; export * from './MenuDemo/MenuDemo'; export * from './MenuDemo/MenuDrilldownDemo'; +export * from './ModalDeprecatedDemo/ModalDeprecatedDemo'; export * from './ModalDemo/ModalDemo'; -export * from './ModalNextDemo/ModalNextDemo'; export * from './NavDemo/NavDemo'; export * from './NotificationBadgeDemo/NotificationBadgeDemo'; export * from './NotificationDrawerDemo/NotificationDrawerBasicDemo';