From 21ab9b9d8c9973a1ee62b2f5efd9f83c09fce108 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Tue, 14 Apr 2026 12:22:25 +0800 Subject: [PATCH] refactor(web): remove highPriority modal stacking (#35132) --- .../base/modal/__tests__/index.spec.tsx | 13 ----- .../components/base/modal/index.stories.tsx | 13 ++--- web/app/components/base/modal/index.tsx | 10 ++-- web/app/components/base/ui/dialog/index.tsx | 7 +-- .../base/ui/toast/__tests__/index.spec.tsx | 2 +- web/app/components/base/ui/toast/index.tsx | 3 +- web/app/components/goto-anything/index.tsx | 20 ++++---- web/app/signin/normal-form.tsx | 50 +++++++++---------- web/docs/overlay-migration.md | 11 ++-- web/eslint-suppressions.json | 25 ---------- 10 files changed, 52 insertions(+), 102 deletions(-) diff --git a/web/app/components/base/modal/__tests__/index.spec.tsx b/web/app/components/base/modal/__tests__/index.spec.tsx index caf2b58053..4705d0defd 100644 --- a/web/app/components/base/modal/__tests__/index.spec.tsx +++ b/web/app/components/base/modal/__tests__/index.spec.tsx @@ -135,19 +135,6 @@ describe('Modal', () => { expect(container).toBeInTheDocument() }) - it('should apply highPriority z-index when highPriority is true', async () => { - await act(async () => { - render( - -
Content
-
, - ) - }) - - const dialog = document.querySelector('.z-1100') - expect(dialog).toBeInTheDocument() - }) - it('should apply overlayOpacity background when overlayOpacity is true', async () => { await act(async () => { render( diff --git a/web/app/components/base/modal/index.stories.tsx b/web/app/components/base/modal/index.stories.tsx index 91bb851f20..33d0366324 100644 --- a/web/app/components/base/modal/index.stories.tsx +++ b/web/app/components/base/modal/index.stories.tsx @@ -9,7 +9,7 @@ const meta = { layout: 'fullscreen', docs: { description: { - component: 'Lightweight modal wrapper with optional header/description, close icon, and high-priority stacking for dropdown overlays.', + component: 'Lightweight modal wrapper with optional header/description and close icon.', }, }, }, @@ -43,10 +43,6 @@ const meta = { control: 'boolean', description: 'Allows content to overflow the modal panel.', }, - highPriority: { - control: 'boolean', - description: 'Lifts the modal above other high z-index elements like dropdowns.', - }, onClose: { control: false, description: 'Callback invoked when the modal requests to close.', @@ -115,18 +111,17 @@ export const Default: Story = { render: args => , } -export const HighPriorityOverflow: Story = { +export const OverflowVisible: Story = { render: args => , args: { - highPriority: true, overflowVisible: true, - description: 'Demonstrates the modal configured to sit above dropdowns while letting the body content overflow.', + description: 'Demonstrates the modal configured to let the body content overflow.', className: 'max-w-[540px]', }, parameters: { docs: { description: { - story: 'Shows the modal with `highPriority` and `overflowVisible` enabled, useful when nested within complex surfaces.', + story: 'Shows the modal with `overflowVisible` enabled for content that needs to escape the panel bounds.', }, }, }, diff --git a/web/app/components/base/modal/index.tsx b/web/app/components/base/modal/index.tsx index 92a38268e4..8107718b29 100644 --- a/web/app/components/base/modal/index.tsx +++ b/web/app/components/base/modal/index.tsx @@ -20,7 +20,6 @@ type IModal = { children?: React.ReactNode closable?: boolean overflowVisible?: boolean - highPriority?: boolean // For modals that need to appear above dropdowns overlayOpacity?: boolean // For semi-transparent overlay instead of default clickOutsideNotClose?: boolean // Prevent closing when clicking outside modal } @@ -36,13 +35,12 @@ export default function Modal({ children, closable = false, overflowVisible = false, - highPriority = false, overlayOpacity = false, clickOutsideNotClose = false, }: IModal) { return ( - +
@@ -59,19 +57,19 @@ export default function Modal({ {!!title && ( {title} )} {!!description && ( -
+
{description}
)} {closable && ( -
+
{ expect(screen.getByText('Your changes are available now.')).toBeInTheDocument() const viewport = screen.getByRole('region', { name: 'Notifications' }) expect(viewport).toHaveAttribute('aria-live', 'polite') - expect(viewport).toHaveClass('z-1101') + expect(viewport).toHaveClass('z-1003') expect(viewport.firstElementChild).toHaveClass('top-4') expect(screen.getByRole('dialog')).not.toHaveClass('outline-hidden') expect(document.body.querySelector('[aria-hidden="true"].i-ri-checkbox-circle-fill')).toBeInTheDocument() diff --git a/web/app/components/base/ui/toast/index.tsx b/web/app/components/base/ui/toast/index.tsx index 4b589836e3..f07815f3a6 100644 --- a/web/app/components/base/ui/toast/index.tsx +++ b/web/app/components/base/ui/toast/index.tsx @@ -222,8 +222,7 @@ function ToastViewport() {
= ({ return ( <> - { + if (!open) + modalClose() + }} > -
+ = ({ hasQuery={!!searchQuery.trim()} /> -
-
+ +
{activePlugin && ( {
- +
-

{t('licenseLost', { ns: 'login' })}

-

{t('licenseLostTip', { ns: 'login' })}

+

{t('licenseLost', { ns: 'login' })}

+

{t('licenseLostTip', { ns: 'login' })}

@@ -109,10 +109,10 @@ const NormalForm = () => {
- +
-

{t('licenseExpired', { ns: 'login' })}

-

{t('licenseExpiredTip', { ns: 'login' })}

+

{t('licenseExpired', { ns: 'login' })}

+

{t('licenseExpiredTip', { ns: 'login' })}

@@ -125,10 +125,10 @@ const NormalForm = () => {
- +
-

{t('licenseInactive', { ns: 'login' })}

-

{t('licenseInactiveTip', { ns: 'login' })}

+

{t('licenseInactive', { ns: 'login' })}

+

{t('licenseInactiveTip', { ns: 'login' })}

@@ -141,12 +141,12 @@ const NormalForm = () => { {isInviteLink ? (
-

+

{t('join', { ns: 'login' })} {workspaceName}

{!systemFeatures.branding.enabled && ( -

+

{t('joinTipStart', { ns: 'login' })} {workspaceName} {t('joinTipEnd', { ns: 'login' })} @@ -156,8 +156,8 @@ const NormalForm = () => { ) : (

-

{systemFeatures.branding.enabled ? t('pageTitleForE', { ns: 'login' }) : t('pageTitle', { ns: 'login' })}

-

{t('welcome', { ns: 'login' })}

+

{systemFeatures.branding.enabled ? t('pageTitleForE', { ns: 'login' }) : t('pageTitle', { ns: 'login' })}

+

{t('welcome', { ns: 'login' })}

)}
@@ -174,7 +174,7 @@ const NormalForm = () => {
- {t('or', { ns: 'login' })} + {t('or', { ns: 'login' })}
@@ -187,7 +187,7 @@ const NormalForm = () => { {systemFeatures.enable_email_password_login && (
{ updateAuthType('password') }}> - {t('usePassword', { ns: 'login' })} + {t('usePassword', { ns: 'login' })}
)} @@ -197,18 +197,18 @@ const NormalForm = () => { {systemFeatures.enable_email_code_login && (
{ updateAuthType('code') }}> - {t('useVerificationCode', { ns: 'login' })} + {t('useVerificationCode', { ns: 'login' })}
)} )} - + ) } {systemFeatures.is_allow_register && authType === 'password' && ( -
+
{t('signup.noAccount', { ns: 'login' })} {
-

{t('noLoginMethod', { ns: 'login' })}

-

{t('noLoginMethodTip', { ns: 'login' })}

+

{t('noLoginMethod', { ns: 'login' })}

+

{t('noLoginMethodTip', { ns: 'login' })}