mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-12 01:24:12 +08:00
🐛 fix(overlay): 修复浮窗与弹层层级遮挡
- 统一分离窗口、弹出层和弹窗的层级常量 - 将浮动窗口通过 Portal 挂载到 body 并隔离 AntD 弹层 - 补充右键菜单和分离窗口层级回归测试
This commit is contained in:
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { CopyOutlined, EditOutlined, UndoOutlined, VerticalAlignBottomOutlined } from '@ant-design/icons';
|
||||
import { t } from '../i18n';
|
||||
import { APP_POPUP_Z_INDEX } from '../utils/overlayZIndex';
|
||||
|
||||
interface CellContextMenuState {
|
||||
visible: boolean;
|
||||
@@ -125,7 +126,7 @@ const DataGridLegacyCellContextMenu: React.FC<DataGridLegacyCellContextMenuProps
|
||||
position: 'fixed',
|
||||
left: cellContextMenu.x,
|
||||
top: cellContextMenu.y,
|
||||
zIndex: 10000,
|
||||
zIndex: APP_POPUP_Z_INDEX,
|
||||
background: bgContextMenu,
|
||||
border: darkMode ? '1px solid #303030' : '1px solid #d9d9d9',
|
||||
borderRadius: 4,
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { Button, message } from 'antd';
|
||||
import { CopyOutlined } from '@ant-design/icons';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { APP_POPUP_Z_INDEX } from '../utils/overlayZIndex';
|
||||
|
||||
import Modal from './common/ResizableDraggableModal';
|
||||
import ImportPreviewModal from './ImportPreviewModal';
|
||||
@@ -882,7 +883,7 @@ const renderDataTableView = () => (
|
||||
position: 'fixed',
|
||||
left: cellContextMenu.x,
|
||||
top: cellContextMenu.y,
|
||||
zIndex: 10000,
|
||||
zIndex: APP_POPUP_Z_INDEX,
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import { Button, Spin } from 'antd';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Button, ConfigProvider, Spin } from 'antd';
|
||||
import { useStore } from '../store';
|
||||
import { t } from '../i18n';
|
||||
import {
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
} from '../utils/detachedWindow';
|
||||
import type { OverlayWorkbenchTheme } from '../utils/overlayWorkbenchTheme';
|
||||
import { hasNativeDetachedWindowManager } from '../utils/nativeDetachedWindowHost';
|
||||
import { APP_POPUP_Z_INDEX } from '../utils/overlayZIndex';
|
||||
import { useManagedPointerInteraction } from '../hooks/useManagedPointerInteraction';
|
||||
import AIPanelErrorBoundary from './ai/AIPanelErrorBoundary';
|
||||
|
||||
@@ -129,8 +131,9 @@ const FloatingAIChatWindow: React.FC<FloatingAIChatWindowProps> = ({
|
||||
const isDark = theme === 'dark';
|
||||
const bounds = windowState;
|
||||
|
||||
return (
|
||||
<div className="gn-detached-ai-chat-layer" aria-label={t('ai_chat.detached.window_aria')}>
|
||||
const floatingWindow = (
|
||||
<ConfigProvider theme={{ token: { zIndexPopupBase: APP_POPUP_Z_INDEX } }}>
|
||||
<div className="gn-detached-ai-chat-layer" aria-label={t('ai_chat.detached.window_aria')}>
|
||||
<style>{`
|
||||
.gn-detached-ai-chat-layer {
|
||||
position: fixed;
|
||||
@@ -293,8 +296,13 @@ const FloatingAIChatWindow: React.FC<FloatingAIChatWindowProps> = ({
|
||||
onPointerDown={(event) => startInteraction(event, 'resize-se', bounds)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
return typeof document === 'undefined'
|
||||
? floatingWindow
|
||||
: createPortal(floatingWindow, document.body);
|
||||
};
|
||||
|
||||
export default FloatingAIChatWindow;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Button, ConfigProvider, Tooltip } from 'antd';
|
||||
import { CloseOutlined, CompressOutlined } from '@ant-design/icons';
|
||||
import { useStore } from '../store';
|
||||
import { t } from '../i18n';
|
||||
@@ -12,6 +13,10 @@ import {
|
||||
DEFAULT_DETACHED_WINDOW_MIN_WIDTH,
|
||||
DETACHED_WINDOW_VIEWPORT_PADDING,
|
||||
} from '../utils/detachedWindow';
|
||||
import {
|
||||
APP_DETACHED_WINDOW_Z_INDEX_BASE,
|
||||
APP_POPUP_Z_INDEX,
|
||||
} from '../utils/overlayZIndex';
|
||||
import { useManagedPointerInteraction } from '../hooks/useManagedPointerInteraction';
|
||||
|
||||
const createLazyDetachedResultDataGrid = () => React.lazy(() => import('./DataGrid'));
|
||||
@@ -148,14 +153,15 @@ const FloatingQueryResultWindows: React.FC = () => {
|
||||
|
||||
const isDark = theme === 'dark';
|
||||
|
||||
return (
|
||||
<div className="gn-detached-result-layer" aria-label={t('query_editor.results_panel.detached.title', { index: '' })}>
|
||||
const floatingWindows = (
|
||||
<ConfigProvider theme={{ token: { zIndexPopupBase: APP_POPUP_Z_INDEX } }}>
|
||||
<div className="gn-detached-result-layer" aria-label={t('query_editor.results_panel.detached.title', { index: '' })}>
|
||||
<style>{`
|
||||
.gn-detached-result-layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 1210;
|
||||
z-index: ${APP_DETACHED_WINDOW_Z_INDEX_BASE};
|
||||
}
|
||||
.gn-detached-result-window {
|
||||
position: fixed;
|
||||
@@ -343,8 +349,13 @@ const FloatingQueryResultWindows: React.FC = () => {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
return typeof document === 'undefined'
|
||||
? floatingWindows
|
||||
: createPortal(floatingWindows, document.body);
|
||||
};
|
||||
|
||||
export default FloatingQueryResultWindows;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Button, ConfigProvider, Tooltip } from 'antd';
|
||||
import { CloseOutlined, CompressOutlined } from '@ant-design/icons';
|
||||
import { useStore } from '../store';
|
||||
import { t } from '../i18n';
|
||||
@@ -18,6 +19,10 @@ import WorkbenchTabContent from './WorkbenchTabContent';
|
||||
import { hasNativeDetachedWindowManager } from '../utils/nativeDetachedWindowHost';
|
||||
import { useWorkbenchTabs } from '../hooks/useWorkbenchTabs';
|
||||
import { useManagedPointerInteraction } from '../hooks/useManagedPointerInteraction';
|
||||
import {
|
||||
APP_DETACHED_WINDOW_Z_INDEX_BASE,
|
||||
APP_POPUP_Z_INDEX,
|
||||
} from '../utils/overlayZIndex';
|
||||
|
||||
const getTabKindLabel = (type: string): string => {
|
||||
if (type === 'query') return t('tab_manager.kind_badge.query');
|
||||
@@ -184,14 +189,15 @@ const FloatingWorkbenchWindows: React.FC = () => {
|
||||
|
||||
const isDark = theme === 'dark';
|
||||
|
||||
return (
|
||||
<div className="gn-detached-window-layer" aria-label={t('tab_manager.detached.title_fallback')}>
|
||||
const floatingWindows = (
|
||||
<ConfigProvider theme={{ token: { zIndexPopupBase: APP_POPUP_Z_INDEX } }}>
|
||||
<div className="gn-detached-window-layer" aria-label={t('tab_manager.detached.title_fallback')}>
|
||||
<style>{`
|
||||
.gn-detached-window-layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 1200;
|
||||
z-index: ${APP_DETACHED_WINDOW_Z_INDEX_BASE};
|
||||
}
|
||||
.gn-detached-window {
|
||||
position: fixed;
|
||||
@@ -368,8 +374,13 @@ const FloatingWorkbenchWindows: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
return typeof document === 'undefined'
|
||||
? floatingWindows
|
||||
: createPortal(floatingWindows, document.body);
|
||||
};
|
||||
|
||||
export default FloatingWorkbenchWindows;
|
||||
|
||||
@@ -71,6 +71,7 @@ export {
|
||||
import React, { useEffect, useState, useMemo, useRef, useCallback, useDeferredValue } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Tree, message, Dropdown, MenuProps, Input, Button, Form, Popover, Radio, Select, Tooltip } from 'antd';
|
||||
import { APP_POPUP_Z_INDEX } from '../utils/overlayZIndex';
|
||||
import {
|
||||
CaretDownFilled,
|
||||
DatabaseOutlined,
|
||||
@@ -3369,7 +3370,7 @@ const Sidebar: React.FC<{
|
||||
position: 'fixed',
|
||||
left: contextMenu.x,
|
||||
top: contextMenu.y,
|
||||
zIndex: 10000,
|
||||
zIndex: APP_POPUP_Z_INDEX,
|
||||
width: contextMenu.overlayStyle?.width ?? SIDEBAR_CONTEXT_MENU_FALLBACK_WIDTH,
|
||||
maxWidth: contextMenu.overlayStyle?.maxWidth ?? 'calc(100vw - 24px)',
|
||||
['--gn-v2-context-menu-max-height' as any]: `${contextMenu.maxHeight ?? SIDEBAR_CONTEXT_MENU_FALLBACK_HEIGHT}px`,
|
||||
|
||||
@@ -31,6 +31,7 @@ import { extractTableNameFromMetadataRow } from '../utils/tableMetadataRows';
|
||||
import { V2TableContextMenuView, type V2TableContextMenuActionKey } from './V2TableContextMenu';
|
||||
import { showSQLExportOptionsDialog } from './SQLExportOptionsDialog';
|
||||
import { confirmCopyTable } from './tableCopyAction';
|
||||
import { APP_POPUP_Z_INDEX } from '../utils/overlayZIndex';
|
||||
|
||||
interface TableOverviewProps {
|
||||
tab: TabData;
|
||||
@@ -1606,7 +1607,7 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
position: 'fixed',
|
||||
left: v2ContextMenu.x,
|
||||
top: v2ContextMenu.y,
|
||||
zIndex: 10000,
|
||||
zIndex: APP_POPUP_Z_INDEX,
|
||||
width: OVERVIEW_CONTEXT_MENU_WIDTH,
|
||||
maxWidth: 'calc(100vw - 24px)',
|
||||
['--gn-v2-context-menu-max-height' as any]: `${v2ContextMenu.maxHeight}px`,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Button, Drawer, Empty, Pagination, Select, Space, Table, Tag, Tooltip, Typography, message } from 'antd';
|
||||
import { Button, ConfigProvider, Drawer, Empty, Pagination, Select, Space, Table, Tag, Tooltip, Typography, message } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import {
|
||||
CloseOutlined,
|
||||
@@ -36,6 +36,10 @@ import {
|
||||
DEFAULT_DETACHED_WINDOW_MIN_WIDTH,
|
||||
DETACHED_WINDOW_VIEWPORT_PADDING,
|
||||
} from '../../utils/detachedWindow';
|
||||
import {
|
||||
APP_DETACHED_WINDOW_Z_INDEX_BASE,
|
||||
APP_POPUP_Z_INDEX,
|
||||
} from '../../utils/overlayZIndex';
|
||||
import { useManagedPointerInteraction } from '../../hooks/useManagedPointerInteraction';
|
||||
import {
|
||||
loadResultDiffDetachedBoundsMemory,
|
||||
@@ -79,7 +83,7 @@ type FloatingBounds = {
|
||||
zIndex: number;
|
||||
};
|
||||
|
||||
const initialFloatingBounds = (zIndex = 1320): FloatingBounds =>
|
||||
const initialFloatingBounds = (zIndex = APP_DETACHED_WINDOW_Z_INDEX_BASE + 1): FloatingBounds =>
|
||||
resolveResultDiffDetachedBounds(loadResultDiffDetachedBoundsMemory(), zIndex);
|
||||
|
||||
const ResultDiffPanel: React.FC<ResultDiffPanelProps> = ({
|
||||
@@ -707,13 +711,14 @@ const ResultDiffPanel: React.FC<ResultDiffPanelProps> = ({
|
||||
|
||||
const floatingWindow = detached && typeof document !== 'undefined'
|
||||
? createPortal(
|
||||
<div className="gn-result-diff-floating-layer" aria-label={titleText}>
|
||||
<ConfigProvider theme={{ token: { zIndexPopupBase: APP_POPUP_Z_INDEX } }}>
|
||||
<div className="gn-result-diff-floating-layer" aria-label={titleText}>
|
||||
<style>{`
|
||||
.gn-result-diff-floating-layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 1320;
|
||||
z-index: ${APP_DETACHED_WINDOW_Z_INDEX_BASE};
|
||||
}
|
||||
.gn-result-diff-floating-window {
|
||||
position: fixed;
|
||||
@@ -782,7 +787,10 @@ const ResultDiffPanel: React.FC<ResultDiffPanelProps> = ({
|
||||
height: bounds.height,
|
||||
zIndex: bounds.zIndex,
|
||||
}}
|
||||
onMouseDown={() => setBounds((prev) => ({ ...prev, zIndex: Math.max(prev.zIndex, 1320) + 1 }))}
|
||||
onMouseDown={() => setBounds((prev) => ({
|
||||
...prev,
|
||||
zIndex: Math.max(prev.zIndex, APP_DETACHED_WINDOW_Z_INDEX_BASE) + 1,
|
||||
}))}
|
||||
>
|
||||
<div
|
||||
className="gn-result-diff-floating-header"
|
||||
@@ -811,7 +819,8 @@ const ResultDiffPanel: React.FC<ResultDiffPanelProps> = ({
|
||||
onPointerDown={(event) => startFloatingDrag(event, 'resize-se')}
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
</div>
|
||||
</ConfigProvider>,
|
||||
document.body,
|
||||
)
|
||||
: null;
|
||||
|
||||
@@ -13,11 +13,19 @@ import {
|
||||
shouldDetachAtScreenPoint,
|
||||
toAIChatDetachedBoundsMemory,
|
||||
} from './detachedWindow';
|
||||
import {
|
||||
APP_DETACHED_WINDOW_Z_INDEX_BASE,
|
||||
APP_POPUP_Z_INDEX,
|
||||
} from './overlayZIndex';
|
||||
|
||||
describe('detachedWindow helpers', () => {
|
||||
it('computes next z-index above existing windows', () => {
|
||||
expect(nextDetachedZIndex([])).toBe(1201);
|
||||
expect(nextDetachedZIndex([{ zIndex: 1300 }, { zIndex: 1250 }])).toBe(1301);
|
||||
expect(nextDetachedZIndex([])).toBe(APP_DETACHED_WINDOW_Z_INDEX_BASE + 1);
|
||||
expect(nextDetachedZIndex([
|
||||
{ zIndex: APP_DETACHED_WINDOW_Z_INDEX_BASE + 100 },
|
||||
{ zIndex: APP_DETACHED_WINDOW_Z_INDEX_BASE + 50 },
|
||||
])).toBe(APP_DETACHED_WINDOW_Z_INDEX_BASE + 101);
|
||||
expect(nextDetachedZIndex([])).toBeLessThan(APP_POPUP_Z_INDEX);
|
||||
});
|
||||
|
||||
it('detaches only when vertical drag exceeds threshold', () => {
|
||||
@@ -30,7 +38,8 @@ describe('detachedWindow helpers', () => {
|
||||
const bounds = createDefaultDetachedBounds([]);
|
||||
expect(bounds.width).toBeGreaterThan(0);
|
||||
expect(bounds.height).toBeGreaterThan(0);
|
||||
expect(bounds.zIndex).toBeGreaterThan(1200);
|
||||
expect(bounds.zIndex).toBeGreaterThan(APP_DETACHED_WINDOW_Z_INDEX_BASE);
|
||||
expect(bounds.zIndex).toBeLessThan(APP_POPUP_Z_INDEX);
|
||||
});
|
||||
|
||||
it('resolves floating window titles with object labels', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { APP_DETACHED_WINDOW_Z_INDEX_BASE } from './overlayZIndex';
|
||||
|
||||
export type DetachedWindowBounds = {
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -86,7 +88,7 @@ export const clamp = (value: number, min: number, max: number): number =>
|
||||
Math.min(Math.max(value, min), max);
|
||||
|
||||
export const nextDetachedZIndex = (windows: Array<{ zIndex?: number }>): number => {
|
||||
let max = 1200;
|
||||
let max = APP_DETACHED_WINDOW_Z_INDEX_BASE;
|
||||
for (const windowState of windows) {
|
||||
const z = Number(windowState?.zIndex);
|
||||
if (Number.isFinite(z) && z > max) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
APP_COMMAND_PALETTE_Z_INDEX,
|
||||
APP_DETACHED_WINDOW_Z_INDEX_BASE,
|
||||
APP_FOREGROUND_MODAL_Z_INDEX,
|
||||
APP_NESTED_MODAL_Z_INDEX,
|
||||
APP_OVERLAY_Z_INDEX_BASE,
|
||||
@@ -28,6 +29,14 @@ const connectionModalSource = readSource('../components/ConnectionModal.tsx');
|
||||
const redisViewerSource = readSource('../components/RedisViewer.tsx');
|
||||
const resultDiffPanelSource = readSource('../components/resultDiff/ResultDiffPanel.tsx');
|
||||
const sidebarSearchPanelSource = readSource('../components/sidebar/SidebarSearchPanel.tsx');
|
||||
const floatingAIChatSource = readSource('../components/FloatingAIChatWindow.tsx');
|
||||
const floatingWorkbenchSource = readSource('../components/FloatingWorkbenchWindows.tsx');
|
||||
const floatingQueryResultSource = readSource('../components/FloatingQueryResultWindows.tsx');
|
||||
const detachedWindowSource = readSource('./detachedWindow.ts');
|
||||
const legacyGridContextMenuSource = readSource('../components/DataGridLegacyCellContextMenu.tsx');
|
||||
const dataGridShellSource = readSource('../components/DataGridShell.tsx');
|
||||
const sidebarSource = readSource('../components/Sidebar.tsx');
|
||||
const tableOverviewSource = readSource('../components/TableOverview.tsx');
|
||||
const v2ThemeSource = readSource('../v2-theme.css');
|
||||
|
||||
const collectRuntimeSources = (directory: string): string[] => readdirSync(directory).flatMap((entry) => {
|
||||
@@ -94,9 +103,10 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe('application overlay z-index policy', () => {
|
||||
it('keeps root, popup, and foreground modal layers ordered', () => {
|
||||
it('keeps root dialogs, floating windows, popups, and foreground dialogs ordered', () => {
|
||||
expect(APP_OVERLAY_Z_INDEX_BASE).toBe(10_000);
|
||||
expect(APP_POPUP_Z_INDEX).toBeGreaterThan(APP_OVERLAY_Z_INDEX_BASE);
|
||||
expect(APP_DETACHED_WINDOW_Z_INDEX_BASE).toBeGreaterThan(APP_OVERLAY_Z_INDEX_BASE);
|
||||
expect(APP_POPUP_Z_INDEX).toBeGreaterThan(APP_DETACHED_WINDOW_Z_INDEX_BASE);
|
||||
expect(APP_FOREGROUND_MODAL_Z_INDEX).toBeGreaterThan(APP_POPUP_Z_INDEX);
|
||||
expect(APP_NESTED_MODAL_Z_INDEX).toBeGreaterThan(APP_FOREGROUND_MODAL_Z_INDEX);
|
||||
expect(APP_COMMAND_PALETTE_Z_INDEX).toBeGreaterThan(APP_NESTED_MODAL_Z_INDEX);
|
||||
@@ -110,7 +120,7 @@ describe('application overlay z-index policy', () => {
|
||||
expect(configSpy).toHaveBeenCalledWith({
|
||||
theme: {
|
||||
token: {
|
||||
zIndexPopupBase: APP_OVERLAY_Z_INDEX_BASE,
|
||||
zIndexPopupBase: APP_POPUP_Z_INDEX,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -168,6 +178,34 @@ describe('application overlay z-index policy', () => {
|
||||
expect(resultDiffPanelSource).not.toContain('zIndex: 10050');
|
||||
});
|
||||
|
||||
it('keeps every in-WebView floating window above root dialogs with usable portaled popups', () => {
|
||||
expect(detachedWindowSource).toContain('let max = APP_DETACHED_WINDOW_Z_INDEX_BASE;');
|
||||
for (const source of [
|
||||
floatingAIChatSource,
|
||||
floatingWorkbenchSource,
|
||||
floatingQueryResultSource,
|
||||
]) {
|
||||
expect(source).toContain("import { createPortal } from 'react-dom';");
|
||||
expect(source).toContain('zIndexPopupBase: APP_POPUP_Z_INDEX');
|
||||
expect(source).toContain('document.body');
|
||||
}
|
||||
expect(floatingWorkbenchSource).toContain('z-index: ${APP_DETACHED_WINDOW_Z_INDEX_BASE};');
|
||||
expect(floatingQueryResultSource).toContain('z-index: ${APP_DETACHED_WINDOW_Z_INDEX_BASE};');
|
||||
expect(resultDiffPanelSource).toContain('z-index: ${APP_DETACHED_WINDOW_Z_INDEX_BASE};');
|
||||
expect(resultDiffPanelSource).toContain('zIndexPopupBase: APP_POPUP_Z_INDEX');
|
||||
});
|
||||
|
||||
it('routes body-level context menus through the shared popup layer', () => {
|
||||
for (const source of [
|
||||
legacyGridContextMenuSource,
|
||||
dataGridShellSource,
|
||||
sidebarSource,
|
||||
tableOverviewSource,
|
||||
]) {
|
||||
expect(source).toContain('zIndex: APP_POPUP_Z_INDEX');
|
||||
}
|
||||
});
|
||||
|
||||
it('portals the command palette above modal stacking contexts', () => {
|
||||
expect(sidebarSearchPanelSource).toContain("import { createPortal } from 'react-dom';");
|
||||
expect(sidebarSearchPanelSource).toContain('style={{ zIndex: APP_COMMAND_PALETTE_Z_INDEX }}');
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
export const APP_OVERLAY_Z_INDEX_BASE = 10_000;
|
||||
export const APP_POPUP_Z_INDEX = APP_OVERLAY_Z_INDEX_BASE + 50;
|
||||
export const APP_FOREGROUND_MODAL_Z_INDEX = APP_OVERLAY_Z_INDEX_BASE + 100;
|
||||
export const APP_NESTED_MODAL_Z_INDEX = APP_FOREGROUND_MODAL_Z_INDEX + 100;
|
||||
export const APP_COMMAND_PALETTE_Z_INDEX = APP_NESTED_MODAL_Z_INDEX + 100;
|
||||
export const APP_DETACHED_WINDOW_Z_INDEX_BASE = APP_OVERLAY_Z_INDEX_BASE + 1_000;
|
||||
export const APP_POPUP_Z_INDEX = APP_OVERLAY_Z_INDEX_BASE + 9_000;
|
||||
export const APP_FOREGROUND_MODAL_Z_INDEX = APP_OVERLAY_Z_INDEX_BASE + 10_000;
|
||||
export const APP_NESTED_MODAL_Z_INDEX = APP_FOREGROUND_MODAL_Z_INDEX + 1_000;
|
||||
export const APP_COMMAND_PALETTE_Z_INDEX = APP_NESTED_MODAL_Z_INDEX + 1_000;
|
||||
|
||||
export const configureAntdStaticOverlayLayer = (): void => {
|
||||
ConfigProvider.config({
|
||||
theme: {
|
||||
token: {
|
||||
zIndexPopupBase: APP_OVERLAY_Z_INDEX_BASE,
|
||||
zIndexPopupBase: APP_POPUP_Z_INDEX,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
resolveResultDiffDetachedBounds,
|
||||
saveResultDiffDetachedBoundsMemory,
|
||||
} from './detachedBoundsMemory';
|
||||
import { APP_DETACHED_WINDOW_Z_INDEX_BASE } from '../overlayZIndex';
|
||||
|
||||
describe('resultDiff detachedBoundsMemory', () => {
|
||||
beforeEach(() => {
|
||||
@@ -46,5 +47,6 @@ describe('resultDiff detachedBoundsMemory', () => {
|
||||
const resolved = resolveResultDiffDetachedBounds(null);
|
||||
expect(resolved.width).toBeGreaterThan(0);
|
||||
expect(resolved.height).toBeGreaterThan(0);
|
||||
expect(resolved.zIndex).toBe(APP_DETACHED_WINDOW_Z_INDEX_BASE + 1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
DEFAULT_DETACHED_WINDOW_WIDTH,
|
||||
DETACHED_WINDOW_VIEWPORT_PADDING,
|
||||
} from '../detachedWindow';
|
||||
import { APP_DETACHED_WINDOW_Z_INDEX_BASE } from '../overlayZIndex';
|
||||
|
||||
const STORAGE_KEY = 'gonavi.resultDiff.detachedBounds.v1';
|
||||
|
||||
@@ -62,7 +63,7 @@ export const saveResultDiffDetachedBoundsMemory = (
|
||||
/** 按当前视口校正记忆的位置与尺寸,避免移出屏幕 */
|
||||
export const resolveResultDiffDetachedBounds = (
|
||||
memory?: ResultDiffDetachedBoundsMemory | null,
|
||||
zIndex = 1320,
|
||||
zIndex = APP_DETACHED_WINDOW_Z_INDEX_BASE + 1,
|
||||
): {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
Reference in New Issue
Block a user