update z-index use
This commit is contained in:
@ -513,4 +513,95 @@ Completed comprehensive refactoring to ensure clean, maintainable code with sepa
|
|||||||
The refactoring follows the principles in instructions.md:
|
The refactoring follows the principles in instructions.md:
|
||||||
- Uses static templates with manual DOM operations
|
- Uses static templates with manual DOM operations
|
||||||
- Maintains separated concerns in different classes
|
- Maintains separated concerns in different classes
|
||||||
- Results in clean, concise, and manageable code
|
- Results in clean, concise, and manageable code
|
||||||
|
|
||||||
|
## Z-Index Management System (2025-12-24)
|
||||||
|
|
||||||
|
A comprehensive z-index management system has been implemented to fix overlay stacking conflicts:
|
||||||
|
|
||||||
|
### The Problem:
|
||||||
|
- Modals were hiding dropdown overlays
|
||||||
|
- Context menus appeared behind modals
|
||||||
|
- Inconsistent z-index values across components
|
||||||
|
- No clear hierarchy for overlay stacking
|
||||||
|
|
||||||
|
### The Solution:
|
||||||
|
|
||||||
|
#### 1. Central Z-Index Constants (`00zindex.ts`):
|
||||||
|
Created a centralized file defining all z-index layers:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export const zIndexLayers = {
|
||||||
|
// Base layer: Regular content
|
||||||
|
base: {
|
||||||
|
content: 'auto',
|
||||||
|
inputElements: 1,
|
||||||
|
},
|
||||||
|
// Fixed UI elements
|
||||||
|
fixed: {
|
||||||
|
appBar: 10,
|
||||||
|
sideMenu: 10,
|
||||||
|
mobileNav: 250,
|
||||||
|
},
|
||||||
|
// Overlay backdrops
|
||||||
|
backdrop: {
|
||||||
|
dropdown: 1999,
|
||||||
|
modal: 2999,
|
||||||
|
contextMenu: 3999,
|
||||||
|
},
|
||||||
|
// Interactive overlays
|
||||||
|
overlay: {
|
||||||
|
dropdown: 2000, // Dropdowns and select menus
|
||||||
|
modal: 3000, // Modal dialogs
|
||||||
|
contextMenu: 4000, // Context menus and tooltips
|
||||||
|
toast: 5000, // Toast notifications
|
||||||
|
},
|
||||||
|
// Special cases
|
||||||
|
modalDropdown: 3500, // Dropdowns inside modals
|
||||||
|
wysiwygMenus: 4500, // Editor formatting menus
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Updated Components:
|
||||||
|
- **dees-modal**: Changed from 2000 to 3000
|
||||||
|
- **dees-windowlayer**: Changed from 200-201 to 1999-2000 (used by dropdowns)
|
||||||
|
- **dees-contextmenu**: Changed from 10000 to 4000
|
||||||
|
- **dees-toast**: Changed from 10000 to 5000
|
||||||
|
- **wysiwyg menus**: Changed from 10000 to 4500
|
||||||
|
- **dees-appui-profiledropdown**: Uses new dropdown z-index (2000)
|
||||||
|
|
||||||
|
#### 3. Stacking Order (bottom to top):
|
||||||
|
1. Regular page content (auto)
|
||||||
|
2. Fixed navigation elements (10-250)
|
||||||
|
3. Dropdown backdrop (1999)
|
||||||
|
4. Dropdown content (2000)
|
||||||
|
5. Modal backdrop (2999)
|
||||||
|
6. Modal content (3000)
|
||||||
|
7. Context menu (4000)
|
||||||
|
8. WYSIWYG menus (4500)
|
||||||
|
9. Toast notifications (5000)
|
||||||
|
|
||||||
|
#### 4. Key Benefits:
|
||||||
|
- Dropdowns now appear above modals
|
||||||
|
- Context menus appear above dropdowns and modals
|
||||||
|
- Toast notifications always appear on top
|
||||||
|
- Consistent and predictable stacking behavior
|
||||||
|
- Easy to adjust hierarchy by modifying central constants
|
||||||
|
|
||||||
|
#### 5. Testing:
|
||||||
|
Created `test-zindex.demo.ts` to verify stacking behavior with:
|
||||||
|
- Modal containing dropdown
|
||||||
|
- Context menu on modal
|
||||||
|
- Toast notifications
|
||||||
|
- Complex overlay combinations
|
||||||
|
|
||||||
|
### Usage:
|
||||||
|
Import and use the z-index constants in any component:
|
||||||
|
```typescript
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
|
|
||||||
|
// In styles
|
||||||
|
z-index: ${zIndexLayers.overlay.modal};
|
||||||
|
```
|
||||||
|
|
||||||
|
This system ensures proper stacking order for all overlay components and prevents z-index conflicts.
|
59
ts_web/elements/00zindex.ts
Normal file
59
ts_web/elements/00zindex.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* Central z-index management for consistent stacking order
|
||||||
|
* Higher numbers appear on top of lower numbers
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const zIndexLayers = {
|
||||||
|
// Base layer: Regular content
|
||||||
|
base: {
|
||||||
|
content: 'auto',
|
||||||
|
inputElements: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Fixed UI elements
|
||||||
|
fixed: {
|
||||||
|
appBar: 10,
|
||||||
|
sideMenu: 10,
|
||||||
|
mobileNav: 250,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Overlay backdrops (semi-transparent backgrounds)
|
||||||
|
backdrop: {
|
||||||
|
dropdown: 1999, // Below modals but above fixed elements
|
||||||
|
modal: 2999, // Below dropdowns on modals
|
||||||
|
contextMenu: 3999, // Below critical overlays
|
||||||
|
},
|
||||||
|
|
||||||
|
// Interactive overlays
|
||||||
|
overlay: {
|
||||||
|
dropdown: 2000, // Dropdowns and select menus
|
||||||
|
modal: 3000, // Modal dialogs
|
||||||
|
contextMenu: 4000, // Context menus and tooltips
|
||||||
|
toast: 5000, // Toast notifications (highest priority)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Special cases for nested elements
|
||||||
|
modalDropdown: 3500, // Dropdowns inside modals
|
||||||
|
wysiwygMenus: 4500, // Editor formatting menus
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// Helper function to get z-index value
|
||||||
|
export function getZIndex(category: keyof typeof zIndexLayers, subcategory?: string): number | string {
|
||||||
|
const categoryObj = zIndexLayers[category];
|
||||||
|
if (typeof categoryObj === 'object' && subcategory) {
|
||||||
|
return categoryObj[subcategory as keyof typeof categoryObj] || 'auto';
|
||||||
|
}
|
||||||
|
return typeof categoryObj === 'number' ? categoryObj : 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Z-index assignments for components
|
||||||
|
export const componentZIndex = {
|
||||||
|
'dees-modal': zIndexLayers.overlay.modal,
|
||||||
|
'dees-windowlayer': zIndexLayers.overlay.dropdown,
|
||||||
|
'dees-contextmenu': zIndexLayers.overlay.contextMenu,
|
||||||
|
'dees-toast': zIndexLayers.overlay.toast,
|
||||||
|
'dees-appui-mainmenu': zIndexLayers.fixed.appBar,
|
||||||
|
'dees-mobilenavigation': zIndexLayers.fixed.mobileNav,
|
||||||
|
'dees-slash-menu': zIndexLayers.wysiwygMenus,
|
||||||
|
'dees-formatting-menu': zIndexLayers.wysiwygMenus,
|
||||||
|
} as const;
|
@ -1,5 +1,6 @@
|
|||||||
import * as plugins from './00plugins.js';
|
import * as plugins from './00plugins.js';
|
||||||
import * as interfaces from './interfaces/index.js';
|
import * as interfaces from './interfaces/index.js';
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DeesElement,
|
DeesElement,
|
||||||
@ -46,7 +47,7 @@ export class DeesAppuiMainmenu extends DeesElement {
|
|||||||
.mainContainer {
|
.mainContainer {
|
||||||
--menuSize: 60px;
|
--menuSize: 60px;
|
||||||
color: ${cssManager.bdTheme('#666', '#ccc')};
|
color: ${cssManager.bdTheme('#666', '#ccc')};
|
||||||
z-index: 10;
|
z-index: ${zIndexLayers.fixed.appBar};
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: var(--menuSize);
|
width: var(--menuSize);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as plugins from './00plugins.js';
|
import * as plugins from './00plugins.js';
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DeesElement,
|
DeesElement,
|
||||||
@ -73,7 +74,7 @@ export class DeesAppuiProfileDropdown extends DeesElement {
|
|||||||
'0 4px 12px rgba(0, 0, 0, 0.15)',
|
'0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||||
'0 4px 12px rgba(0, 0, 0, 0.3)'
|
'0 4px 12px rgba(0, 0, 0, 0.3)'
|
||||||
)};
|
)};
|
||||||
z-index: 1000;
|
z-index: ${zIndexLayers.overlay.dropdown};
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0.95) translateY(-10px);
|
transform: scale(0.95) translateY(-10px);
|
||||||
transition: opacity 0.2s, transform 0.2s;
|
transition: opacity 0.2s, transform 0.2s;
|
||||||
@ -258,7 +259,7 @@ export class DeesAppuiProfileDropdown extends DeesElement {
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: rgba(0, 0, 0, 0.3);
|
background: rgba(0, 0, 0, 0.3);
|
||||||
z-index: 999;
|
z-index: ${zIndexLayers.backdrop.dropdown};
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
|
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
import { DeesWindowLayer } from './dees-windowlayer.js';
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
import './dees-icon.js';
|
import './dees-icon.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -74,7 +75,7 @@ export class DeesContextmenu extends DeesElement {
|
|||||||
eventArg.stopPropagation();
|
eventArg.stopPropagation();
|
||||||
const contextMenu = new DeesContextmenu();
|
const contextMenu = new DeesContextmenu();
|
||||||
contextMenu.style.position = 'fixed';
|
contextMenu.style.position = 'fixed';
|
||||||
contextMenu.style.zIndex = '10000';
|
contextMenu.style.zIndex = String(zIndexLayers.overlay.contextMenu);
|
||||||
contextMenu.style.opacity = '0';
|
contextMenu.style.opacity = '0';
|
||||||
contextMenu.style.transform = 'scale(0.95) translateY(-10px)';
|
contextMenu.style.transform = 'scale(0.95) translateY(-10px)';
|
||||||
contextMenu.menuItems = menuItemsArg;
|
contextMenu.menuItems = menuItemsArg;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as plugins from './00plugins.js';
|
import * as plugins from './00plugins.js';
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
import {
|
import {
|
||||||
cssManager,
|
cssManager,
|
||||||
css,
|
css,
|
||||||
@ -83,7 +84,7 @@ export class DeesMobilenavigation extends DeesElement {
|
|||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
transform: translateX(200px);
|
transform: translateX(200px);
|
||||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
z-index: 250;
|
z-index: ${zIndexLayers.fixed.mobileNav};
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
padding: 16px 32px;
|
padding: 16px 32px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as colors from './00colors.js';
|
import * as colors from './00colors.js';
|
||||||
import * as plugins from './00plugins.js';
|
import * as plugins from './00plugins.js';
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
|
|
||||||
import { demoFunc } from './dees-modal.demo.js';
|
import { demoFunc } from './dees-modal.demo.js';
|
||||||
import {
|
import {
|
||||||
@ -85,7 +86,7 @@ export class DeesModal extends DeesElement {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 2000;
|
z-index: ${zIndexLayers.overlay.modal};
|
||||||
}
|
}
|
||||||
.modal {
|
.modal {
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { customElement, DeesElement, type TemplateResult, html, css, property, cssManager } from '@design.estate/dees-element';
|
import { customElement, DeesElement, type TemplateResult, html, css, property, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
import { demoFunc } from './dees-toast.demo.js';
|
import { demoFunc } from './dees-toast.demo.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -32,7 +33,7 @@ export class DeesToast extends DeesElement {
|
|||||||
container.className = `toast-container toast-container-${position}`;
|
container.className = `toast-container toast-container-${position}`;
|
||||||
container.style.cssText = `
|
container.style.cssText = `
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 10000;
|
z-index: ${zIndexLayers.overlay.toast};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { customElement, DeesElement, domtools, type TemplateResult, html, property, type CSSResult, state, } from '@design.estate/dees-element';
|
import { customElement, DeesElement, domtools, type TemplateResult, html, property, type CSSResult, state, } from '@design.estate/dees-element';
|
||||||
|
import { zIndexLayers } from './00zindex.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@ -62,7 +63,7 @@ export class DeesWindowLayer extends DeesElement {
|
|||||||
background: rgba(0, 0, 0, 0.0);
|
background: rgba(0, 0, 0, 0.0);
|
||||||
backdrop-filter: brightness(1) ${this.options.blur ? 'blur(0px)' : ''};
|
backdrop-filter: brightness(1) ${this.options.blur ? 'blur(0px)' : ''};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 200;
|
z-index: ${zIndexLayers.backdrop.dropdown};
|
||||||
}
|
}
|
||||||
.slotContent {
|
.slotContent {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -71,7 +72,7 @@ export class DeesWindowLayer extends DeesElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 201;
|
z-index: ${zIndexLayers.overlay.dropdown};
|
||||||
}
|
}
|
||||||
|
|
||||||
.visible {
|
.visible {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
export * from './00zindex.js';
|
||||||
export * from './dees-appui-activitylog.js';
|
export * from './dees-appui-activitylog.js';
|
||||||
export * from './dees-appui-appbar.js';
|
export * from './dees-appui-appbar.js';
|
||||||
export * from './dees-appui-base.js';
|
export * from './dees-appui-base.js';
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
css,
|
css,
|
||||||
state,
|
state,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
import { zIndexLayers } from '../00zindex.js';
|
||||||
|
|
||||||
import { WysiwygFormatting } from './wysiwyg.formatting.js';
|
import { WysiwygFormatting } from './wysiwyg.formatting.js';
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ export class DeesFormattingMenu extends DeesElement {
|
|||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 10000;
|
z-index: ${zIndexLayers.wysiwygMenus};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
css,
|
css,
|
||||||
state,
|
state,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
import { zIndexLayers } from '../00zindex.js';
|
||||||
|
|
||||||
import { type ISlashMenuItem } from './wysiwyg.types.js';
|
import { type ISlashMenuItem } from './wysiwyg.types.js';
|
||||||
import { WysiwygShortcuts } from './wysiwyg.shortcuts.js';
|
import { WysiwygShortcuts } from './wysiwyg.shortcuts.js';
|
||||||
@ -49,7 +50,7 @@ export class DeesSlashMenu extends DeesElement {
|
|||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 10000;
|
z-index: ${zIndexLayers.wysiwygMenus};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user