grafana/packages/grafana-ui/src/components/Modal/Modal.tsx

136 lines
4.0 KiB
TypeScript
Raw Normal View History

import { cx } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { OverlayContainer, useOverlay } from '@react-aria/overlays';
import React, { PropsWithChildren, useRef } from 'react';
import { useTheme2 } from '../../themes';
import { IconName } from '../../types';
import { IconButton } from '../IconButton/IconButton';
import { HorizontalGroup } from '../Layout/Layout';
import { ModalHeader } from './ModalHeader';
import { getModalStyles } from './getModalStyles';
export interface Props {
/** @deprecated no longer used */
@grafana/ui: Create Icon component and replace part of the icons (#23402) * Part1: Unicons implementation (#23197) * Create a new Icon component * Update icons in main sidebar * Update icons in Useful links and in react components on main site * Update icons in Useful links and in main top navigation * Adjust sizing * Update panel navigation and timepicker * Update icons in Panel menu * NewPanelEditor: Fixed so that test alert rule works in new edit mode (#23179) * Update icons in add panel widget * Resolve merge conflict * Fix part of the test errors and type errors * Fix storybook errors * Update getAvailableIcons import in storybook knobs * Fix import path * Fix SyntaxError: Cannot use import statement outside a module in test environment error * Remove dynamic imports * Remove types as using @ts-ignore * Update snapshot test * Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax * Remove color prop from icon, remove color implemetation in mono icons * Update navbar styling * Move toPascalCase to utils/string Co-authored-by: Torkel Ödegaard <torkel@grafana.com> * Resolve type errors resulted from merge * Part2: Unicons implementation (#23266) * Create a new Icon component * Update icons in main sidebar * Update icons in Useful links and in react components on main site * Update icons in Useful links and in main top navigation * Adjust sizing * Update panel navigation and timepicker * Update icons in Panel menu * Update icons in add panel widget * Resolve merge conflict * Fix part of the test errors and type errors * Fix storybook errors * Update getAvailableIcons import in storybook knobs * Fix import path * Fix SyntaxError: Cannot use import statement outside a module in test environment error * Remove dynamic imports * Remove types as using @ts-ignore * Update snapshot test * Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax * Implment icons in Tabs * Implement icons in search items and empty list * Update buttons * Update button-related snapshot tests * Update icons in modals and page headers * Create anfular wrapper and update all icons on search screen * Update sizing, remove colors, update snapshot tests * Remove color prop from icon, remove color implemetation in mono icons * Remove color props from monochrome icons * Complete update of icons for search screen * Update icons for infor tooltips, playlist, permissions * Support temporarly font awesome icons used in enterprise grafana * Part1: Unicons implementation (#23197) * Create a new Icon component * Update icons in main sidebar * Update icons in Useful links and in react components on main site * Update icons in Useful links and in main top navigation * Adjust sizing * Update panel navigation and timepicker * Update icons in Panel menu * NewPanelEditor: Fixed so that test alert rule works in new edit mode (#23179) * Update icons in add panel widget * Resolve merge conflict * Fix part of the test errors and type errors * Fix storybook errors * Update getAvailableIcons import in storybook knobs * Fix import path * Fix SyntaxError: Cannot use import statement outside a module in test environment error * Remove dynamic imports * Remove types as using @ts-ignore * Update snapshot test * Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax * Remove color prop from icon, remove color implemetation in mono icons * Update navbar styling * Move toPascalCase to utils/string Co-authored-by: Torkel Ödegaard <torkel@grafana.com> * Icons update * Add optional chaining to for isFontAwesome variable Co-authored-by: Torkel Ödegaard <torkel@grafana.com> * Part3: Unicons implementation (#23356) * Create a new Icon component * Update icons in main sidebar * Update icons in Useful links and in react components on main site * Update icons in Useful links and in main top navigation * Adjust sizing * Update panel navigation and timepicker * Update icons in Panel menu * Update icons in add panel widget * Resolve merge conflict * Fix part of the test errors and type errors * Fix storybook errors * Update getAvailableIcons import in storybook knobs * Fix import path * Fix SyntaxError: Cannot use import statement outside a module in test environment error * Remove dynamic imports * Remove types as using @ts-ignore * Update snapshot test * Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax * Implment icons in Tabs * Implement icons in search items and empty list * Update buttons * Update button-related snapshot tests * Update icons in modals and page headers * Create anfular wrapper and update all icons on search screen * Update sizing, remove colors, update snapshot tests * Remove color prop from icon, remove color implemetation in mono icons * Remove color props from monochrome icons * Complete update of icons for search screen * Update icons for infor tooltips, playlist, permissions * Support temporarly font awesome icons used in enterprise grafana * Part1: Unicons implementation (#23197) * Create a new Icon component * Update icons in main sidebar * Update icons in Useful links and in react components on main site * Update icons in Useful links and in main top navigation * Adjust sizing * Update panel navigation and timepicker * Update icons in Panel menu * NewPanelEditor: Fixed so that test alert rule works in new edit mode (#23179) * Update icons in add panel widget * Resolve merge conflict * Fix part of the test errors and type errors * Fix storybook errors * Update getAvailableIcons import in storybook knobs * Fix import path * Fix SyntaxError: Cannot use import statement outside a module in test environment error * Remove dynamic imports * Remove types as using @ts-ignore * Update snapshot test * Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax * Remove color prop from icon, remove color implemetation in mono icons * Update navbar styling * Move toPascalCase to utils/string Co-authored-by: Torkel Ödegaard <torkel@grafana.com> * Update icons in Explore * Update icons in alerting * Update + and x buttons * Update icons in configurations and settings * Update close icons * Update icons in rich history * Update alert messages * Add optional chaining to for isFontAwesome variable * Remove icon mock, set up jest.config * Fix navbar plus icon * Fir enable-bacground to enableBackgournd Co-authored-by: Torkel Ödegaard <torkel@grafana.com> * Merge remote branch origin master to icons-unicons * Revert "Merge remote branch origin master to icons-unicons" This reverts commit 3f25d50a39a940883fefe73ce51219139c1ed37f. * Size-up dashnav icons * Fix alerting icons, panel headers, update tests * Fix typecheck error * Adjustments - add panel icon, spacing * Set TerserPlugin sourceMap to false to prevent running out of memory when publishing storybook Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2020-04-08 07:33:31 -05:00
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;
closeOnBackdropClick?: boolean;
trapFocus?: boolean;
isOpen?: boolean;
onDismiss?: () => void;
/** If not set will call onDismiss if that is set. */
onClickBackdrop?: () => void;
}
export function Modal(props: PropsWithChildren<Props>) {
const {
title,
children,
isOpen = false,
closeOnEscape = true,
closeOnBackdropClick = true,
className,
contentClassName,
onDismiss,
onClickBackdrop,
trapFocus = true,
} = props;
const theme = useTheme2();
const styles = getModalStyles(theme);
const ref = useRef<HTMLDivElement>(null);
// Handle interacting outside the dialog and pressing
// the Escape key to close the modal.
const { overlayProps, underlayProps } = useOverlay(
{ isKeyboardDismissDisabled: !closeOnEscape, isOpen, onClose: onDismiss },
ref
);
// Get props for the dialog and its title
const { dialogProps, titleProps } = useDialog({}, ref);
if (!isOpen) {
return null;
}
const headerClass = cx(styles.modalHeader, typeof title !== 'string' && styles.modalHeaderWithTabs);
return (
<OverlayContainer>
<div
className={styles.modalBackdrop}
onClick={onClickBackdrop || (closeOnBackdropClick ? onDismiss : undefined)}
{...underlayProps}
/>
<FocusScope contain={trapFocus} autoFocus restoreFocus>
<div className={cx(styles.modal, className)} ref={ref} {...overlayProps} {...dialogProps}>
<div className={headerClass}>
{typeof title === 'string' && <DefaultModalHeader {...props} title={title} id={titleProps.id} />}
{
// FIXME: custom title components won't get an accessible title.
// Do we really want to support them or shall we just limit this ModalTabsHeader?
typeof title !== 'string' && title
}
<div className={styles.modalHeaderClose}>
<IconButton aria-label="Close dialogue" name="times" size="xl" onClick={onDismiss} />
</div>
</div>
<div className={cx(styles.modalContent, contentClassName)}>{children}</div>
</div>
</FocusScope>
</OverlayContainer>
);
}
function ModalButtonRow({ leftItems, children }: { leftItems?: React.ReactNode; children: React.ReactNode }) {
const theme = useTheme2();
const styles = getModalStyles(theme);
if (leftItems) {
return (
<div className={styles.modalButtonRow}>
<HorizontalGroup justify="space-between">
<HorizontalGroup justify="flex-start" spacing="md">
{leftItems}
</HorizontalGroup>
<HorizontalGroup justify="flex-end" spacing="md">
{children}
</HorizontalGroup>
</HorizontalGroup>
</div>
);
}
return (
<div className={styles.modalButtonRow}>
<HorizontalGroup justify="flex-end" spacing="md">
{children}
</HorizontalGroup>
</div>
);
}
Modal.ButtonRow = ModalButtonRow;
interface DefaultModalHeaderProps {
id?: string;
title: string;
icon?: IconName;
iconTooltip?: string;
}
function DefaultModalHeader({ icon, iconTooltip, title, id }: DefaultModalHeaderProps): JSX.Element {
return <ModalHeader icon={icon} iconTooltip={iconTooltip} title={title} id={id} />;
}