chore(core): adjust ai onboarding dismiss logic, persist dialog and dismiss once closed (#7417)

This commit is contained in:
CatsJuice
2024-07-04 07:00:17 +00:00
parent b79d13bcc8
commit d6ad7d566f
2 changed files with 86 additions and 58 deletions

View File

@@ -10,7 +10,7 @@ import * as VisuallyHidden from '@radix-ui/react-visually-hidden';
import { assignInlineVars } from '@vanilla-extract/dynamic'; import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx'; import clsx from 'clsx';
import type { CSSProperties } from 'react'; import type { CSSProperties } from 'react';
import { forwardRef } from 'react'; import { forwardRef, useCallback } from 'react';
import type { IconButtonProps } from '../button'; import type { IconButtonProps } from '../button';
import { IconButton } from '../button'; import { IconButton } from '../button';
@@ -23,12 +23,20 @@ export interface ModalProps extends DialogProps {
title?: React.ReactNode; title?: React.ReactNode;
description?: React.ReactNode; description?: React.ReactNode;
withoutCloseButton?: boolean; withoutCloseButton?: boolean;
/**
* __Click outside__ or __Press `Esc`__ won't close the modal
* @default false
*/
persistent?: boolean;
portalOptions?: DialogPortalProps; portalOptions?: DialogPortalProps;
contentOptions?: DialogContentProps; contentOptions?: DialogContentProps;
overlayOptions?: DialogOverlayProps; overlayOptions?: DialogOverlayProps;
closeButtonOptions?: IconButtonProps; closeButtonOptions?: IconButtonProps;
} }
type PointerDownOutsideEvent = Parameters<
Exclude<DialogContentProps['onPointerDownOutside'], undefined>
>[0];
const getVar = (style: number | string = '', defaultValue = '') => { const getVar = (style: number | string = '', defaultValue = '') => {
return style return style
@@ -48,11 +56,14 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>(
description, description,
withoutCloseButton = false, withoutCloseButton = false,
modal, modal,
persistent,
portalOptions, portalOptions,
contentOptions: { contentOptions: {
style: contentStyle, style: contentStyle,
className: contentClassName, className: contentClassName,
onPointerDownOutside,
onEscapeKeyDown,
...otherContentOptions ...otherContentOptions
} = {}, } = {},
overlayOptions: { overlayOptions: {
@@ -64,63 +75,79 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>(
...props ...props
}, },
ref ref
) => ( ) => {
<Dialog.Root modal={modal} {...props}> return (
<Dialog.Portal {...portalOptions}> <Dialog.Root modal={modal} {...props}>
<Dialog.Overlay <Dialog.Portal {...portalOptions}>
className={clsx(styles.modalOverlay, overlayClassName)} <Dialog.Overlay
{...otherOverlayOptions} className={clsx(styles.modalOverlay, overlayClassName)}
/> {...otherOverlayOptions}
<div data-modal={modal} className={clsx(styles.modalContentWrapper)}> />
<Dialog.Content <div data-modal={modal} className={clsx(styles.modalContentWrapper)}>
className={clsx(styles.modalContent, contentClassName)} <Dialog.Content
style={{ onPointerDownOutside={useCallback(
...assignInlineVars({ (e: PointerDownOutsideEvent) => {
[styles.widthVar]: getVar(width, '50vw'), onPointerDownOutside?.(e);
[styles.heightVar]: getVar(height, 'unset'), persistent && e.preventDefault();
[styles.minHeightVar]: getVar(minHeight, '26px'), },
}), [onPointerDownOutside, persistent]
...contentStyle, )}
}} onEscapeKeyDown={useCallback(
{...otherContentOptions} (e: KeyboardEvent) => {
ref={ref} onEscapeKeyDown?.(e);
> persistent && e.preventDefault();
{withoutCloseButton ? null : ( },
<Dialog.Close asChild> [onEscapeKeyDown, persistent]
<IconButton )}
className={styles.closeButton} className={clsx(styles.modalContent, contentClassName)}
aria-label="Close" style={{
type="plain" ...assignInlineVars({
data-testid="modal-close-button" [styles.widthVar]: getVar(width, '50vw'),
{...closeButtonOptions} [styles.heightVar]: getVar(height, 'unset'),
> [styles.minHeightVar]: getVar(minHeight, '26px'),
<CloseIcon /> }),
</IconButton> ...contentStyle,
</Dialog.Close> }}
)} {...otherContentOptions}
{title ? ( ref={ref}
<Dialog.Title className={styles.modalHeader}> >
{title} {withoutCloseButton ? null : (
</Dialog.Title> <Dialog.Close asChild>
) : ( <IconButton
// Refer: https://www.radix-ui.com/primitives/docs/components/dialog#title className={styles.closeButton}
// If you want to hide the title, wrap it inside our Visually Hidden utility like this <VisuallyHidden asChild>. aria-label="Close"
<VisuallyHidden.Root asChild> type="plain"
<Dialog.Title></Dialog.Title> data-testid="modal-close-button"
</VisuallyHidden.Root> {...closeButtonOptions}
)} >
{description ? ( <CloseIcon />
<Dialog.Description className={styles.modalDescription}> </IconButton>
{description} </Dialog.Close>
</Dialog.Description> )}
) : null} {title ? (
<Dialog.Title className={styles.modalHeader}>
{title}
</Dialog.Title>
) : (
// Refer: https://www.radix-ui.com/primitives/docs/components/dialog#title
// If you want to hide the title, wrap it inside our Visually Hidden utility like this <VisuallyHidden asChild>.
<VisuallyHidden.Root asChild>
<Dialog.Title></Dialog.Title>
</VisuallyHidden.Root>
)}
{description ? (
<Dialog.Description className={styles.modalDescription}>
{description}
</Dialog.Description>
) : null}
{children} {children}
</Dialog.Content> </Dialog.Content>
</div> </div>
</Dialog.Portal> </Dialog.Portal>
</Dialog.Root> </Dialog.Root>
) );
}
); );
Modal.displayName = 'Modal'; Modal.displayName = 'Modal';

View File

@@ -184,10 +184,11 @@ export const AIOnboardingGeneral = () => {
return readyToOpen ? ( return readyToOpen ? (
<Modal <Modal
persistent
open={open} open={open}
onOpenChange={v => { onOpenChange={v => {
showAIOnboardingGeneral$.next(v); showAIOnboardingGeneral$.next(v);
if (!v && isLast) toggleGeneralAIOnboarding(false); if (!v) toggleGeneralAIOnboarding(false);
}} }}
contentOptions={{ className: styles.dialog }} contentOptions={{ className: styles.dialog }}
overlayOptions={{ className: baseStyles.dialogOverlay }} overlayOptions={{ className: baseStyles.dialogOverlay }}