Modal: Expose ariaLabel prop to use with custom header element (#112668)
add optional aria-label for modal when passing custom header element
This commit is contained in:
@@ -810,11 +810,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"packages/grafana-ui/src/components/Modal/Modal.story.tsx": {
|
||||
"no-restricted-syntax": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"packages/grafana-ui/src/components/Modal/ModalsContext.tsx": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 4
|
||||
|
||||
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
|
||||
import { useRef, useEffect } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { Button, Icon, Modal, useStyles2 } from '@grafana/ui';
|
||||
|
||||
type ConfirmModalProps = {
|
||||
@@ -33,6 +33,7 @@ export function ConfirmModal({ isOpen, onCancel, onDiscard, onCopy }: ConfirmMod
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
ariaLabel={t('grafana-sql.components.confirm-modal.warning', 'Warning')}
|
||||
onDismiss={onCancel}
|
||||
isOpen={isOpen}
|
||||
>
|
||||
|
||||
@@ -21,8 +21,6 @@ const meta: Meta = {
|
||||
controls: {
|
||||
exclude: ['className', 'contentClassName', 'onDismiss', 'onClickBackdrop'],
|
||||
},
|
||||
// TODO fix a11y issue in story and remove this
|
||||
a11y: { test: 'off' },
|
||||
},
|
||||
args: {
|
||||
body: oneLineTrim(`Id incididunt do pariatur qui labore. Sint culpa irure cillum et ullamco proident. Deserunt ipsum velit dolore est enim proident dolore consectetur. Et cillum tempor pariatur et. Est tempor cillum ad id nulla. Cillum ut proident
|
||||
@@ -92,7 +90,7 @@ export const WithTabs: StoryFn = (args) => {
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<Modal title={modalHeader} isOpen={true}>
|
||||
<Modal ariaLabel={args.title} title={modalHeader} isOpen={true}>
|
||||
<TabContent>
|
||||
{activeTab === tabs[0].value && <div>{args.body}</div>}
|
||||
{activeTab === tabs[1].value && <div>Second tab content</div>}
|
||||
@@ -110,7 +108,8 @@ WithTabs.args = {
|
||||
export const UsingContentClassName: StoryFn = ({ title, body, ...args }) => {
|
||||
const override = {
|
||||
modalContent: css({
|
||||
backgroundColor: 'darkorange',
|
||||
backgroundColor: 'red',
|
||||
color: 'black',
|
||||
}),
|
||||
};
|
||||
return (
|
||||
|
||||
@@ -15,13 +15,11 @@ import { Stack } from '../Layout/Stack/Stack';
|
||||
import { ModalHeader } from './ModalHeader';
|
||||
import { getModalStyles } from './getModalStyles';
|
||||
|
||||
export interface Props {
|
||||
interface BaseProps {
|
||||
/** @deprecated no longer used */
|
||||
icon?: IconName;
|
||||
/** @deprecated no longer used */
|
||||
iconTooltip?: string;
|
||||
/** Title for the modal or custom header element */
|
||||
title: string | JSX.Element;
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
closeOnEscape?: boolean;
|
||||
@@ -35,9 +33,25 @@ export interface Props {
|
||||
onClickBackdrop?: () => void;
|
||||
}
|
||||
|
||||
interface WithStringTitleProps extends BaseProps {
|
||||
/** Title for the modal or custom header element */
|
||||
title: string;
|
||||
ariaLabel?: never;
|
||||
}
|
||||
|
||||
interface WithCustomTitleProps extends BaseProps {
|
||||
/** Title for the modal or custom header element */
|
||||
title: JSX.Element;
|
||||
/** aria-label for the dialog. only needed when passing a custom title element */
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
export type Props = WithStringTitleProps | WithCustomTitleProps;
|
||||
|
||||
export function Modal(props: PropsWithChildren<Props>) {
|
||||
const {
|
||||
title,
|
||||
ariaLabel,
|
||||
children,
|
||||
isOpen = false,
|
||||
closeOnEscape = true,
|
||||
@@ -60,7 +74,12 @@ export function Modal(props: PropsWithChildren<Props>) {
|
||||
);
|
||||
|
||||
// Get props for the dialog and its title
|
||||
const { dialogProps, titleProps } = useDialog({}, ref);
|
||||
const { dialogProps, titleProps } = useDialog(
|
||||
{
|
||||
'aria-label': ariaLabel,
|
||||
},
|
||||
ref
|
||||
);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
|
||||
@@ -263,6 +263,7 @@ const useAlertGroupsModal = (
|
||||
onDismiss={handleDismiss}
|
||||
closeOnBackdropClick={true}
|
||||
closeOnEscape={true}
|
||||
ariaLabel={t('alerting.policies.matchers', 'Matchers')}
|
||||
title={
|
||||
<Stack direction="row" alignItems="center" gap={1} wrap={'wrap'}>
|
||||
<Stack direction="row" alignItems="center" gap={0.5}>
|
||||
@@ -303,6 +304,7 @@ const UpdatingModal: FC<Pick<ModalProps, 'isOpen'>> = ({ isOpen }) => (
|
||||
onDismiss={() => {}}
|
||||
closeOnBackdropClick={false}
|
||||
closeOnEscape={false}
|
||||
ariaLabel={t('alerting.policies.update.updating', 'Updating...')}
|
||||
title={
|
||||
<Stack direction="row" alignItems="center" gap={0.5}>
|
||||
<Trans i18nKey="alerting.policies.update.updating">Updating...</Trans> <Spinner inline />
|
||||
|
||||
@@ -65,6 +65,7 @@ export function NoAccessModal({ item, isOpen, onDismiss }: NoAccessModalProps) {
|
||||
className={styles.modal}
|
||||
contentClassName={styles.modalContent}
|
||||
title={<NoAccessModalHeader item={item} />}
|
||||
ariaLabel={item.name}
|
||||
isOpen={isOpen}
|
||||
onDismiss={onDismiss}
|
||||
>
|
||||
|
||||
@@ -130,16 +130,14 @@ class UnthemedShareModal extends React.Component<Props, State> {
|
||||
return tabs.find((t) => t.value === activeTab)!;
|
||||
}
|
||||
|
||||
renderTitle() {
|
||||
const { panel } = this.props;
|
||||
renderTitle(modalTitle: string) {
|
||||
const { activeTab } = this.state;
|
||||
const title = panel ? t('share-modal.panel.title', 'Share Panel') : t('share-modal.dashboard.title', 'Share');
|
||||
const canEditDashboard = this.props.dashboard.canEditDashboard();
|
||||
const tabs = getTabs(canEditDashboard, this.props.panel, this.state.activeTab).tabs;
|
||||
|
||||
return (
|
||||
<ModalTabsHeader
|
||||
title={title}
|
||||
title={modalTitle}
|
||||
icon="share-alt"
|
||||
tabs={tabs}
|
||||
activeTab={activeTab}
|
||||
@@ -152,9 +150,10 @@ class UnthemedShareModal extends React.Component<Props, State> {
|
||||
const { dashboard, panel } = this.props;
|
||||
const activeTabModel = this.getActiveTab();
|
||||
const ActiveTab = activeTabModel.component;
|
||||
const modalTitle = panel ? t('share-modal.panel.title', 'Share Panel') : t('share-modal.dashboard.title', 'Share');
|
||||
|
||||
return (
|
||||
<Modal isOpen={true} title={this.renderTitle()} onDismiss={this.props.onDismiss}>
|
||||
<Modal ariaLabel={modalTitle} isOpen={true} title={this.renderTitle(modalTitle)} onDismiss={this.props.onDismiss}>
|
||||
<TabContent>
|
||||
<ActiveTab dashboard={dashboard} panel={panel} onDismiss={this.props.onDismiss} />
|
||||
</TabContent>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { reportInteraction } from '@grafana/runtime';
|
||||
import { PageInfoItem } from '@grafana/runtime/internal';
|
||||
import {
|
||||
@@ -242,7 +242,7 @@ export function PluginDetailsPanel(props: Props): React.ReactElement | null {
|
||||
</Stack>
|
||||
{reportAbuseModalOpen && (
|
||||
<Modal
|
||||
title={<Trans i18nKey="plugins.details.modal.title">Report a plugin concern</Trans>}
|
||||
title={t('plugins.details.modal.title', 'Report a plugin concern')}
|
||||
isOpen
|
||||
onDismiss={() => setReportAbuseModalOpen(false)}
|
||||
>
|
||||
|
||||
@@ -34,7 +34,14 @@ export function ExplainScorePopup({ name, explain, frame, row }: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal title={modalHeader} isOpen={isOpen} onDismiss={() => setOpen(false)} closeOnBackdropClick closeOnEscape>
|
||||
<Modal
|
||||
ariaLabel={name}
|
||||
title={modalHeader}
|
||||
isOpen={isOpen}
|
||||
onDismiss={() => setOpen(false)}
|
||||
closeOnBackdropClick
|
||||
closeOnEscape
|
||||
>
|
||||
<TabContent>
|
||||
{activeTab === tabs[0].value && (
|
||||
<CodeEditor
|
||||
|
||||
Reference in New Issue
Block a user