From 8b4ba0980f3ec44d262626380eb64eb1e660895a Mon Sep 17 00:00:00 2001 From: Rajat Date: Fri, 12 Jan 2024 00:59:52 +0530 Subject: [PATCH] fix: Modal Close button a11y issues (#15057) * fix: modal close button * fix: spacing * fix: changes * chore: refactor closeButtonLabel default * feat(IconButton): add TypeScript types * chore(modal): improve types * fix(Button): adjust typescript types of Button and IconButton * test(react): update index-test.js with new export * chore(test): update snapshots * style(ComposedModal): add new classes to ComposedModal to fix alignment --------- Co-authored-by: Taylor Jones Co-authored-by: Taylor Jones Co-authored-by: Joseph D. Harvey Co-authored-by: TJ Egan Co-authored-by: Joe Harvey <51208233+jdharvey-ibm@users.noreply.github.com> --- .../__snapshots__/PublicAPI-test.js.snap | 6 + packages/react/src/__tests__/index-test.js | 1 + .../react/src/components/Button/Button.tsx | 27 +++-- .../ComposedModal/ComposedModal.tsx | 1 - .../components/ComposedModal/ModalHeader.tsx | 25 ++-- .../components/DangerButton/DangerButton.tsx | 5 +- .../IconButton/{index.js => index.tsx} | 108 ++++++++++++++++-- packages/react/src/components/Modal/Modal.tsx | 34 +++--- .../styles/scss/components/modal/_modal.scss | 12 +- 9 files changed, 171 insertions(+), 48 deletions(-) rename packages/react/src/components/IconButton/{index.js => index.tsx} (56%) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 8b4192c9b5f6..2b9fdb161faa 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -4133,6 +4133,12 @@ Map { }, "render": [Function], }, + "IconButtonKinds" => Object { + "0": "primary", + "1": "secondary", + "2": "ghost", + "3": "tertiary", + }, "IconSkeleton" => Object { "propTypes": Object { "className": Object { diff --git a/packages/react/src/__tests__/index-test.js b/packages/react/src/__tests__/index-test.js index ad6feeee9876..78eacda17385 100644 --- a/packages/react/src/__tests__/index-test.js +++ b/packages/react/src/__tests__/index-test.js @@ -93,6 +93,7 @@ describe('Carbon Components React', () => { "HeaderSideNavItems", "Heading", "IconButton", + "IconButtonKinds", "IconSkeleton", "IconSwitch", "IconTab", diff --git a/packages/react/src/components/Button/Button.tsx b/packages/react/src/components/Button/Button.tsx index 260a92943ddb..4bd08a0215fc 100644 --- a/packages/react/src/components/Button/Button.tsx +++ b/packages/react/src/components/Button/Button.tsx @@ -8,7 +8,7 @@ import PropTypes from 'prop-types'; import React, { useRef } from 'react'; import classNames from 'classnames'; -import { IconButton } from '../IconButton'; +import { IconButton, IconButtonKind } from '../IconButton'; import { composeEventHandlers } from '../../tools/events'; import { usePrefix } from '../../internal/usePrefix'; import { useId } from '../../internal/useId'; @@ -107,11 +107,20 @@ export type ButtonProps = PolymorphicProps< ButtonBaseProps >; -export interface ButtonComponent { - ( - props: ButtonProps, - context?: any - ): React.ReactElement | null; +export type ButtonComponent = ( + props: ButtonProps, + context?: any +) => React.ReactElement | null; + +function isIconOnlyButton( + hasIconOnly: ButtonBaseProps['hasIconOnly'], + _kind: ButtonBaseProps['kind'] +): _kind is IconButtonKind { + if (hasIconOnly === true) { + return true; + } + + return false; } const Button = React.forwardRef(function Button( @@ -149,7 +158,6 @@ const Button = React.forwardRef(function Button( // Prevent clicks on the tooltip from triggering the button click event if (evt.target === tooltipRef.current) { evt.preventDefault(); - return; } }; @@ -221,7 +229,7 @@ const Button = React.forwardRef(function Button( otherProps = anchorProps; } - if (!hasIconOnly) { + if (!isIconOnlyButton(hasIconOnly, kind)) { return React.createElement( component, { @@ -272,7 +280,7 @@ const Button = React.forwardRef(function Button( {...rest} {...commonProps} {...otherProps}> - {iconOnlyImage ? iconOnlyImage : children} + {iconOnlyImage ?? children} ); } @@ -346,6 +354,7 @@ Button.propTypes = { /** * Specify the kind of Button you want to create */ + // TODO: this should be either ButtonKinds or IconButtonKinds based on the value of "hasIconOnly" kind: PropTypes.oneOf(ButtonKinds), /** diff --git a/packages/react/src/components/ComposedModal/ComposedModal.tsx b/packages/react/src/components/ComposedModal/ComposedModal.tsx index 8a44f827ef73..35d3f4ab4dfe 100644 --- a/packages/react/src/components/ComposedModal/ComposedModal.tsx +++ b/packages/react/src/components/ComposedModal/ComposedModal.tsx @@ -13,7 +13,6 @@ import { isElement } from 'react-is'; import PropTypes, { ReactNodeLike } from 'prop-types'; import { ModalHeader, type ModalHeaderProps } from './ModalHeader'; import { ModalFooter, type ModalFooterProps } from './ModalFooter'; - import cx from 'classnames'; import toggleClass from '../../tools/toggleClass'; diff --git a/packages/react/src/components/ComposedModal/ModalHeader.tsx b/packages/react/src/components/ComposedModal/ModalHeader.tsx index 1ddbc044454f..0f57c94ba9a2 100644 --- a/packages/react/src/components/ComposedModal/ModalHeader.tsx +++ b/packages/react/src/components/ComposedModal/ModalHeader.tsx @@ -14,6 +14,7 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import { Close } from '@carbon/icons-react'; import { usePrefix } from '../../internal/usePrefix'; +import { IconButton } from '../IconButton'; type DivProps = Omit, 'title'>; export interface ModalHeaderProps extends DivProps { @@ -127,14 +128,22 @@ export const ModalHeader = React.forwardRef( {children} - +
+ + +
); } diff --git a/packages/react/src/components/DangerButton/DangerButton.tsx b/packages/react/src/components/DangerButton/DangerButton.tsx index 5e863c5bf15c..c9cd236783d5 100644 --- a/packages/react/src/components/DangerButton/DangerButton.tsx +++ b/packages/react/src/components/DangerButton/DangerButton.tsx @@ -10,6 +10,9 @@ import Button, { ButtonComponent, ButtonProps } from '../Button'; const DangerButton: ButtonComponent = ( props: ButtonProps -) => +
+ + +
); const modalBody = ( diff --git a/packages/styles/scss/components/modal/_modal.scss b/packages/styles/scss/components/modal/_modal.scss index e1cd4736baf5..a5a45e7f1b09 100644 --- a/packages/styles/scss/components/modal/_modal.scss +++ b/packages/styles/scss/components/modal/_modal.scss @@ -434,18 +434,20 @@ // ----------------------------- // Modal close btn // ----------------------------- - .#{$prefix}--modal-close { + + .#{$prefix}--modal-close-button { position: absolute; - z-index: 2; - overflow: hidden; + inset-block-start: 0; + inset-inline-end: 0; + } + + .#{$prefix}--modal-close { padding: convert.to-rem(12px); border: 2px solid transparent; background-color: transparent; block-size: 3rem; cursor: pointer; inline-size: 3rem; - inset-block-start: 0; - inset-inline-end: 0; transition: background-color $duration-fast-02 motion(standard, productive); &:hover {