mirror of
https://github.com/langgenius/dify.git
synced 2026-05-02 16:38:04 +08:00
refactor: migrate workflow onboarding modal to base dialog (#32915)
This commit is contained in:
@ -1,11 +1,13 @@
|
||||
import { Dialog as BaseDialog } from '@base-ui/react/dialog'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogCloseButton,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogPortal,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '../index'
|
||||
@ -29,7 +31,7 @@ describe('Dialog wrapper', () => {
|
||||
})
|
||||
|
||||
describe('Props', () => {
|
||||
it('should not render close button when closable is omitted', () => {
|
||||
it('should not render close button when DialogCloseButton is not provided', () => {
|
||||
render(
|
||||
<Dialog open>
|
||||
<DialogContent>
|
||||
@ -41,20 +43,47 @@ describe('Dialog wrapper', () => {
|
||||
expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render close button when closable is true', () => {
|
||||
it('should render explicit close button with custom aria-label', () => {
|
||||
render(
|
||||
<Dialog open>
|
||||
<DialogContent closable>
|
||||
<DialogContent>
|
||||
<DialogCloseButton aria-label="Dismiss dialog" />
|
||||
<span>Dialog body</span>
|
||||
</DialogContent>
|
||||
</Dialog>,
|
||||
)
|
||||
|
||||
const dialog = screen.getByRole('dialog')
|
||||
const closeButton = screen.getByRole('button', { name: 'Close' })
|
||||
expect(screen.getByRole('button', { name: 'Dismiss dialog' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
expect(dialog).toContainElement(closeButton)
|
||||
expect(closeButton).toHaveAttribute('aria-label', 'Close')
|
||||
it('should render default close button label when aria-label is omitted', () => {
|
||||
render(
|
||||
<Dialog open>
|
||||
<DialogContent>
|
||||
<DialogCloseButton />
|
||||
<span>Dialog body</span>
|
||||
</DialogContent>
|
||||
</Dialog>,
|
||||
)
|
||||
|
||||
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should forward close button props to base primitive', () => {
|
||||
const onClick = vi.fn()
|
||||
render(
|
||||
<Dialog open>
|
||||
<DialogContent>
|
||||
<DialogCloseButton data-testid="close-button" disabled onClick={onClick} />
|
||||
<span>Dialog body</span>
|
||||
</DialogContent>
|
||||
</Dialog>,
|
||||
)
|
||||
|
||||
const closeButton = screen.getByTestId('close-button')
|
||||
expect(closeButton).toBeDisabled()
|
||||
fireEvent.click(closeButton)
|
||||
expect(onClick).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@ -65,6 +94,7 @@ describe('Dialog wrapper', () => {
|
||||
expect(DialogTitle).toBe(BaseDialog.Title)
|
||||
expect(DialogDescription).toBe(BaseDialog.Description)
|
||||
expect(DialogClose).toBe(BaseDialog.Close)
|
||||
expect(DialogPortal).toBe(BaseDialog.Portal)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -16,22 +16,42 @@ export const DialogTrigger = BaseDialog.Trigger
|
||||
export const DialogTitle = BaseDialog.Title
|
||||
export const DialogDescription = BaseDialog.Description
|
||||
export const DialogClose = BaseDialog.Close
|
||||
export const DialogPortal = BaseDialog.Portal
|
||||
|
||||
type DialogCloseButtonProps = Omit<React.ComponentPropsWithoutRef<typeof BaseDialog.Close>, 'children'>
|
||||
|
||||
export function DialogCloseButton({
|
||||
className,
|
||||
'aria-label': ariaLabel = 'Close',
|
||||
...props
|
||||
}: DialogCloseButtonProps) {
|
||||
return (
|
||||
<BaseDialog.Close
|
||||
aria-label={ariaLabel}
|
||||
{...props}
|
||||
className={cn(
|
||||
'absolute right-6 top-6 z-10 flex h-5 w-5 cursor-pointer items-center justify-center rounded-2xl hover:bg-state-base-hover focus-visible:bg-state-base-hover focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-components-input-border-hover disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-close-line h-4 w-4 text-text-tertiary" />
|
||||
</BaseDialog.Close>
|
||||
)
|
||||
}
|
||||
|
||||
type DialogContentProps = {
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
overlayClassName?: string
|
||||
closable?: boolean
|
||||
}
|
||||
|
||||
export function DialogContent({
|
||||
children,
|
||||
className,
|
||||
overlayClassName,
|
||||
closable = false,
|
||||
}: DialogContentProps) {
|
||||
return (
|
||||
<BaseDialog.Portal>
|
||||
<DialogPortal>
|
||||
<BaseDialog.Backdrop
|
||||
className={cn(
|
||||
'fixed inset-0 z-50 bg-background-overlay',
|
||||
@ -41,18 +61,13 @@ export function DialogContent({
|
||||
/>
|
||||
<BaseDialog.Popup
|
||||
className={cn(
|
||||
'fixed left-1/2 top-1/2 z-50 max-h-[80dvh] w-[480px] max-w-[calc(100vw-2rem)] -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-6 shadow-xl',
|
||||
'fixed left-1/2 top-1/2 z-50 max-h-[80dvh] w-[480px] max-w-[calc(100vw-2rem)] -translate-x-1/2 -translate-y-1/2 overflow-y-auto overscroll-contain rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-6 shadow-xl',
|
||||
'transition-[transform,scale,opacity] duration-150 data-[ending-style]:scale-95 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0 motion-reduce:transition-none',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{closable && (
|
||||
<BaseDialog.Close aria-label="Close" className="absolute right-6 top-6 z-10 flex h-5 w-5 cursor-pointer items-center justify-center rounded-2xl hover:bg-state-base-hover">
|
||||
<span className="i-ri-close-line h-4 w-4 text-text-tertiary" />
|
||||
</BaseDialog.Close>
|
||||
)}
|
||||
{children}
|
||||
</BaseDialog.Popup>
|
||||
</BaseDialog.Portal>
|
||||
</DialogPortal>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user