react-dockable-desktop 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +385 -365
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -3
- package/dist/index.d.ts +90 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/styles.css +333 -17
- package/package.json +5 -5
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/WindowManager.tsx","../src/components/WindowManagerContext.tsx","../src/components/PanelRegistry.ts","../src/components/predefinedMessages.ts","../src/utils/rtl.ts","../src/components/FormContainerContext.ts","../src/components/PanelProviderContext.tsx","../src/forms/ConfirmationForm.tsx","../src/components/ModalStackRenderer.tsx","../src/components/SidePanelRenderer.tsx","../src/components/Sidebar.tsx"],"sourcesContent":["/**\n * @file WindowManager.tsx\n * @description Core component for react-dockable-desktop layout engine.\n * Renders the workspace desktop containing docked splits, tabbed panels, floated windows,\n * resize handles, context menus, and taskbar docks. Exposes lifecycle event listeners.\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useWindowManagerState, useWindowManagerActions, useFormatMessage, formatLabel, usePredefinedMessages, useStyleClasses } from './WindowManagerContext';\nimport type { LayoutNode, LayoutLeafNode } from './WindowManagerContext';\nimport { PanelRegistry } from './PanelRegistry';\nimport { isElementRtl } from '../utils/rtl';\nimport { JsonContextMenu, type JsonContextMenuRef } from 'replace-react-contexify';\nimport 'replace-react-contexify/styles.css';\nimport { FormContainerProvider } from './FormContainerContext';\nimport type { FormContainerContract } from './FormContainerContext';\nimport { usePanelActions } from './PanelProviderContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\n\n// DOM Element Cache for preserving contexts (WebGL map, text area etc.)\nconst domCache = new Map<string, HTMLDivElement>();\nconst hiddenContainerId = 'preserved-dom-container';\n\nconst DefaultGridIcon = (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ display: 'block' }}>\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"9\" rx=\"1\" />\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"5\" rx=\"1\" />\n <rect x=\"14\" y=\"12\" width=\"7\" height=\"9\" rx=\"1\" />\n <rect x=\"3\" y=\"16\" width=\"7\" height=\"5\" rx=\"1\" />\n </svg>\n);\n\nconst getOrCreateDomCacheElement = (id: string): HTMLDivElement => {\n let el = domCache.get(id);\n if (!el) {\n el = document.createElement('div');\n el.style.width = '100%';\n el.style.height = '100%';\n domCache.set(id, el);\n }\n return el;\n};\n\n\n// ==========================================\n// 3. Persistent DOM Container Host & Slot\n// ==========================================\n\nconst renderPanelContent = (id: string, componentKey: string) => {\n const registryEntry = PanelRegistry.get(componentKey);\n if (!registryEntry) {\n return (\n <div className=\"w-100 h-100 d-flex flex-column align-items-center justify-content-center bg-transparent text-danger font-monospace p-3 text-center\" style={{ border: '2px dashed var(--bs-danger, #dc3545)' }}>\n <h6 className=\"fw-bold mb-1\">⚠️ Component Unregistered</h6>\n <span className=\"small text-muted\">Key: {componentKey}</span>\n </div>\n );\n }\n const Component = registryEntry.Component;\n return <Component panelId={id} />;\n};\n\nconst activePanelDimensions = new Map<string, { width: number; height: number }>();\n\nconst panelLifecycleRegistry = new Map<string, {\n onClose: Set<() => void>;\n onMinimize: Set<() => void>;\n onRestore: Set<() => void>;\n onResize: Set<(w: number, h: number) => void>;\n}>();\n\nconst getOrCreateLifecycleRegistry = (panelId: string) => {\n let entry = panelLifecycleRegistry.get(panelId);\n if (!entry) {\n entry = {\n onClose: new Set(),\n onMinimize: new Set(),\n onRestore: new Set(),\n onResize: new Set(),\n };\n panelLifecycleRegistry.set(panelId, entry);\n }\n return entry;\n};\n\nconst PreservedDOMWrapper: React.FC<{ panelId: string }> = ({ panelId }) => {\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const cachedEl = getOrCreateDomCacheElement(panelId);\n host.appendChild(cachedEl);\n\n const resizeObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n const { width, height } = entry.contentRect;\n if (width > 0 && height > 0) {\n activePanelDimensions.set(panelId, { width, height });\n const lifecycle = panelLifecycleRegistry.get(panelId);\n if (lifecycle) {\n lifecycle.onResize.forEach(h => h(width, height));\n }\n }\n }\n });\n resizeObserver.observe(host);\n\n return () => {\n resizeObserver.disconnect();\n let hiddenContainer = document.getElementById(hiddenContainerId);\n if (!hiddenContainer) {\n hiddenContainer = document.createElement('div');\n hiddenContainer.id = hiddenContainerId;\n hiddenContainer.style.display = 'none';\n document.body.appendChild(hiddenContainer);\n }\n hiddenContainer.appendChild(cachedEl);\n };\n }, [panelId]);\n\n return <div ref={hostRef} className=\"w-100 h-100\" />;\n};\n\nconst PreviewDOMWrapper: React.FC<{ panelId: string }> = ({ panelId }) => {\n const state = useWindowManagerState();\n const formatMessage = useFormatMessage();\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n const panel = state.panels[panelId];\n const regEntry = panel ? PanelRegistry.get(panel.component) : null;\n const disableLivePreview = regEntry?.defaultOptions?.disableLivePreview || false;\n\n const lastSize = activePanelDimensions.get(panelId) || { width: 800, height: 500 };\n const origW = lastSize.width;\n const origH = lastSize.height;\n const maxW = 220;\n const maxH = 140;\n const scale = Math.min(maxW / origW, maxH / origH);\n\n useEffect(() => {\n if (disableLivePreview) return;\n\n const host = hostRef.current;\n if (!host) return;\n\n const cachedEl = domCache.get(panelId);\n if (!cachedEl) return;\n\n host.appendChild(cachedEl);\n\n return () => {\n let hiddenContainer = document.getElementById(hiddenContainerId);\n if (!hiddenContainer) {\n hiddenContainer = document.createElement('div');\n hiddenContainer.id = hiddenContainerId;\n hiddenContainer.style.display = 'none';\n document.body.appendChild(hiddenContainer);\n }\n hiddenContainer.appendChild(cachedEl);\n };\n }, [panelId, disableLivePreview]);\n\n if (disableLivePreview) {\n const displayW = origW * scale;\n const displayH = origH * scale;\n const rawTitle = panel?.title || regEntry?.defaultOptions?.title || 'Panel';\n const title = formatLabel(rawTitle, formatMessage);\n const initialChar = (Array.from(title)[0] || 'P').toUpperCase();\n\n return (\n <div\n className=\"taskbar-item-preview-frame d-flex align-items-center justify-content-center\"\n style={{\n width: `${displayW}px`,\n height: `${displayH}px`,\n background: 'rgba(108, 117, 125, 0.15)',\n border: '1px dashed var(--taskbar-item-border, rgba(255, 255, 255, 0.15))'\n }}\n >\n <div\n style={{\n fontSize: '2rem',\n fontWeight: 600,\n color: 'var(--panel-title-color, var(--panel-text, rgba(255, 255, 255, 0.85)))',\n userSelect: 'none'\n }}\n >\n {initialChar}\n </div>\n </div>\n );\n }\n\n return (\n <div\n className=\"taskbar-item-preview-frame\"\n style={{\n width: `${origW * scale}px`,\n height: `${origH * scale}px`,\n }}\n >\n <div\n ref={hostRef}\n className=\"taskbar-item-preview-host\"\n style={{\n width: `${origW}px`,\n height: `${origH}px`,\n transform: `scale(${scale})`,\n transformOrigin: 'top left',\n position: 'absolute',\n top: 0,\n left: 0,\n ['--preview-scale' as string]: scale\n }}\n />\n </div>\n );\n};\n\nconst FormContainerProviderWrapper: React.FC<{ panelId: string; children: React.ReactNode }> = ({ panelId, children }) => {\n const state = useWindowManagerState();\n const { requestClosePanel, setPanelDirty, registerCloseGuard, unregisterCloseGuard, updatePanelTitle } = useWindowManagerActions();\n\n const isMin = state.minimized.some(m => m.id === panelId);\n const prevMinRef = useRef(isMin);\n\n useEffect(() => {\n const entry = panelLifecycleRegistry.get(panelId);\n if (!entry) return;\n\n if (isMin && !prevMinRef.current) {\n entry.onMinimize.forEach(h => h());\n } else if (!isMin && prevMinRef.current) {\n entry.onRestore.forEach(h => h());\n }\n prevMinRef.current = isMin;\n }, [isMin, panelId]);\n\n useEffect(() => {\n return () => {\n const entry = panelLifecycleRegistry.get(panelId);\n if (entry) {\n entry.onClose.forEach(h => h());\n panelLifecycleRegistry.delete(panelId);\n }\n };\n }, [panelId]);\n\n const contract = React.useMemo<FormContainerContract>(() => ({\n requestClose: (options) => requestClosePanel(panelId, options),\n setDirty: (dirty) => setPanelDirty(panelId, dirty),\n onCloseRequested: (handler) => {\n registerCloseGuard(panelId, handler);\n return () => unregisterCloseGuard(panelId);\n },\n setTitle: (title) => updatePanelTitle(panelId, title),\n instanceId: panelId,\n onClose: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onClose.add(handler);\n return () => reg.onClose.delete(handler);\n },\n onMinimize: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onMinimize.add(handler);\n return () => reg.onMinimize.delete(handler);\n },\n onRestore: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onRestore.add(handler);\n return () => reg.onRestore.delete(handler);\n },\n onResize: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onResize.add(handler);\n return () => reg.onResize.delete(handler);\n }\n }), [panelId, requestClosePanel, setPanelDirty, registerCloseGuard, unregisterCloseGuard, updatePanelTitle]);\n\n return (\n <FormContainerProvider value={contract}>\n {children}\n </FormContainerProvider>\n );\n};\n\n\n\n\n// ==========================================\n// 4. Panel Tab Headers & Split Layout Component\n// ==========================================\n\ninterface WorkspaceGridProps {\n node: LayoutNode;\n path: number[];\n onTabRightClick: (id: string, e: React.MouseEvent) => void;\n activeDropZone: { leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null;\n onHoverDropZone: (leafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center' | null) => void;\n onTabDragStart: (id: string, e: React.MouseEvent) => void;\n hoveredTab: { leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null;\n onTabHover: (leafId: string, panelId: string, index: number, side: 'left' | 'right' | null) => void;\n defaultPanelIcon?: React.ReactNode;\n onRequestClosePanel: (id: string) => void;\n}\n\nconst WorkspaceGrid: React.FC<WorkspaceGridProps> = ({ node, path, onTabRightClick, activeDropZone, onHoverDropZone, onTabDragStart, hoveredTab, onTabHover, defaultPanelIcon, onRequestClosePanel }) => {\n const { updateSplitSizes } = useWindowManagerActions();\n\n if (node.type === 'leaf') {\n return <LeafGroup leaf={node} onTabRightClick={onTabRightClick} activeDropZone={activeDropZone} onHoverDropZone={onHoverDropZone} onTabDragStart={onTabDragStart} hoveredTab={hoveredTab} onTabHover={onTabHover} defaultPanelIcon={defaultPanelIcon} onRequestClosePanel={onRequestClosePanel} />;\n }\n\n const isRow = node.orientation === 'horizontal';\n\n const handleResizerMouseDown = (idx: number, e: React.MouseEvent) => {\n e.preventDefault();\n const startOffset = isRow ? e.clientX : e.clientY;\n const startSizes = [...node.sizes];\n\n // Add active classes directly for zero-latency DOM responsiveness during drag\n const resizerEl = e.currentTarget as HTMLDivElement;\n resizerEl.classList.add('active');\n document.body.classList.add('resizing-active', isRow ? 'resizing-row-active' : 'resizing-col-active');\n\n // Capture the parent element and its size synchronously on mousedown\n const parentEl = e.currentTarget.parentElement;\n const parentSize = parentEl\n ? (isRow ? parentEl.clientWidth : parentEl.clientHeight)\n : (isRow ? 1000 : 800);\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const currentOffset = isRow ? moveEvent.clientX : moveEvent.clientY;\n const delta = currentOffset - startOffset;\n\n const deltaPercentage = delta / parentSize;\n\n const newSizes = [...startSizes];\n newSizes[idx] += deltaPercentage;\n newSizes[idx + 1] -= deltaPercentage;\n\n // Restrict range bounds\n if (newSizes[idx] > 0.1 && newSizes[idx + 1] > 0.1) {\n updateSplitSizes(path, newSizes);\n }\n };\n\n const handleMouseUp = () => {\n resizerEl.classList.remove('active');\n document.body.classList.remove('resizing-active', 'resizing-row-active', 'resizing-col-active');\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n };\n\n return (\n <div\n className={`d-flex w-100 h-100 ${isRow ? 'flex-row' : 'flex-column'}`}\n style={{ overflow: 'hidden', position: 'relative' }}\n >\n {node.children.map((child, idx) => {\n const size = node.sizes[idx] * 100;\n return (\n <React.Fragment key={idx}>\n <div style={{ flexGrow: node.sizes[idx], flexBasis: `${size}%`, overflow: 'hidden', position: 'relative' }}>\n <WorkspaceGrid node={child} path={[...path, idx]} onTabRightClick={onTabRightClick} activeDropZone={activeDropZone} onHoverDropZone={onHoverDropZone} onTabDragStart={onTabDragStart} hoveredTab={hoveredTab} onTabHover={onTabHover} defaultPanelIcon={defaultPanelIcon} onRequestClosePanel={onRequestClosePanel} />\n </div>\n {idx < node.children.length - 1 && (\n <div\n onMouseDown={(e) => handleResizerMouseDown(idx, e)}\n style={{\n cursor: isRow ? 'col-resize' : 'row-resize',\n width: isRow ? '1px' : '100%',\n height: isRow ? '100%' : '1px',\n zIndex: 20,\n }}\n className=\"resizer-bar\"\n />\n )}\n </React.Fragment>\n );\n })}\n </div>\n );\n};\n\ninterface LeafGroupProps {\n leaf: LayoutLeafNode;\n onTabRightClick: (id: string, e: React.MouseEvent) => void;\n activeDropZone: { leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null;\n onHoverDropZone: (leafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center' | null) => void;\n onTabDragStart: (id: string, e: React.MouseEvent) => void;\n hoveredTab: { leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null;\n onTabHover: (leafId: string, panelId: string, index: number, side: 'left' | 'right' | null) => void;\n defaultPanelIcon?: React.ReactNode;\n onRequestClosePanel: (id: string) => void;\n}\n\nconst LeafGroup: React.FC<LeafGroupProps> = ({ leaf, onTabRightClick, activeDropZone, onHoverDropZone, onTabDragStart, hoveredTab, onTabHover, defaultPanelIcon, onRequestClosePanel }) => {\n const state = useWindowManagerState();\n const { openPanel, closeLeafGroup, setActivePanel } = useWindowManagerActions();\n const formatMessage = useFormatMessage();\n const messages = usePredefinedMessages();\n const { windowClass, windowBodyClass } = useStyleClasses();\n\n const selectTab = (id: string) => {\n openPanel(id, state.panels[id].component);\n setActivePanel(id);\n };\n\n return (\n <div\n data-active-panel-id={leaf.activePanelId || ''}\n className={`workspace-panel w-100 h-100 d-flex flex-column ${windowClass ?? ''}`}\n style={{ overflow: 'hidden', position: 'relative' }}\n >\n {/* Tab Headers */}\n <div className=\"workspace-tab-bar d-flex flex-row justify-content-between align-items-center\" style={{ minHeight: '38px' }}>\n <div\n className=\"d-flex flex-row overflow-x-auto flex-grow-1 tab-headers-container\"\n style={{ scrollbarWidth: 'none' }}\n onMouseMove={(e) => {\n if (state.draggedPanelId && e.target === e.currentTarget) {\n onTabHover(leaf.id, 'EMPTY', leaf.panels.length, 'right');\n }\n }}\n onMouseLeave={(e) => {\n if (state.draggedPanelId && e.target === e.currentTarget) {\n onTabHover(leaf.id, '', -1, null);\n }\n }}\n >\n {leaf.panels.map((id, idx) => {\n const panel = state.panels[id];\n if (!panel) return null;\n const isSelected = leaf.activePanelId === id;\n const isGloballyActive = state.activePanelId === id;\n\n const registryEntry = PanelRegistry.get(panel.component);\n const options = registryEntry?.defaultOptions;\n\n const isHovered = hoveredTab && hoveredTab.leafId === leaf.id && hoveredTab.panelId === id;\n const isLast = idx === leaf.panels.length - 1;\n const isHoveredEmpty = hoveredTab && hoveredTab.leafId === leaf.id && hoveredTab.panelId === 'EMPTY' && isLast;\n const sideClass = isHovered\n ? (hoveredTab.side === 'left' ? 'drag-hover-left' : 'drag-hover-right')\n : (isHoveredEmpty ? 'drag-hover-right' : '');\n\n const tabFocusClass = isSelected\n ? (isGloballyActive ? 'active workspace-tab-active-focused' : 'active workspace-tab-active-unfocused')\n : 'workspace-tab-inactive';\n\n return (\n <div\n key={id}\n onClick={() => selectTab(id)}\n onMouseDown={(e) => {\n if (options?.canDrag !== false) {\n onTabDragStart(id, e);\n }\n }}\n onContextMenu={(e) => onTabRightClick(id, e)}\n onMouseMove={(e) => {\n if (state.draggedPanelId) {\n const rect = e.currentTarget.getBoundingClientRect();\n const relativeX = e.clientX - rect.left;\n const side = relativeX < rect.width / 2 ? 'left' : 'right';\n onTabHover(leaf.id, id, idx, side);\n }\n }}\n onMouseLeave={() => {\n if (state.draggedPanelId) {\n onTabHover(leaf.id, '', -1, null);\n }\n }}\n className={`workspace-tab ${tabFocusClass} ${sideClass}`}\n style={{ cursor: options?.canDrag === false ? 'default' : 'pointer' }}\n >\n <span className=\"text-truncate d-flex align-items-center\" style={{ maxWidth: '120px' }}>\n <span className=\"workspace-tab-icon\">{options?.icon || defaultPanelIcon || DefaultGridIcon}</span>\n <span>\n {formatLabel(panel.title, formatMessage)}\n {panel.dirty ? ' *' : ''}\n </span>\n </span>\n {options?.renderHeaderActions && (\n <span\n className=\"tab-header-actions ms-auto d-flex align-items-center me-1\"\n style={{ gap: 'var(--header-button-gap, 4px)' }}\n onClick={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n >\n {options.renderHeaderActions(id)}\n </span>\n )}\n {options?.canClose !== false && (\n <span\n onClick={(e) => {\n e.stopPropagation();\n onRequestClosePanel(id);\n }}\n title={formatLabel(messages.closeTab, formatMessage)}\n className={`close-tab-x ${options?.renderHeaderActions ? '' : 'ms-auto'} d-flex align-items-center justify-content-center`}\n style={{ width: '18px', height: '18px' }}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n )}\n </div>\n );\n })}\n </div>\n\n {/* Empty group close button — only visible when keepOnEmpty keeps the group alive */}\n {leaf.panels.length === 0 && leaf.keepOnEmpty && leaf.canClose !== false && (\n <span\n onClick={() => closeLeafGroup(leaf.id)}\n className=\"close-tab-x d-flex align-items-center justify-content-center me-2 header-close-empty-group\"\n style={{ width: '18px', height: '18px', cursor: 'pointer' }}\n title={formatLabel(messages.closeEmptyGroup, formatMessage)}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n )}\n </div>\n\n {/* Tab Content Display Area */}\n <div className={`flex-grow-1 w-100 h-100 bg-transparent ${windowBodyClass ?? ''}`} style={{ position: 'relative', overflow: 'hidden' }}>\n {leaf.activePanelId && state.panels[leaf.activePanelId] ? (\n <PreservedDOMWrapper key={leaf.activePanelId} panelId={leaf.activePanelId} />\n ) : (\n <div className=\"w-100 h-100 d-flex align-items-center justify-content-center font-monospace text-muted small empty-leaf-placeholder\">\n <span>Empty Workspace Section</span>\n </div>\n )}\n\n {/* Drag overlay targets cross */}\n {state.draggedPanelId !== null && (\n <div className=\"dock-drop-zone-overlay\">\n <div className=\"dock-target-cross\">\n {/* Top target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'top')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-top\"\n >\n ▲\n </div>\n {/* Bottom target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'bottom')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-bottom\"\n >\n ▼\n </div>\n {/* Left target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'left')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-left\"\n >\n ◀\n </div>\n {/* Right target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'right')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-right\"\n >\n ▶\n </div>\n {/* Center target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'center')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-center\"\n >\n ▣\n </div>\n </div>\n </div>\n )}\n\n {/* Visual preview highlight overlay */}\n {state.draggedPanelId !== null && activeDropZone !== null && activeDropZone.leafId === leaf.id && (\n <div\n className=\"dock-preview-highlight\"\n style={{\n left: activeDropZone.position === 'right' ? '50%' : '0',\n top: activeDropZone.position === 'bottom' ? '50%' : '0',\n width: (activeDropZone.position === 'left' || activeDropZone.position === 'right') ? '50%' : '100%',\n height: (activeDropZone.position === 'top' || activeDropZone.position === 'bottom') ? '50%' : '100%',\n }}\n />\n )}\n </div>\n </div>\n );\n};\n\n\n// ==========================================\n// 5. WindowManager (Main Render Component)\n// ==========================================\n\nexport interface WindowManagerProps {\n skin?: string;\n defaultPanelIcon?: React.ReactNode;\n}\n\nexport const WindowManager: React.FC<WindowManagerProps> = ({ skin = 'vscode', defaultPanelIcon }) => {\n const state = useWindowManagerState();\n const { restorePanel, minimizePanel, requestClosePanel, maximizePanel, updateFloatingPosition, bringToFront, floatPanel, setDraggedPanelId, dockPanelToGroup, movePanelOrder, dockPanelToWorkspaceEdge, setActivePanel, setDirection } = useWindowManagerActions();\n const { openModal } = usePanelActions();\n const formatMessage = useFormatMessage();\n const messages = usePredefinedMessages();\n\n const handleRequestClose = React.useCallback((id: string) => {\n const panel = state.panels[id];\n requestClosePanel(id, {\n onConfirm: (customOpts) => new Promise<boolean>((resolve) => {\n const opts = customOpts || panel?.dirtyOptions;\n const baseTitle = panel ? formatLabel(panel.title, formatMessage) : 'Panel';\n openModal(\n ConfirmationForm,\n {\n title: opts?.title || messages.unsavedChangesTitle,\n message: opts?.message || {\n id: messages.unsavedChangesMessage.id,\n defaultMessage: messages.unsavedChangesMessage.defaultMessage,\n values: { title: baseTitle }\n },\n alert: opts?.alert,\n alertType: opts?.alertType || 'danger',\n useYesNoTitles: true,\n onOK: () => resolve(true),\n onCancel: () => resolve(false),\n },\n { size: 'small' }\n );\n })\n });\n }, [requestClosePanel, state.panels, formatMessage, openModal, messages]);\n\n const { windowClass, windowBodyClass } = useStyleClasses();\n const taskbarRef = useRef<HTMLDivElement | null>(null);\n const contextMenuRef = useRef<JsonContextMenuRef>(null);\n\n const [hoveredMinimized, setHoveredMinimized] = useState<{ id: string; rect: DOMRect; title: string | any; component: string } | null>(null);\n const minimizedTooltipTimeoutRef = useRef<number>(null);\n const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);\n\n useEffect(() => {\n return () => {\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n if (hoveredMinimized) {\n const isStillMinimized = state.minimized.some(m => m.id === hoveredMinimized.id);\n if (!isStillMinimized) {\n setHoveredMinimized(null);\n }\n }\n }, [state.minimized, hoveredMinimized]);\n\n const [activeDropZone, setActiveDropZone] = useState<{ leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null>(null);\n const activeDropZoneRef = useRef<{ leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null>(null);\n const [dragPos, setDragPos] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n\n const [activeEdgeDrop, setActiveEdgeDropState] = useState<'left' | 'right' | 'top' | 'bottom' | null>(null);\n const activeEdgeDropRef = useRef<'left' | 'right' | 'top' | 'bottom' | null>(null);\n const setActiveEdgeDrop = (val: 'left' | 'right' | 'top' | 'bottom' | null) => {\n setActiveEdgeDropState(val);\n activeEdgeDropRef.current = val;\n };\n\n const [hoveredTab, setHoveredTab] = useState<{ leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null>(null);\n const hoveredTabRef = useRef<{ leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null>(null);\n\n const handleTabHover = (leafId: string, panelId: string, index: number, side: 'left' | 'right' | null) => {\n const val = side ? { leafId, panelId, index, side } : null;\n setHoveredTab(val);\n hoveredTabRef.current = val;\n };\n\n const handleHoverDropZone = (leafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center' | null) => {\n const val = position ? { leafId, position } : null;\n setActiveDropZone(val);\n activeDropZoneRef.current = val;\n };\n\n const handleTabDragStart = (id: string, e: React.MouseEvent) => {\n // Only handle left click drags\n if (e.button !== 0) return;\n\n const startX = e.clientX;\n const startY = e.clientY;\n let dragStarted = false;\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const dx = moveEvent.clientX - startX;\n const dy = moveEvent.clientY - startY;\n\n // Threshold trigger (5px)\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n\n if (dragStarted) {\n setDragPos({ x: moveEvent.clientX, y: moveEvent.clientY });\n }\n };\n\n const handleMouseUp = (moveEvent: MouseEvent) => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUpWrapper);\n\n if (dragStarted) {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n\n if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, edgeDrop);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') {\n targetIndex += 1;\n }\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, dropZone.position);\n } else {\n // Float at dropped coordinates\n floatPanel(id, {\n x: moveEvent.clientX - 150,\n y: moveEvent.clientY - 15,\n width: 450,\n height: 350\n });\n }\n setDraggedPanelId(null);\n setActiveDropZone(null);\n activeDropZoneRef.current = null;\n setHoveredTab(null);\n hoveredTabRef.current = null;\n setActiveEdgeDrop(null);\n }\n };\n\n const handleMouseUpWrapper = (moveEvent: MouseEvent) => {\n handleMouseUp(moveEvent);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUpWrapper);\n };\n\n const handleTabRightClick = (id: string, e: React.MouseEvent) => {\n e.preventDefault();\n const panel = state.panels[id];\n if (!panel) return;\n const registryEntry = PanelRegistry.get(panel.component);\n const options = registryEntry?.defaultOptions;\n\n const items = [];\n if (options?.canDrag !== false) {\n items.push({\n label: formatLabel(messages.floatWindow, formatMessage),\n action: () => floatPanel(id)\n });\n }\n if (options?.canMinimize !== false) {\n items.push({\n label: formatLabel(messages.minimizePanel, formatMessage),\n action: () => minimizePanel(id)\n });\n }\n if (items.length > 0 && options?.canClose !== false) {\n items.push({ separator: true as const });\n }\n if (options?.canClose !== false) {\n items.push({\n label: formatLabel(messages.closeTab, formatMessage),\n action: () => handleRequestClose(id)\n });\n }\n\n if (items.length === 0) return;\n\n contextMenuRef.current?.show({\n event: e,\n contextMenu: { items }\n });\n };\n\n const handleMinimizedRightClick = (id: string, e: React.MouseEvent) => {\n e.preventDefault();\n setHoveredMinimized(null);\n contextMenuRef.current?.show({\n event: e,\n contextMenu: {\n items: [\n {\n label: formatLabel(messages.restorePanel, formatMessage),\n action: () => restorePanel(id)\n },\n {\n label: formatLabel(messages.maximizePanel, formatMessage),\n action: () => maximizePanel(id)\n },\n { separator: true },\n {\n label: formatLabel(messages.closePanel, formatMessage),\n action: () => handleRequestClose(id)\n }\n ]\n }\n });\n };\n\n // Clean up domCache for panels that are no longer in state.panels\n useEffect(() => {\n const keys = Object.keys(state.panels);\n for (const cachedId of Array.from(domCache.keys())) {\n if (!keys.includes(cachedId)) {\n domCache.delete(cachedId);\n }\n }\n }, [state.panels]);\n\n // Safe window blur handler to cancel sticky dragging states when iframe/webview loses focus\n useEffect(() => {\n const handleWindowBlur = () => {\n if (state.draggedPanelId !== null) {\n setDraggedPanelId(null);\n setActiveDropZone(null);\n setHoveredTab(null);\n }\n };\n window.addEventListener('blur', handleWindowBlur);\n return () => {\n window.removeEventListener('blur', handleWindowBlur);\n };\n }, [state.draggedPanelId]);\n\n const workspaceRef = useRef<HTMLDivElement | null>(null);\n const [workspaceSize, setWorkspaceSize] = useState({ width: 1024, height: 768 });\n\n // Dynamically observe the workspace container bounds (accounts for sidebar expanding/collapsing and taskbar showing/hiding)\n useEffect(() => {\n const el = workspaceRef.current;\n if (!el) return;\n\n const observer = new ResizeObserver((entries) => {\n if (!entries || entries.length === 0) return;\n const rect = entries[0].contentRect;\n setWorkspaceSize({\n width: Math.max(100, rect.width),\n height: Math.max(100, rect.height)\n });\n });\n\n observer.observe(el);\n return () => {\n observer.disconnect();\n };\n }, []);\n\n // Dynamically observe document/container direction changes\n useEffect(() => {\n const el = workspaceRef.current;\n if (!el) return;\n\n const updateDir = () => {\n const isRtl = isElementRtl(el);\n setDirection(isRtl ? 'rtl' : 'ltr');\n };\n\n updateDir();\n\n const observer = new MutationObserver(updateDir);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] });\n observer.observe(document.body, { attributes: true, attributeFilter: ['dir'] });\n\n const closestDir = el.closest('[dir]');\n if (closestDir && closestDir !== document.documentElement && closestDir !== document.body) {\n observer.observe(closestDir, { attributes: true, attributeFilter: ['dir'] });\n }\n\n return () => {\n observer.disconnect();\n };\n }, [setDirection]);\n\n // Sync / Realignment Effect when actual workspace size changes\n useEffect(() => {\n const viewW = workspaceSize.width;\n const viewH = workspaceSize.height;\n\n state.floating.forEach(w => {\n const winW = typeof w.width === 'string' ? parseFloat(w.width) : w.width;\n const winH = typeof w.height === 'string' ? parseFloat(w.height) : w.height;\n const winX = typeof w.x === 'string' ? parseFloat(w.x) : w.x;\n const winY = typeof w.y === 'string' ? parseFloat(w.y) : w.y;\n\n let newWidth = winW;\n let newHeight = winH;\n let newX = winX;\n let newY = winY;\n let changed = false;\n\n // Clamp window size if it exceeds the new workspace size\n if (newWidth > viewW) {\n newWidth = Math.max(200, viewW - 20);\n changed = true;\n }\n if (newHeight > viewH) {\n newHeight = Math.max(150, viewH - 40);\n changed = true;\n }\n\n const GAP = 10;\n\n // Align sticky borders\n if (w.stickyRight) {\n newX = viewW - newWidth - GAP;\n changed = true;\n } else {\n // Bounding clamp for non-sticky windows to prevent falling off-screen\n const maxX = viewW - 100; // Keep at least 100px of titlebar visible\n if (newX > maxX) {\n newX = Math.max(0, maxX);\n changed = true;\n }\n }\n\n if (w.stickyBottom) {\n newY = viewH - newHeight - GAP;\n changed = true;\n } else {\n const maxY = viewH - 40; // Keep titlebar clickable\n if (newY > maxY) {\n newY = Math.max(0, maxY);\n changed = true;\n }\n }\n\n if (changed) {\n updateFloatingPosition(w.id, {\n x: newX,\n y: newY,\n width: newWidth,\n height: newHeight\n });\n }\n });\n }, [workspaceSize, state.floating, updateFloatingPosition]);\n\n // Global Window Focus Event Delegation (Left-click anywhere inside a window or grid panel focuses it)\n useEffect(() => {\n const handleMouseDownGlobal = (e: MouseEvent) => {\n // Only handle left clicks (button === 0)\n if (e.button !== 0) return;\n\n const target = e.target as HTMLElement | null;\n if (!target) return;\n\n // 1. Check if click is inside a floating window\n const windowEl = target.closest('.floating-window') as HTMLElement | null;\n if (windowEl) {\n const winId = windowEl.getAttribute('data-window-id');\n if (winId) {\n setActivePanel(winId);\n bringToFront(winId);\n }\n return;\n }\n\n // 2. Check if click is inside a grid split pane\n const panelEl = target.closest('.workspace-panel') as HTMLElement | null;\n if (panelEl) {\n const panelId = panelEl.getAttribute('data-active-panel-id');\n if (panelId) {\n setActivePanel(panelId);\n }\n }\n };\n\n document.addEventListener('mousedown', handleMouseDownGlobal);\n return () => {\n document.removeEventListener('mousedown', handleMouseDownGlobal);\n };\n }, [bringToFront, setActivePanel]);\n\n // Floating Window dragging handler\n const startDrag = (id: string, e: React.MouseEvent) => {\n const floatingWin = state.floating.find(w => w.id === id);\n if (!floatingWin || floatingWin.maximized) return;\n bringToFront(id);\n\n const startX = e.clientX;\n const startY = e.clientY;\n const titlebarEl = e.currentTarget as HTMLDivElement;\n const windowEl = titlebarEl.closest('.floating-window') as HTMLDivElement | null;\n const startPosX = windowEl ? windowEl.offsetLeft : 0;\n const startPosY = windowEl ? windowEl.offsetTop : 0;\n let dragStarted = false;\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const dx = moveEvent.clientX - startX;\n const dy = moveEvent.clientY - startY;\n\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n\n if (dragStarted) {\n const newX = startPosX + dx;\n const newY = startPosY + dy;\n\n // Dragging clears all sticky anchoring\n updateFloatingPosition(id, {\n x: newX,\n y: newY,\n stickyRight: false,\n stickyBottom: false\n });\n }\n };\n\n const handleMouseUp = () => {\n if (dragStarted) {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n\n if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, edgeDrop);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') {\n targetIndex += 1;\n }\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, dropZone.position);\n }\n setDraggedPanelId(null);\n setActiveDropZone(null);\n activeDropZoneRef.current = null;\n setHoveredTab(null);\n hoveredTabRef.current = null;\n setActiveEdgeDrop(null);\n }\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n };\n\n // Floating Window resizing handler\n const startResize = (id: string, e: React.MouseEvent) => {\n e.stopPropagation();\n const floatingWin = state.floating.find(w => w.id === id);\n if (!floatingWin || floatingWin.maximized) return;\n bringToFront(id);\n\n const startX = e.clientX;\n const startY = e.clientY;\n const handleEl = e.currentTarget as HTMLDivElement;\n const windowEl = handleEl.closest('.floating-window') as HTMLDivElement | null;\n const startW = windowEl ? windowEl.offsetWidth : 400;\n const startH = windowEl ? windowEl.offsetHeight : 300;\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const dw = moveEvent.clientX - startX;\n const dh = moveEvent.clientY - startY;\n\n let newWidth = Math.max(200, startW + dw);\n let newHeight = Math.max(150, startH + dh);\n\n let newX = floatingWin.x;\n let newY = floatingWin.y;\n\n const viewW = workspaceSize.width;\n const viewH = workspaceSize.height;\n\n const parsedX = typeof floatingWin.x === 'string' ? parseFloat(floatingWin.x) : floatingWin.x;\n const parsedY = typeof floatingWin.y === 'string' ? parseFloat(floatingWin.y) : floatingWin.y;\n const parsedW = typeof floatingWin.width === 'string' ? parseFloat(floatingWin.width) : floatingWin.width;\n const parsedH = typeof floatingWin.height === 'string' ? parseFloat(floatingWin.height) : floatingWin.height;\n\n const isRightSnapped = Math.abs(parsedX + parsedW - viewW) < 4;\n const isBottomSnapped = Math.abs(parsedY + parsedH - viewH) < 4;\n\n if (isRightSnapped) {\n newX = viewW - newWidth;\n if (newX < 0) {\n newX = 0;\n newWidth = viewW;\n }\n }\n\n if (isBottomSnapped) {\n newY = viewH - newHeight;\n if (newY < 0) {\n newY = 0;\n newHeight = viewH;\n }\n }\n\n updateFloatingPosition(id, {\n x: newX,\n y: newY,\n width: newWidth,\n height: newHeight,\n stickyRight: isRightSnapped,\n stickyBottom: isBottomSnapped\n });\n };\n\n const handleMouseUp = () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n };\n\n // horizontal scroll for minimized taskbar\n const scrollTaskbar = (direction: 'left' | 'right') => {\n if (taskbarRef.current) {\n const amount = direction === 'left' ? -150 : 150;\n taskbarRef.current.scrollBy({ left: amount, behavior: 'smooth' });\n }\n };\n\n // Fetch the active bs-theme from documentElement to make sure nested variables resolve correctly\n const [currentBsTheme, setCurrentBsTheme] = useState<'dark' | 'light'>('dark');\n useEffect(() => {\n const updateThemeState = () => {\n const activeTheme = document.documentElement.getAttribute('data-bs-theme') === 'light' ? 'light' : 'dark';\n setCurrentBsTheme(activeTheme);\n };\n updateThemeState();\n const obs = new MutationObserver(updateThemeState);\n obs.observe(document.documentElement, { attributes: true, attributeFilter: ['data-bs-theme'] });\n return () => obs.disconnect();\n }, []);\n\n return (\n <div\n data-workspace-skin={skin}\n data-bs-theme={currentBsTheme}\n className=\"d-flex flex-column w-100 h-100 overflow-hidden\"\n style={{ userSelect: 'none' }}\n dir={state.dir}\n >\n\n {/* 1. Main Workspace Viewport (Grids & Floating Panels) */}\n <div\n ref={workspaceRef}\n className={`flex-grow-1 w-100 position-relative ${state.draggedPanelId ? 'dragging-active' : ''}`}\n style={{ overflow: 'hidden' }}\n >\n {/* Workspace outer edge drop zone targets */}\n {state.draggedPanelId !== null && (\n <>\n <div\n className=\"workspace-edge-trigger edge-trigger-left\"\n onMouseEnter={() => setActiveEdgeDrop('left')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n className=\"workspace-edge-trigger edge-trigger-right\"\n onMouseEnter={() => setActiveEdgeDrop('right')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n className=\"workspace-edge-trigger edge-trigger-top\"\n onMouseEnter={() => setActiveEdgeDrop('top')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n className=\"workspace-edge-trigger edge-trigger-bottom\"\n onMouseEnter={() => setActiveEdgeDrop('bottom')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n </>\n )}\n\n {/* Edge drop visual preview overlay */}\n {state.draggedPanelId !== null && activeEdgeDrop !== null && (\n <div className={`workspace-edge-preview edge-preview-${activeEdgeDrop}`} />\n )}\n\n {/* 1.1 Viewport Split Grid Layout */}\n <div className=\"w-100 h-100\" style={{ overflow: 'hidden', position: 'relative' }}>\n {state.gridRoot ? (\n <WorkspaceGrid\n node={state.gridRoot}\n path={[]}\n onTabRightClick={handleTabRightClick}\n activeDropZone={activeDropZone}\n onHoverDropZone={handleHoverDropZone}\n onTabDragStart={handleTabDragStart}\n hoveredTab={hoveredTab}\n onTabHover={handleTabHover}\n defaultPanelIcon={defaultPanelIcon}\n onRequestClosePanel={handleRequestClose}\n />\n ) : (\n <div className=\"w-100 h-100 d-flex align-items-center justify-content-center text-muted font-monospace small\">\n Grid Empty\n </div>\n )}\n </div>\n\n {(() => {\n return state.floating.map(w => {\n const panel = state.panels[w.id];\n if (!panel) return null;\n\n const isMaximized = w.maximized;\n const isDragged = state.draggedPanelId === w.id;\n const isFocused = state.activePanelId === w.id;\n\n const registryEntry = PanelRegistry.get(panel.component);\n const options = registryEntry?.defaultOptions;\n\n return (\n <div\n key={w.id}\n data-window-id={w.id}\n dir={state.dir}\n onMouseDownCapture={() => {\n setActivePanel(w.id);\n bringToFront(w.id);\n }}\n className={`floating-window ${isMaximized ? 'maximized' : ''} ${isFocused ? 'v2-window-focused' : ''} ${windowClass ?? ''}`}\n style={{\n position: 'absolute',\n left: isMaximized ? 0 : (typeof w.x === 'number' ? `${w.x}px` : w.x),\n top: isMaximized ? 0 : (typeof w.y === 'number' ? `${w.y}px` : w.y),\n width: isMaximized ? '100%' : (typeof w.width === 'number' ? `${w.width}px` : w.width),\n height: isMaximized ? '100%' : (typeof w.height === 'number' ? `${w.height}px` : w.height),\n zIndex: w.z,\n pointerEvents: isDragged ? 'none' : 'auto',\n }}\n >\n {/* Title Bar */}\n <div\n onDoubleClick={() => maximizePanel(w.id)}\n onMouseDown={(e) => {\n if (options?.canDrag !== false) {\n startDrag(w.id, e);\n }\n }}\n className=\"floating-window-titlebar d-flex flex-row justify-content-between align-items-center cursor-move\"\n style={{ cursor: isMaximized || options?.canDrag === false ? 'default' : 'move' }}\n >\n <span className=\"floating-window-title text-truncate me-2 d-flex align-items-center\">\n <span className=\"window-title-icon\">{options?.icon || defaultPanelIcon || DefaultGridIcon}</span>\n <span>\n {formatLabel(panel.title, formatMessage)}\n {panel.dirty ? ' *' : ''}\n </span>\n </span>\n <div className=\"d-flex align-items-center\" style={{ gap: 'var(--header-button-gap, 4px)' }} onMouseDown={(e) => e.stopPropagation()}>\n {options?.renderHeaderActions && (\n <div className=\"window-header-actions d-flex align-items-center me-1\" style={{ gap: 'var(--header-button-gap, 4px)' }}>\n {options.renderHeaderActions(w.id)}\n </div>\n )}\n {options?.canDrag !== false && (\n <button\n type=\"button\"\n title={formatLabel(messages.windowAnchoringOptions, formatMessage)}\n onClick={(e) => {\n const isRight = !!w.stickyRight;\n const isBottom = !!w.stickyBottom;\n contextMenuRef.current?.show({\n event: e,\n contextMenu: {\n items: [\n {\n label: formatLabel(messages.anchorToRightEdge, formatMessage),\n checkbox: {\n active: true,\n enabled: true,\n value: isRight\n },\n action: () => {\n const viewW = workspaceSize.width;\n const winW = typeof w.width === 'string' ? parseFloat(w.width) : w.width;\n const GAP = 10;\n if (!isRight) {\n updateFloatingPosition(w.id, { x: viewW - winW - GAP, stickyRight: true });\n } else {\n updateFloatingPosition(w.id, { stickyRight: false });\n }\n }\n },\n {\n label: formatLabel(messages.anchorToBottomEdge, formatMessage),\n checkbox: {\n active: true,\n enabled: true,\n value: isBottom\n },\n action: () => {\n const viewH = workspaceSize.height;\n const winH = typeof w.height === 'string' ? parseFloat(w.height) : w.height;\n const GAP = 10;\n if (!isBottom) {\n updateFloatingPosition(w.id, { y: viewH - winH - GAP, stickyBottom: true });\n } else {\n updateFloatingPosition(w.id, { stickyBottom: false });\n }\n }\n }\n ]\n }\n });\n }}\n className=\"custom-tab-btn btn-anchor-tab\"\n >\n <svg className={`anchor-icon ${(w.stickyRight && w.stickyBottom) ? 'anchor-sticky-both' : w.stickyRight ? 'anchor-sticky-right' : w.stickyBottom ? 'anchor-sticky-bottom' : ''}`} width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <circle cx=\"12\" cy=\"5\" r=\"2\" />\n <path d=\"M12 7v7m0 0a4 4 0 0 1-4-4M12 14a4 4 0 0 0 4-4M5 18h14\" />\n </svg>\n </button>\n )}\n <button\n type=\"button\"\n title={isMaximized\n ? formatLabel(messages.restoreSize, formatMessage)\n : formatLabel(messages.maximize, formatMessage)}\n onClick={() => maximizePanel(w.id)}\n className=\"custom-tab-btn btn-maximize-tab\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1.5\"/>\n </svg>\n </button>\n {options?.canMinimize !== false && (\n <button\n type=\"button\"\n title={formatLabel(messages.minimize, formatMessage)}\n onClick={() => minimizePanel(w.id)}\n className=\"custom-tab-btn btn-minimize-tab\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\">\n <path d=\"M5 12h14\"/>\n </svg>\n </button>\n )}\n {options?.canClose !== false && (\n <button\n type=\"button\"\n title={formatLabel(messages.close, formatMessage)}\n onClick={() => handleRequestClose(w.id)}\n className=\"custom-tab-btn btn-close-tab\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {/* Window Content */}\n <div className={`flex-grow-1 w-100 overflow-hidden ${windowBodyClass ?? ''}`} style={{ position: 'relative' }}>\n <PreservedDOMWrapper key={w.id} panelId={w.id} />\n </div>\n\n {/* Resize Handle */}\n {!isMaximized && (\n <div\n onMouseDown={(e) => startResize(w.id, e)}\n style={{\n position: 'absolute',\n right: 0,\n bottom: 0,\n width: '14px',\n height: '14px',\n cursor: 'se-resize',\n zIndex: 30,\n background: 'linear-gradient(135deg, transparent 50%, rgba(255,255,255,0.2) 50%)'\n }}\n />\n )}\n </div>\n );\n });\n })()}\n </div>\n\n {/* 2. macOS / Windows 11-style Taskbar Sibling Footer (Flex-shrinked at bottom) */}\n {state.minimized.length > 0 && (\n <div className=\"flex-shrink-0 w-100 d-flex flex-row align-items-center taskbar-footer-container px-3 py-1.5 justify-content-center\" style={{ height: '48px', zIndex: 100 }}>\n <button\n type=\"button\"\n onClick={() => scrollTaskbar('left')}\n className=\"btn btn-sm btn-link taskbar-nav-btn text-decoration-none py-0 font-monospace\"\n style={{ display: state.minimized.length > 4 ? 'block' : 'none' }}\n >\n ◀\n </button>\n\n <div\n ref={taskbarRef}\n className=\"d-flex flex-row gap-2 overflow-x-auto align-items-center mx-2 px-1 py-0.5 scrollbar-hidden\"\n style={{\n maxWidth: '800px',\n scrollbarWidth: 'none',\n scrollSnapType: 'x mandatory'\n }}\n >\n {state.minimized.map(m => {\n const regEntry = PanelRegistry.get(m.component);\n const icon = regEntry?.defaultOptions?.icon || defaultPanelIcon || DefaultGridIcon;\n\n return (\n <div\n key={m.id}\n onClick={() => {\n setHoveredMinimized(null);\n restorePanel(m.id);\n }}\n onContextMenu={(e) => handleMinimizedRightClick(m.id, e)}\n onMouseEnter={(e) => {\n if (isContextMenuOpen) return;\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n const rect = e.currentTarget.getBoundingClientRect();\n const isInside = (\n e.clientX >= rect.left &&\n e.clientX <= rect.right &&\n e.clientY >= rect.top &&\n e.clientY <= rect.bottom\n );\n if (!isInside) return;\n setHoveredMinimized({ id: m.id, rect, title: m.title, component: m.component });\n }}\n onMouseLeave={() => {\n minimizedTooltipTimeoutRef.current = setTimeout(() => {\n setHoveredMinimized(null);\n }, 150);\n }}\n className=\"taskbar-glassmorphic-item rounded d-flex align-items-center justify-content-center cursor-pointer hover-elevate\"\n style={{\n backdropFilter: 'blur(6px)',\n transition: 'all 0.2s',\n cursor: 'pointer',\n scrollSnapAlign: 'start',\n width: '38px',\n height: '38px',\n position: 'relative',\n padding: 0\n }}\n >\n <span className=\"taskbar-item-icon d-flex align-items-center justify-content-center\">\n {icon}\n </span>\n </div>\n );\n })}\n </div>\n\n {hoveredMinimized && createPortal(\n <div\n className=\"taskbar-item-tooltip d-flex flex-column gap-1\"\n dir={state.dir}\n style={{\n position: 'fixed',\n left: `${hoveredMinimized.rect.left + hoveredMinimized.rect.width / 2}px`,\n top: `${hoveredMinimized.rect.top - 8}px`,\n transform: 'translateX(-50%) translateY(-100%)',\n opacity: 1,\n pointerEvents: 'auto',\n zIndex: 999999\n }}\n onMouseEnter={() => {\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n }}\n onMouseLeave={() => {\n setHoveredMinimized(null);\n }}\n onClick={() => {\n restorePanel(hoveredMinimized.id);\n setHoveredMinimized(null);\n }}\n >\n <div className=\"d-flex flex-row align-items-center justify-content-between w-100 gap-3 px-1 py-0.5\">\n <span className=\"tooltip-title-text text-truncate\" style={{ maxWidth: '140px' }}>\n {formatLabel(hoveredMinimized.title, formatMessage)}\n {state.panels[hoveredMinimized.id]?.dirty ? ' *' : ''}\n </span>\n <span\n onClick={(e) => {\n e.stopPropagation();\n handleRequestClose(hoveredMinimized.id);\n setHoveredMinimized(null);\n }}\n title={formatLabel(messages.closePanel, formatMessage)}\n className=\"tooltip-close-x d-flex align-items-center justify-content-center\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n </div>\n <PreviewDOMWrapper panelId={hoveredMinimized.id} />\n </div>,\n document.body\n )}\n\n <button\n type=\"button\"\n onClick={() => scrollTaskbar('right')}\n className=\"btn btn-sm btn-link taskbar-nav-btn text-decoration-none py-0 font-monospace\"\n style={{ display: state.minimized.length > 4 ? 'block' : 'none' }}\n >\n ▶\n </button>\n </div>\n )}\n\n {/* 3. Persistence Port: Portals rendering panels into off-screen elements */}\n {Object.keys(state.panels).map((id) => {\n const panel = state.panels[id];\n if (!panel) return null;\n const targetEl = getOrCreateDomCacheElement(id);\n return createPortal(\n <FormContainerProviderWrapper panelId={id}>\n <div style={{ width: '100%', height: '100%' }}>\n {renderPanelContent(id, panel.component)}\n </div>\n </FormContainerProviderWrapper>,\n targetEl,\n id\n );\n })}\n\n {/* 4. Context Menu (replace-react-contexify JSON mode) */}\n <JsonContextMenu\n ref={contextMenuRef}\n id=\"workspace-context-menu\"\n theme=\"dark\"\n onShow={() => setIsContextMenuOpen(true)}\n onHide={() => setIsContextMenuOpen(false)}\n />\n\n {/* 5. Dragging Tab Ghost Representation */}\n {state.draggedPanelId !== null && !state.floating.some(w => w.id === state.draggedPanelId) && (\n <div\n className=\"position-fixed bg-black bg-opacity-80 border border-info rounded text-info font-monospace px-3 py-1.5 shadow-lg d-flex align-items-center gap-2\"\n style={{\n left: dragPos.x + 12,\n top: dragPos.y + 12,\n zIndex: 100000,\n pointerEvents: 'none',\n fontSize: '0.75rem',\n boxShadow: '0 8px 24px rgba(0,0,0,0.5)',\n borderLeft: '3px solid var(--accent-color)',\n whiteSpace: 'nowrap'\n }}\n >\n 📄 {formatLabel(state.panels[state.draggedPanelId]?.title, formatMessage) || 'Tab'}\n </div>\n )}\n\n\n\n </div>\n );\n};\n\nexport default WindowManager;\n","import React, { createContext, useContext, useState, useRef, useMemo, useCallback, useEffect } from 'react';\nimport { PanelRegistry } from './PanelRegistry';\nimport { defaultPredefinedMessages } from './predefinedMessages';\nimport type { PredefinedMessageKey } from './predefinedMessages';\nexport type { PredefinedMessageKey } from './predefinedMessages';\nexport { defaultPredefinedMessages } from './predefinedMessages';\nimport type { DirtyStateOptions } from './dirtyOptions';\nexport type { DirtyStateOptions };\n\n/**\n * Structure representing localizable message descriptors used in context menus.\n */\nexport interface ContextMenuPredefinedMessage {\n /** Translation dictionary key. */\n id: string;\n /** Fallback label text if translation key is missing. */\n defaultMessage?: string;\n /** Values injected into the translated text placeholder. */\n values?: Record<string, string | number>;\n}\n\n/** Function type interface responsible for resolving localizable messages to flat strings. */\nexport type MessageFormatter = (msg: ContextMenuPredefinedMessage) => string;\n\n/** Orientation modifier indicating split directions. */\nexport type SplitOrientation = 'horizontal' | 'vertical';\n\n/**\n * Grid layout branch node containing nested splits and relative flex sizes.\n */\nexport interface LayoutGridNode {\n type: 'branch';\n /** Split orientation orientation indicator. */\n orientation: SplitOrientation;\n /** Children branches or leaf panels. */\n children: LayoutNode[];\n /** Relative percentage sizes of each child layout block. */\n sizes: number[];\n}\n\n/**\n * Grid layout leaf node containing active tab groups and panel arrays.\n */\nexport interface LayoutLeafNode {\n type: 'leaf';\n /** Unique leaf identifier. */\n id: string;\n /** Array of panel IDs mounted inside this group. */\n panels: string[];\n /** The currently active panel tab ID. */\n activePanelId: string | null;\n /** If false, close menu buttons are disabled for this group's tabs. */\n canClose?: boolean;\n /** When true, the group persists in the layout even after its last panel is closed. */\n keepOnEmpty?: boolean;\n}\n\n/** Union type representing either a branch or a leaf node in the layout grid. */\nexport type LayoutNode = LayoutGridNode | LayoutLeafNode;\n\n/**\n * Bounds and depth metadata for floated panel windows.\n */\nexport interface FloatingWindow {\n /** Unique ID of the floating window. */\n id: string;\n /** CSS left position offset (supports number/px or percentage strings). */\n x: number | string;\n /** CSS top position offset. */\n y: number | string;\n /** CSS width value. */\n width: number | string;\n /** CSS height value. */\n height: number | string;\n /** Rendering depth stack index layer. */\n z: number;\n /** True if the window is currently maximized to full workspace bounds. */\n maximized?: boolean;\n /** Sticky right flag. */\n stickyRight?: boolean;\n /** Sticky bottom flag. */\n stickyBottom?: boolean;\n}\n\n/**\n * Stores active runtime properties and status metadata for individual panel instances.\n */\nexport interface PanelInfo {\n /** Unique panel identifier. */\n id: string;\n /** Plain text label or localizable message descriptor. */\n title: string | ContextMenuPredefinedMessage;\n /** String matching the component registration ID in the {@link PanelRegistry}. */\n component: string;\n /** Current workspace placement mode. */\n state: 'docked' | 'floating' | 'minimized';\n /** Last state held before panel was minimized. */\n previousState?: 'docked' | 'floating';\n /** Saved position boundaries used when returning the panel to a floating state. */\n lastFloatingRect?: { x: number; y: number; width: number; height: number; stickyRight?: boolean; stickyBottom?: boolean };\n /** The leaf group ID this panel was docked in prior to being floated. */\n lastLeafId?: string;\n /** True if the panel contains unsaved user edits. */\n dirty?: boolean;\n /** Custom options applied to the automatic unsaved changes modal. */\n dirtyOptions?: DirtyStateOptions;\n}\n\n/**\n * Global window manager state tree representing grid nodes, windows, and panels.\n */\nexport interface WindowState {\n /** Root branch node representing the grid. */\n gridRoot: LayoutNode;\n /** Array of active floated windows. */\n floating: FloatingWindow[];\n /** Array of minimized panels waiting in the taskbar dock. */\n minimized: { id: string; title: string | ContextMenuPredefinedMessage; component: string }[];\n /** Map indexing panel metadata descriptors. */\n panels: Record<string, PanelInfo>;\n /** The ID of the panel tab currently being dragged. */\n draggedPanelId: string | null;\n /** The ID of the active/focused panel. */\n activePanelId: string | null;\n /** Current layout direction ('ltr' or 'rtl') */\n dir: 'ltr' | 'rtl';\n /** Convenient boolean flag indicating RTL direction */\n isRtl: boolean;\n}\n\n/**\n * Interface mapping layout actions, event bus handles, and serialization methods.\n */\nexport interface WindowActions {\n /** Instantiates a registered panel into the workspace. */\n openPanel: (id: string, component: string, options?: { title?: string | ContextMenuPredefinedMessage; initialTarget?: 'floating' | 'docked' | 'tabbed'; stickyRight?: boolean; stickyBottom?: boolean }) => void;\n /** Directly closes a panel by ID, bypassing close confirmation dialogs. */\n closePanel: (id: string) => void;\n /** Minimizes a panel to the bottom taskbar, saving its current layout positioning. */\n minimizePanel: (id: string) => void;\n /** Restores a minimized panel back to its previous position in the grid or as a float. */\n restorePanel: (id: string) => void;\n /** Detaches a docked panel, turning it into a floating resizable window. */\n floatPanel: (id: string, rect?: { x: number; y: number; width: number; height: number }) => void;\n /** Returns a floating window back to a docked grid tab group. */\n dockPanel: (id: string, targetLeafId?: string) => void;\n /** Maximizes a floating window to cover the entire layout screen boundaries. */\n maximizePanel: (id: string) => void;\n /** Resizes flex dimensions of children inside split layout rows/columns. */\n updateSplitSizes: (path: number[], sizes: number[]) => void;\n /** Updates bounds or positioning attributes on a floating window. */\n updateFloatingPosition: (id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'stickyRight' | 'stickyBottom'>>) => void;\n /** Pushes a floating window z-index layer to render on top of others. */\n bringToFront: (id: string) => void;\n /** Serializes the active grid node structures and panel targets to JSON. */\n saveLayout: () => string;\n /** Rebuilds the grid layouts and floating window placements from a JSON string. */\n loadLayout: (layoutJson: string) => void;\n /** Publishes an event to the global inter-panel message bus. */\n publish: (event: string, data: any) => void;\n /** Subscribes callback listeners to inter-panel event messages. */\n subscribe: (event: string, callback: (data: any) => void) => () => void;\n /** Stores reference to the active tab ID being dragged. */\n setDraggedPanelId: (id: string | null) => void;\n /** Splits an existing tab group to dock a dragged panel next to it. */\n dockPanelToGroup: (id: string, targetLeafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center') => void;\n /** Reorders tab indices inside a docked leaf group. */\n movePanelOrder: (panelId: string, targetLeafId: string, targetIndex: number) => void;\n /** Closes an empty split group. */\n closeLeafGroup: (leafId: string) => void;\n /** Binds a close intercept confirmation guard. */\n registerCloseGuard: (id: string, guard: () => boolean | Promise<boolean>) => void;\n /** Removes close confirmation guards. */\n unregisterCloseGuard: (id: string) => void;\n /** Set panel dirty state flag. */\n setPanelDirty: (id: string, dirty: boolean, options?: DirtyStateOptions) => void;\n /** Change title header. */\n updatePanelTitle: (id: string, title: string | ContextMenuPredefinedMessage) => void;\n /** Intercepts close panel requests, prompting warning dialogs if dirty. */\n requestClosePanel: (id: string, options?: { force?: boolean; onConfirm?: (opts?: DirtyStateOptions) => Promise<boolean> }) => Promise<void>;\n /** Docks a panel directly to workspace edges. */\n dockPanelToWorkspaceEdge: (id: string, position: 'left' | 'right' | 'top' | 'bottom') => void;\n /** Update active focused tab reference. */\n setActivePanel: (id: string | null) => void;\n /** Explicitly set or override layout direction */\n setDirection: (dir: 'ltr' | 'rtl') => void;\n}\n\nconst WindowStateContext = createContext<WindowState | null>(null);\nconst WindowActionsContext = createContext<WindowActions | null>(null);\nconst WindowI18nContext = createContext<MessageFormatter | null>(null);\n\nconst WindowPredefinedMessagesContext = createContext<Record<PredefinedMessageKey, ContextMenuPredefinedMessage>>(defaultPredefinedMessages);\n\n/** Represents custom CSS classes injected into layout parts. */\nexport interface StyleClasses {\n modalClass?: string;\n modalBodyClass?: string;\n sidePanelClass?: string;\n sidePanelBodyClass?: string;\n windowClass?: string;\n windowBodyClass?: string;\n}\n\nconst StyleClassContext = createContext<StyleClasses>({});\n\n/** Custom hook to read configured style class contexts. */\nexport const useStyleClasses = () => useContext(StyleClassContext);\n\n// Event Bus class for pub-sub communication between panels\nclass PanelEventBus {\n private listeners: Record<string, ((data: any) => void)[]> = {};\n\n subscribe(event: string, callback: (data: any) => void) {\n if (!this.listeners[event]) {\n this.listeners[event] = [];\n }\n this.listeners[event].push(callback);\n return () => {\n this.listeners[event] = this.listeners[event].filter(cb => cb !== callback);\n };\n }\n\n publish(event: string, data: any) {\n if (this.listeners[event]) {\n this.listeners[event].forEach(cb => cb(data));\n }\n }\n}\n\nconst initialLayout: LayoutNode = {\n type: 'branch',\n orientation: 'vertical',\n sizes: [0.75, 0.25],\n children: [\n {\n type: 'leaf',\n id: 'group-left-top',\n panels: ['main-map', 'main-editor'],\n activePanelId: 'main-map',\n },\n {\n type: 'leaf',\n id: 'group-left-bottom',\n panels: ['system-console', 'help-docs'],\n activePanelId: 'system-console',\n }\n ]\n};\n\nconst initialPanels: Record<string, PanelInfo> = {\n 'main-map': { id: 'main-map', title: 'Main Map', component: 'mainMap', state: 'docked' },\n 'main-editor': { id: 'main-editor', title: 'Code Editor', component: 'editor', state: 'docked' },\n 'system-console': { id: 'system-console', title: 'Console Output', component: 'terminal', state: 'docked' },\n 'help-docs': { id: 'help-docs', title: 'Help Center', component: 'help', state: 'docked' },\n 'live-preview': { id: 'live-preview', title: 'Live Preview Output', component: 'preview', state: 'floating' }\n};\n\nconst initialFloating: FloatingWindow[] = [\n { id: 'live-preview', x: 450, y: 200, width: 320, height: 250, z: 1000 }\n];\n\nexport interface WindowManagerProviderProps {\n children: React.ReactNode;\n formatMessage?: MessageFormatter;\n predefinedMessages?: Record<string, ContextMenuPredefinedMessage>;\n dir?: 'ltr' | 'rtl';\n modalClass?: string;\n modalBodyClass?: string;\n sidePanelClass?: string;\n sidePanelBodyClass?: string;\n windowClass?: string;\n windowBodyClass?: string;\n}\n\nexport const WindowManagerProvider: React.FC<WindowManagerProviderProps> = ({\n children,\n formatMessage,\n predefinedMessages,\n dir: dirProp,\n modalClass,\n modalBodyClass,\n sidePanelClass,\n sidePanelBodyClass,\n windowClass,\n windowBodyClass\n}) => {\n const [state, setState] = useState<WindowState>({\n gridRoot: initialLayout,\n floating: initialFloating,\n minimized: [],\n panels: initialPanels,\n draggedPanelId: null,\n activePanelId: 'main-map',\n dir: dirProp || 'ltr',\n isRtl: dirProp === 'rtl'\n });\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const closeGuardsRef = useRef<Record<string, () => boolean | Promise<boolean>>>({});\n\n const mergedMessages = useMemo(() => ({\n ...defaultPredefinedMessages,\n ...predefinedMessages\n }), [predefinedMessages]);\n\n const eventBusRef = useRef(new PanelEventBus());\n const maxZRef = useRef(1000);\n\n const subscribe = useCallback((event: string, callback: (data: any) => void) => {\n return eventBusRef.current.subscribe(event, callback);\n }, []);\n\n const publish = useCallback((event: string, data: any) => {\n eventBusRef.current.publish(event, data);\n }, []);\n\n // Helper: Find free cascading location for floating window\n const getCascadedPosition = useCallback((\n fav: { x: number | string; y: number | string; width: number | string; height: number | string },\n currentFloating: FloatingWindow[]\n ) => {\n let x = typeof fav.x === 'string' ? parseFloat(fav.x) : fav.x;\n let y = typeof fav.y === 'string' ? parseFloat(fav.y) : fav.y;\n let width = typeof fav.width === 'string' ? parseFloat(fav.width) : fav.width;\n let height = typeof fav.height === 'string' ? parseFloat(fav.height) : fav.height;\n\n // Fallbacks if parseFloat fails and returns NaN\n if (isNaN(x)) x = 300;\n if (isNaN(y)) y = 150;\n if (isNaN(width)) width = 450;\n if (isNaN(height)) height = 350;\n\n const isOverlapping = (pos: { x: number; y: number }) => {\n return currentFloating.some(w => {\n const wx = typeof w.x === 'string' ? parseFloat(w.x) : w.x;\n const wy = typeof w.y === 'string' ? parseFloat(w.y) : w.y;\n return !w.maximized && Math.abs(wx - pos.x) < 20 && Math.abs(wy - pos.y) < 20;\n });\n };\n\n let attempts = 0;\n while (isOverlapping({ x, y }) && attempts < 10) {\n x += 30;\n y += 30;\n attempts++;\n }\n\n // Capture safe viewport boundaries (min 1024x768 fallback if not measured or in headless environments)\n const viewW = Math.max(100, window.innerWidth || 1024);\n const viewH = Math.max(100, window.innerHeight || 768);\n\n if (x + width > viewW || y + height > viewH) {\n x = 100 + (attempts % 5) * 30;\n y = 100 + (attempts % 5) * 30;\n }\n\n // Final safety clamp to make sure window title bar is always visible and clickable\n x = Math.max(0, Math.min(x, viewW - 100));\n y = Math.max(0, Math.min(y, viewH - 40));\n\n return { x, y, width, height };\n }, []);\n\n const bringToFront = useCallback((id: string) => {\n maxZRef.current += 1;\n const z = maxZRef.current;\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n if (panel.state === 'floating') {\n return {\n ...prev,\n floating: prev.floating.map(w => w.id === id ? { ...w, z } : w),\n activePanelId: id\n };\n } else if (panel.state === 'docked') {\n const selectActiveInTree = (node: LayoutNode): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.panels.includes(id)) {\n return { ...node, activePanelId: id };\n }\n return node;\n } else {\n return { ...node, children: node.children.map(selectActiveInTree) };\n }\n };\n return {\n ...prev,\n gridRoot: selectActiveInTree(prev.gridRoot),\n activePanelId: id\n };\n }\n return { ...prev, activePanelId: id };\n });\n }, []);\n\n // Recursive helpers to manipulate layout tree\n const removePanelFromTree = (node: LayoutNode, id: string): LayoutNode | null => {\n if (node.type === 'leaf') {\n const idx = node.panels.indexOf(id);\n if (idx === -1) return node;\n const panels = node.panels.filter(p => p !== id);\n const activePanelId = node.activePanelId === id\n ? (panels[idx] || panels[idx - 1] || panels[0] || null)\n : node.activePanelId;\n const updatedLeaf = { ...node, panels, activePanelId };\n // Auto-remove this leaf when it becomes empty, unless keepOnEmpty is set\n if (panels.length === 0 && !node.keepOnEmpty) return null;\n return updatedLeaf;\n } else {\n const children = node.children\n .map(c => removePanelFromTree(c, id))\n .filter((c): c is LayoutNode => c !== null);\n\n if (children.length === 0) return null;\n if (children.length === 1) return children[0];\n\n // Re-normalize sizes\n const sizes = node.sizes.slice(0, children.length);\n const sum = sizes.reduce((a, b) => a + b, 0);\n return {\n ...node,\n children,\n sizes: sizes.map(s => s / sum)\n };\n }\n };\n\n const addPanelToLeaf = (node: LayoutNode, leafId: string, panelId: string): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.id === leafId) {\n const panels = node.panels.includes(panelId) ? node.panels : [...node.panels, panelId];\n return { ...node, panels, activePanelId: panelId };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(c => addPanelToLeaf(c, leafId, panelId))\n };\n }\n };\n\n const findFirstLeafId = (node: LayoutNode): string | null => {\n if (node.type === 'leaf') return node.id;\n for (const child of node.children) {\n const id = findFirstLeafId(child);\n if (id) return id;\n }\n return null;\n };\n\n const openPanel = useCallback((id: string, component: string, options?: { title?: string | ContextMenuPredefinedMessage; initialTarget?: 'floating' | 'docked' | 'tabbed'; stickyRight?: boolean; stickyBottom?: boolean }) => {\n setState(prev => {\n const exists = prev.panels[id];\n const entry = PanelRegistry.get(component);\n const title = options?.title || options?.title || entry?.defaultOptions?.title || id;\n const target = options?.initialTarget || entry?.defaultOptions?.initialTarget || 'docked';\n const favPos = entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n\n // Case 1: Already exists\n if (exists) {\n if (exists.state === 'minimized') {\n // Restore\n const nextMinimized = prev.minimized.filter(m => m.id !== id);\n if (target === 'floating' || !prev.gridRoot) {\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n return {\n ...prev,\n minimized: nextMinimized,\n floating: [...prev.floating, { ...cascaded, id, z: maxZRef.current }],\n panels: { ...prev.panels, [id]: { ...exists, state: 'floating' } }\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-left-top';\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, id),\n panels: { ...prev.panels, [id]: { ...exists, state: 'docked' } }\n };\n }\n } else if (exists.state === 'floating') {\n bringToFront(id);\n return prev;\n } else {\n // Focus in tab group\n const selectActiveInTree = (node: LayoutNode): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.panels.includes(id)) {\n return { ...node, activePanelId: id };\n }\n return node;\n } else {\n return { ...node, children: node.children.map(selectActiveInTree) };\n }\n };\n return {\n ...prev,\n gridRoot: selectActiveInTree(prev.gridRoot)\n };\n }\n }\n\n // Case 2: New panel\n const targetState = target === 'tabbed' ? 'docked' : target;\n const newPanelInfo: PanelInfo = { id, title, component, state: targetState };\n const nextPanels = { ...prev.panels, [id]: newPanelInfo };\n\n if (target === 'floating') {\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n\n const stickyRight = options?.stickyRight ?? entry?.defaultOptions?.defaultStickyRight ?? false;\n const stickyBottom = options?.stickyBottom ?? entry?.defaultOptions?.defaultStickyBottom ?? false;\n\n const viewW = Math.max(100, window.innerWidth || 1024);\n const viewH = Math.max(100, window.innerHeight || 768);\n const winW = typeof cascaded.width === 'string' ? parseFloat(cascaded.width) : cascaded.width;\n const winH = typeof cascaded.height === 'string' ? parseFloat(cascaded.height) : cascaded.height;\n\n let initialX = cascaded.x;\n let initialY = cascaded.y;\n\n const GAP = 10;\n if (stickyRight) {\n initialX = viewW - winW - GAP;\n }\n if (stickyBottom) {\n initialY = viewH - winH - GAP;\n }\n\n return {\n ...prev,\n floating: [...prev.floating, { ...cascaded, id, z: maxZRef.current, x: initialX, y: initialY, stickyRight, stickyBottom }],\n panels: nextPanels\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-left-top';\n return {\n ...prev,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, id),\n panels: nextPanels\n };\n }\n });\n }, [getCascadedPosition, bringToFront]);\n\n const closePanel = useCallback((id: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const registryEntry = PanelRegistry.get(panel.component);\n if (registryEntry?.defaultOptions?.canClose === false) {\n return prev;\n }\n\n delete closeGuardsRef.current[id];\n\n const nextPanels = { ...prev.panels };\n delete nextPanels[id];\n\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: prev.minimized.filter(m => m.id !== id),\n panels: nextPanels\n };\n });\n }, []);\n\n const registerCloseGuard = useCallback((id: string, guard: () => boolean | Promise<boolean>) => {\n closeGuardsRef.current[id] = guard;\n }, []);\n\n const unregisterCloseGuard = useCallback((id: string) => {\n delete closeGuardsRef.current[id];\n }, []);\n\n const setPanelDirty = useCallback((id: string, dirty: boolean, options?: DirtyStateOptions) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n return {\n ...prev,\n panels: {\n ...prev.panels,\n [id]: { ...panel, dirty, dirtyOptions: options }\n }\n };\n });\n }, []);\n\n const updatePanelTitle = useCallback((id: string, title: string | ContextMenuPredefinedMessage) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n return {\n ...prev,\n panels: {\n ...prev.panels,\n [id]: { ...panel, title }\n }\n };\n });\n }, []);\n\n const requestClosePanel = useCallback(async (id: string, options?: { force?: boolean; onConfirm?: (opts?: DirtyStateOptions) => Promise<boolean> }) => {\n if (options?.force) {\n closePanel(id);\n return;\n }\n\n // 1. Check custom close guard\n const guard = closeGuardsRef.current[id];\n if (guard) {\n const canClose = await guard();\n if (!canClose) return;\n }\n\n // 2. Check automatic dirty flag\n const panel = stateRef.current.panels[id];\n if (panel?.dirty) {\n if (options?.onConfirm) {\n const discard = await options.onConfirm(panel.dirtyOptions);\n if (!discard) return;\n } else {\n return;\n }\n }\n\n closePanel(id);\n }, [closePanel]);\n\n const minimizePanel = useCallback((id: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel || panel.state === 'minimized') return prev;\n\n const registryEntry = PanelRegistry.get(panel.component);\n if (registryEntry?.defaultOptions?.canMinimize === false) {\n return prev;\n }\n\n let lastFloatingRect: any = undefined;\n let lastLeafId: any = undefined;\n\n if (panel.state === 'floating') {\n const win = prev.floating.find(w => w.id === id);\n if (win) {\n lastFloatingRect = { \n x: win.x, \n y: win.y, \n width: win.width, \n height: win.height,\n stickyRight: win.stickyRight,\n stickyBottom: win.stickyBottom\n };\n }\n } else if (panel.state === 'docked') {\n const findLeafForPanel = (node: LayoutNode): string | null => {\n if (node.type === 'leaf') {\n return node.panels.includes(id) ? node.id : null;\n } else {\n for (const child of node.children) {\n const res = findLeafForPanel(child);\n if (res) return res;\n }\n return null;\n }\n };\n lastLeafId = findLeafForPanel(prev.gridRoot);\n }\n\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: [...prev.minimized, { id, title: panel.title, component: panel.component }],\n panels: {\n ...prev.panels,\n [id]: {\n ...panel,\n state: 'minimized',\n previousState: panel.state,\n lastFloatingRect,\n lastLeafId\n }\n }\n };\n });\n }, []);\n\n const restorePanel = useCallback((id: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel || panel.state !== 'minimized') return prev;\n\n const nextMinimized = prev.minimized.filter(m => m.id !== id);\n const prevState = panel.previousState || 'docked';\n\n if (prevState === 'floating') {\n maxZRef.current += 1;\n const entry = PanelRegistry.get(panel.component);\n const favPos = panel.lastFloatingRect || entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n const cascaded = getCascadedPosition(favPos, prev.floating);\n return {\n ...prev,\n minimized: nextMinimized,\n floating: [\n ...prev.floating, \n { \n ...cascaded, \n id, \n z: maxZRef.current,\n stickyRight: !!panel.lastFloatingRect?.stickyRight,\n stickyBottom: !!panel.lastFloatingRect?.stickyBottom\n }\n ],\n panels: { ...prev.panels, [id]: { ...panel, state: 'floating' } }\n };\n } else {\n const leafExists = (node: LayoutNode, targetId: string): boolean => {\n if (node.type === 'leaf') return node.id === targetId;\n return node.children.some(c => leafExists(c, targetId));\n };\n\n const parentLeafExists = panel.lastLeafId && leafExists(prev.gridRoot, panel.lastLeafId);\n const entry = PanelRegistry.get(panel.component);\n const canDrag = entry?.defaultOptions?.canDrag !== false;\n\n if (parentLeafExists) {\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, panel.lastLeafId!, id),\n panels: { ...prev.panels, [id]: { ...panel, state: 'docked' } }\n };\n } else if (canDrag) {\n // Leaf group ceased to exist: float it instead if floatable!\n maxZRef.current += 1;\n const favPos = panel.lastFloatingRect || entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n const cascaded = getCascadedPosition(favPos, prev.floating);\n return {\n ...prev,\n minimized: nextMinimized,\n floating: [\n ...prev.floating, \n { \n ...cascaded, \n id, \n z: maxZRef.current,\n stickyRight: !!panel.lastFloatingRect?.stickyRight,\n stickyBottom: !!panel.lastFloatingRect?.stickyBottom\n }\n ],\n panels: { ...prev.panels, [id]: { ...panel, state: 'floating' } }\n };\n } else {\n // Leaf group ceased to exist but not floatable: dock into fallback leaf group\n const targetLeafId = findFirstLeafId(prev.gridRoot) || 'group-left-top';\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, targetLeafId, id),\n panels: { ...prev.panels, [id]: { ...panel, state: 'docked' } }\n };\n }\n }\n });\n }, [getCascadedPosition]);\n\n const floatPanel = useCallback((id: string, rect?: { x: number; y: number; width: number; height: number }) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const registryEntry = PanelRegistry.get(panel.component);\n if (registryEntry?.defaultOptions?.canDrag === false) {\n return prev;\n }\n\n const entry = PanelRegistry.get(panel.component);\n const favPos = rect || entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: [...prev.floating, { ...cascaded, id, z: maxZRef.current }],\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'floating' }\n }\n };\n });\n }, [getCascadedPosition]);\n\n const dockPanel = useCallback((id: string, targetLeafId?: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n const leafId = targetLeafId || findFirstLeafId(cleanRoot || prev.gridRoot) || 'group-left-top';\n\n return {\n ...prev,\n gridRoot: addPanelToLeaf(cleanRoot || prev.gridRoot, leafId, id),\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'docked' }\n }\n };\n });\n }, []);\n\n // Helper to split a layout leaf node into a branch (for drag split targets)\n const splitLeafInTree = (\n node: LayoutNode,\n leafId: string,\n panelId: string,\n position: 'left' | 'right' | 'top' | 'bottom'\n ): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.id === leafId) {\n const newLeaf: LayoutLeafNode = {\n type: 'leaf',\n id: `group-split-${Date.now()}-${Math.floor(Math.random() * 1000)}`,\n panels: [panelId],\n activePanelId: panelId\n };\n const orientation: SplitOrientation = (position === 'left' || position === 'right') ? 'horizontal' : 'vertical';\n const children = (position === 'left' || position === 'top') ? [newLeaf, node] : [node, newLeaf];\n return {\n type: 'branch',\n orientation,\n sizes: [0.5, 0.5],\n children\n };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(c => splitLeafInTree(c, leafId, panelId, position))\n };\n }\n };\n\n const setDraggedPanelId = useCallback((id: string | null) => {\n setState(prev => ({ ...prev, draggedPanelId: id }));\n }, []);\n\n const dockPanelToGroup = useCallback((id: string, targetLeafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center') => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n\n let newRoot: LayoutNode;\n if (position === 'center') {\n newRoot = addPanelToLeaf(cleanRoot || prev.gridRoot, targetLeafId, id);\n } else {\n newRoot = splitLeafInTree(cleanRoot || prev.gridRoot, targetLeafId, id, position);\n }\n\n return {\n ...prev,\n gridRoot: newRoot,\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'docked' }\n },\n draggedPanelId: null\n };\n });\n }, []);\n\n const dockPanelToWorkspaceEdge = useCallback((id: string, position: 'left' | 'right' | 'top' | 'bottom') => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n\n const newLeaf: LayoutLeafNode = {\n type: 'leaf',\n id: `group-edge-${Date.now()}-${Math.floor(Math.random() * 1000)}`,\n panels: [id],\n activePanelId: id\n };\n\n const orientation: SplitOrientation = (position === 'left' || position === 'right') ? 'horizontal' : 'vertical';\n const children = (position === 'left' || position === 'top')\n ? [newLeaf, cleanRoot || prev.gridRoot]\n : [cleanRoot || prev.gridRoot, newLeaf];\n\n const newRoot: LayoutNode = {\n type: 'branch',\n orientation,\n sizes: (position === 'left' || position === 'top') ? [0.3, 0.7] : [0.7, 0.3],\n children\n };\n\n return {\n ...prev,\n gridRoot: newRoot,\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'docked' }\n },\n draggedPanelId: null\n };\n });\n }, []);\n\n const movePanelOrder = useCallback((panelId: string, targetLeafId: string, targetIndex: number) => {\n setState(prev => {\n const panel = prev.panels[panelId];\n if (!panel) return prev;\n\n // 1. Remove panel from its current group in the layout tree\n const cleanRoot = removePanelFromTree(prev.gridRoot, panelId);\n\n // 2. Insert panel at specific index in target leaf ID\n const insertInLeaf = (node: LayoutNode): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.id === targetLeafId) {\n const remaining = node.panels.filter(p => p !== panelId);\n const index = Math.max(0, Math.min(targetIndex, remaining.length));\n const newPanels = [...remaining];\n newPanels.splice(index, 0, panelId);\n return {\n ...node,\n panels: newPanels,\n activePanelId: panelId\n };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(insertInLeaf)\n };\n }\n };\n\n const newRoot = insertInLeaf(cleanRoot || prev.gridRoot);\n const nextFloating = prev.floating.filter(w => w.id !== panelId);\n\n return {\n ...prev,\n gridRoot: newRoot,\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [panelId]: { ...panel, state: 'docked' }\n },\n draggedPanelId: null\n };\n });\n }, []);\n\n const closeLeafGroup = useCallback((leafId: string) => {\n setState(prev => {\n const removeLeafFromTree = (node: LayoutNode): LayoutNode | null => {\n if (node.type === 'leaf') {\n if (node.id === leafId && node.canClose !== false) {\n return null;\n }\n return node;\n } else {\n const children = node.children\n .map(c => removeLeafFromTree(c))\n .filter((c): c is LayoutNode => c !== null);\n\n if (children.length === 0) return null;\n if (children.length === 1) return children[0];\n\n // Re-normalize sizes\n const sizes = node.sizes.slice(0, children.length);\n const sum = sizes.reduce((a, b) => a + b, 0);\n return {\n ...node,\n children,\n sizes: sizes.map(s => s / sum)\n };\n }\n };\n\n const newRoot = removeLeafFromTree(prev.gridRoot);\n return {\n ...prev,\n gridRoot: newRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null }\n };\n });\n }, []);\n\n const maximizePanel = useCallback((id: string) => {\n setState(prev => ({\n ...prev,\n floating: prev.floating.map(w => w.id === id ? { ...w, maximized: !w.maximized } : w)\n }));\n }, []);\n\n const updateSplitSizes = useCallback((path: number[], sizes: number[]) => {\n const updateInTree = (node: LayoutNode, depth: number): LayoutNode => {\n if (node.type === 'leaf') return node;\n if (depth === path.length) {\n return { ...node, sizes };\n }\n const idx = path[depth];\n const children = node.children.map((c, i) => i === idx ? updateInTree(c, depth + 1) : c);\n return { ...node, children };\n };\n\n setState(prev => ({\n ...prev,\n gridRoot: updateInTree(prev.gridRoot, 0)\n }));\n }, []);\n\n const updateFloatingPosition = useCallback((id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'stickyRight' | 'stickyBottom'>>) => {\n setState(prev => ({\n ...prev,\n floating: prev.floating.map(w => w.id === id ? { ...w, ...updates } : w)\n }));\n }, []);\n\n const saveLayout = useCallback(() => {\n return JSON.stringify({\n gridRoot: state.gridRoot,\n floating: state.floating,\n minimized: state.minimized,\n panels: state.panels\n });\n }, [state]);\n\n const loadLayout = useCallback((layoutJson: string) => {\n try {\n const parsed = JSON.parse(layoutJson);\n if (parsed.gridRoot && parsed.floating && parsed.minimized && parsed.panels) {\n const firstActive = Object.keys(parsed.panels)[0] || null;\n setState(prev => ({\n ...prev,\n gridRoot: parsed.gridRoot,\n floating: parsed.floating,\n minimized: parsed.minimized,\n panels: parsed.panels,\n draggedPanelId: null,\n activePanelId: firstActive\n }));\n }\n } catch (e) {\n console.error('Failed to parse layout configuration:', e);\n }\n }, []);\n\n const setActivePanel = useCallback((id: string | null) => {\n setState(prev => {\n if (prev.activePanelId === id) return prev;\n return { ...prev, activePanelId: id };\n });\n }, []);\n\n const setDirection = useCallback((dir: 'ltr' | 'rtl') => {\n setState(prev => {\n if (prev.dir === dir) return prev;\n return { ...prev, dir, isRtl: dir === 'rtl' };\n });\n }, []);\n\n useEffect(() => {\n if (dirProp) {\n setState(prev => {\n if (prev.dir === dirProp) return prev;\n return { ...prev, dir: dirProp, isRtl: dirProp === 'rtl' };\n });\n }\n }, [dirProp]);\n\n const actions = useMemo<WindowActions>(() => ({\n openPanel,\n closePanel,\n minimizePanel,\n restorePanel,\n floatPanel,\n dockPanel,\n maximizePanel,\n updateSplitSizes,\n updateFloatingPosition,\n bringToFront,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection\n }), [\n openPanel,\n closePanel,\n minimizePanel,\n restorePanel,\n floatPanel,\n dockPanel,\n maximizePanel,\n updateSplitSizes,\n updateFloatingPosition,\n bringToFront,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection\n ]);\n\n const defaultFormatMessage: MessageFormatter = (msg) => {\n let text = msg.defaultMessage || msg.id;\n if (msg.values) {\n Object.entries(msg.values).forEach(([key, value]) => {\n text = text.replace(`{${key}}`, String(value));\n });\n }\n return text;\n };\n\n const styleClasses = useMemo(() => ({\n modalClass,\n modalBodyClass,\n sidePanelClass,\n sidePanelBodyClass,\n windowClass,\n windowBodyClass\n }), [modalClass, modalBodyClass, sidePanelClass, sidePanelBodyClass, windowClass, windowBodyClass]);\n\n return (\n <StyleClassContext.Provider value={styleClasses}>\n <WindowStateContext.Provider value={state}>\n <WindowActionsContext.Provider value={actions}>\n <WindowI18nContext.Provider value={formatMessage || defaultFormatMessage}>\n <WindowPredefinedMessagesContext.Provider value={mergedMessages}>\n {children}\n </WindowPredefinedMessagesContext.Provider>\n </WindowI18nContext.Provider>\n </WindowActionsContext.Provider>\n </WindowStateContext.Provider>\n </StyleClassContext.Provider>\n );\n};\n\n/**\n * React hook to retrieve the active Window Manager layout state.\n * @throws Error if used outside of a {@link WindowManagerProvider}.\n */\nexport const useWindowManagerState = () => {\n const ctx = useContext(WindowStateContext);\n if (!ctx) throw new Error('useWindowManagerState must be used within WindowManagerProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve layouts mutation actions (dock, float, minimize, save/load).\n * @throws Error if used outside of a {@link WindowManagerProvider}.\n */\nexport const useWindowManagerActions = () => {\n const ctx = useContext(WindowActionsContext);\n if (!ctx) throw new Error('useWindowManagerActions must be used within WindowManagerProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve the active i18n formatter.\n */\nexport const useFormatMessage = () => {\n const formatter = useContext(WindowI18nContext);\n return formatter || ((msg) => {\n let text = msg.defaultMessage || msg.id;\n if (msg.values) {\n Object.entries(msg.values).forEach(([key, value]) => {\n text = text.replace(`{${key}}`, String(value));\n });\n }\n return text;\n });\n};\n\n/**\n * Helper to resolve dynamic label strings or localizable descriptor objects into text.\n */\nexport const formatLabel = (\n label: string | ContextMenuPredefinedMessage | undefined,\n formatter: MessageFormatter\n): string => {\n if (!label) return '';\n if (typeof label === 'string') return label;\n return formatter(label);\n};\n\n/**\n * React hook providing pub-sub helper methods for inter-panel event messaging.\n */\nexport const usePanelContext = () => {\n const { publish, subscribe } = useWindowManagerActions();\n return { publish, subscribe };\n};\n\n/**\n * React hook to fetch the localizable predefined message map catalog.\n */\nexport const usePredefinedMessages = () => {\n return useContext(WindowPredefinedMessagesContext);\n};\n","import type { ComponentType } from 'react';\n\n/**\n * Represents a registered component configuration template inside the panel catalog registry.\n */\nexport interface PanelRegistryEntry {\n /** The React component type registered. */\n Component: ComponentType<any>;\n /** Default metadata settings configuration applied on instantiation. */\n defaultOptions?: {\n /** Tab and window headers text. */\n title?: string;\n /** Icon placed next to title tags. */\n icon?: React.ReactNode;\n /** Initial mounting state inside the desktop layout grid. */\n initialTarget?: 'floating' | 'docked' | 'tabbed';\n /** Custom default bounds applied when the container is floated. */\n favoritePosition?: { x: number | string; y: number | string; width: number | string; height: number | string };\n /** Enables/disables window drag interactions. */\n canDrag?: boolean;\n /** Enables/disables minimizing of the panel instance. */\n canMinimize?: boolean;\n /** Enables/disables closing actions for the tab/window. */\n canClose?: boolean;\n /** Affixes the panel to the right edge. */\n defaultStickyRight?: boolean;\n /** Affixes the panel to the bottom edge. */\n defaultStickyBottom?: boolean;\n /** Disables live WebGL rendering canvas thumbnails inside the taskbar hover popup previews. */\n disableLivePreview?: boolean;\n /** Custom header actions renderer, placing custom components in the window/tab titlebar. */\n renderHeaderActions?: (panelId: string) => React.ReactNode;\n };\n}\n\n/**\n * Registry mapping catalog entries to allow programmatic panel instantiation\n * inside dynamic layout cells or floating windows.\n */\nclass PanelRegistryClass {\n private registry = new Map<string, PanelRegistryEntry>();\n\n /**\n * Register a new component to the panel catalog registry.\n * @param id - Unique string identifier.\n * @param Component - React component instance template.\n * @param defaultOptions - Custom default settings configuration.\n */\n register<P extends object>(\n id: string,\n Component: ComponentType<P>,\n defaultOptions?: PanelRegistryEntry['defaultOptions']\n ): void {\n this.registry.set(id, {\n Component: Component as ComponentType<any>,\n defaultOptions\n });\n }\n\n /**\n * Retrieve a registered panel configuration by identifier.\n */\n get(id: string): PanelRegistryEntry | undefined {\n return this.registry.get(id);\n }\n\n /**\n * Returns a list of all registered panel entry identifiers.\n */\n getRegisteredIds(): string[] {\n return Array.from(this.registry.keys());\n }\n}\n\n/** Global singleton instance of the Panel Registry. */\nexport const PanelRegistry = new PanelRegistryClass();\nexport default PanelRegistry;\n","/**\n * @file predefinedMessages.ts\n * @description Provides the default localizable message catalogs and translation keys\n * utilized by Dockable Desktop's context menus, headers, and tooltips.\n *\n * Each value's `id` is the react-intl message ID that the consumer should\n * define in their IntlProvider messages table. The `defaultMessage` is used\n * as a fallback when no external formatter is provided.\n *\n * Pass a partial or full override to <WindowManagerProvider predefinedMessages={…} />\n * to customise labels without replacing the whole table.\n */\nexport const defaultPredefinedMessages = {\n floatWindow: { id: 'dockable-desktop-floatWindow', defaultMessage: 'Float Window' },\n minimizePanel: { id: 'dockable-desktop-minimizePanel', defaultMessage: 'Minimize Panel' },\n closeTab: { id: 'dockable-desktop-closeTab', defaultMessage: 'Close Tab' },\n restorePanel: { id: 'dockable-desktop-restorePanel', defaultMessage: 'Restore Panel' },\n maximizePanel: { id: 'dockable-desktop-maximizePanel', defaultMessage: 'Maximize Panel' },\n closePanel: { id: 'dockable-desktop-closePanel', defaultMessage: 'Close Panel' },\n dockWindow: { id: 'dockable-desktop-dockWindow', defaultMessage: 'Dock Window' },\n minimize: { id: 'dockable-desktop-minimize', defaultMessage: 'Minimize' },\n maximize: { id: 'dockable-desktop-maximize', defaultMessage: 'Maximize' },\n restoreSize: { id: 'dockable-desktop-restoreSize', defaultMessage: 'Restore Size' },\n close: { id: 'dockable-desktop-close', defaultMessage: 'Close' },\n closeEmptyGroup: { id: 'dockable-desktop-closeEmptyGroup', defaultMessage: 'Close empty split group' },\n anchorToRightEdge: { id: 'dockable-desktop-anchorToRightEdge', defaultMessage: 'Anchor to Right Edge' },\n anchorToBottomEdge: { id: 'dockable-desktop-anchorToBottomEdge', defaultMessage: 'Anchor to Bottom Edge' },\n windowAnchoringOptions: { id: 'dockable-desktop-windowAnchoringOptions', defaultMessage: 'Window Anchoring Options' },\n unsavedChangesTitle: { id: 'dockable-desktop-unsavedChangesTitle', defaultMessage: 'Unsaved Changes' },\n unsavedChangesMessage: { id: 'dockable-desktop-unsavedChangesMessage', defaultMessage: '\"{title}\" has unsaved changes. Do you want to discard your changes and close?' },\n discardChanges: { id: 'dockable-desktop-discardChanges', defaultMessage: 'Discard Changes' },\n cancel: { id: 'dockable-desktop-cancel', defaultMessage: 'Cancel' },\n yes: { id: 'dockable-desktop-yes', defaultMessage: 'Yes' },\n no: { id: 'dockable-desktop-no', defaultMessage: 'No' },\n ok: { id: 'dockable-desktop-ok', defaultMessage: 'OK' },\n closePanelTooltip: { id: 'dockable-desktop-closePanelTooltip', defaultMessage: 'Close panel' },\n closeTooltip: { id: 'dockable-desktop-closeTooltip', defaultMessage: 'Close' },\n} as const;\n\n/**\n * Union of every key in `defaultPredefinedMessages`.\n *\n * Import this type in your i18n message tables to get a compile-time\n * guarantee that all keys are present and no typos exist:\n *\n * import type { PredefinedMessageKey } from 'react-dockable-desktop';\n *\n * const myMessages: Record<PredefinedMessageKey, string> = { ... };\n */\nexport type PredefinedMessageKey = keyof typeof defaultPredefinedMessages;\n","export function isElementRtl(el: HTMLElement | null): boolean {\n if (!el) {\n if (typeof document !== 'undefined') {\n return (\n document.documentElement.dir?.toLowerCase() === 'rtl' ||\n document.body.dir?.toLowerCase() === 'rtl'\n );\n }\n return false;\n }\n\n // Check closest element with dir attribute\n const closestDirEl = el.closest('[dir]');\n if (closestDirEl) {\n return closestDirEl.getAttribute('dir')?.toLowerCase() === 'rtl';\n }\n\n // Fallback to document rules\n return (\n document.documentElement.dir?.toLowerCase() === 'rtl' ||\n document.body.dir?.toLowerCase() === 'rtl'\n );\n}\n","import { createContext, useContext } from 'react';\nimport type { DirtyStateOptions } from './dirtyOptions';\n\n/**\n * Options used when requesting to close a container.\n */\nexport interface CloseOptions {\n /** If true, bypasses any dirty state warnings or custom close guards. */\n force?: boolean;\n}\n\n/** Represents the type of container context a panel/form is currently rendered inside. */\nexport type ContainerType = 'left-panel' | 'right-panel' | 'modal' | 'dockable-panel' | 'standalone';\n\n/**\n * Contract interface exposed by a container (like a tab, window, modal, or side-panel)\n * to its children forms, enabling them to control or listen to container events.\n */\nexport interface FormContainerContract {\n /** Request the container to close itself. Bypassed by default unless options.force is true. */\n requestClose: (options?: CloseOptions) => void;\n /** Mark the form's content as dirty (having unsaved changes), triggering alert dialogs on close. */\n setDirty: (dirty: boolean, options?: DirtyStateOptions) => void;\n /** Register a custom close guard handler. Returning false or a promise resolving to false blocks closing. */\n onCloseRequested: (handler: () => boolean | Promise<boolean>) => (() => void);\n /** Change the display title of the containing tab or window dynamically. */\n setTitle: (title: string | { id: string; defaultMessage: string; values?: Record<string, any> }) => void;\n /** Change the tab or window icon dynamically. */\n setIcon?: (icon: React.ReactNode) => void;\n /** The type of container the panel is mounted in. */\n containerType?: ContainerType;\n /** Unique identifier of the panel or window instance. */\n instanceId: string;\n /** Subscribe to the container's close event. Returns an unsubscribe function. */\n onClose?: (handler: () => void) => () => void;\n /** Subscribe to the container's minimize event. Returns an unsubscribe function. */\n onMinimize?: (handler: () => void) => () => void;\n /** Subscribe to the container's restore event. Returns an unsubscribe function. */\n onRestore?: (handler: () => void) => () => void;\n /** Subscribe to the container's window resize event, returning width and height. */\n onResize?: (handler: (width: number, height: number) => void) => () => void;\n}\n\nconst defaultContract: FormContainerContract = {\n requestClose: () => {\n console.warn('FormContainerContract: requestClose called but no container is present');\n },\n setDirty: () => {},\n onCloseRequested: () => () => {},\n setTitle: () => {},\n setIcon: () => {},\n containerType: 'standalone',\n instanceId: 'standalone',\n onClose: () => () => {},\n onMinimize: () => () => {},\n onRestore: () => () => {},\n onResize: () => () => {},\n};\n\n/**\n * Context that supplies the {@link FormContainerContract} to panels inside the Window Manager.\n */\nexport const FormContainerContext = createContext<FormContainerContract>(defaultContract);\nexport const FormContainerProvider = FormContainerContext.Provider;\n\n/**\n * React hook to retrieve the current {@link FormContainerContract} from context.\n * Enables sub-forms to trigger close requests, mark themselves dirty, rename their tabs, or listen to resize events.\n */\nexport const useFormContainer = (): FormContainerContract => {\n return useContext(FormContainerContext);\n};\n\n","import React, { createContext, useContext, useState, useCallback, useMemo, useRef } from 'react';\nimport type { ComponentType, ReactNode } from 'react';\nimport type { DirtyStateOptions } from './dirtyOptions';\nexport type { DirtyStateOptions };\n\n/** Unique string identifier for panel/modal instances. */\nexport type PanelInstanceId = string;\n\n/**\n * Descriptor object for localizable panel titles, supporting context translation systems.\n */\nexport interface PanelTitleDescriptor {\n /** The translation dictionary key. */\n id: string;\n /** Fallback string if translation key is missing. */\n defaultMessage?: string;\n /** Parameters to inject into the translated text string. */\n values?: Record<string, string | number>;\n}\n\n/** Union type representing either a plain string or a localizable title descriptor. */\nexport type PanelTitle = string | PanelTitleDescriptor;\n\n/** Configuration options applied when opening a SidePanel. */\nexport interface SidePanelOptions {\n /** Display title for the side-panel header. */\n title?: PanelTitle;\n /** Icon displayed next to the panel title. */\n icon?: React.ReactNode;\n /** Specific CSS width (e.g. 300, '40%') for the panel container. */\n width?: number | string;\n}\n\n/** Configuration options applied when opening a Modal. */\nexport interface ModalOptions {\n /** Display title for the modal header. */\n title?: PanelTitle;\n /** Icon displayed in the modal title bar. */\n icon?: React.ReactNode;\n /** Size modifier affecting CSS max-width rules. */\n size?: 'small' | 'medium' | 'large' | 'fullscreen' | 'auto';\n /** If false, hides the modal backdrop exit click and header close button. */\n closable?: boolean;\n}\n\n/**\n * Represents a rendered instance of a panel or modal in the layout.\n */\nexport interface PanelInstance {\n /** Unique ID generated for this instance. */\n id: PanelInstanceId;\n /** React Component to mount inside the panel. */\n Component: ComponentType<any>;\n /** Property props passed to the Component. */\n props: Record<string, any>;\n /** The target rendering layout zone. */\n containerType: 'left-panel' | 'right-panel' | 'modal';\n /** Configuration metadata settings. */\n options: SidePanelOptions | ModalOptions;\n /** True if the form container has unsaved user edits. */\n dirty?: boolean;\n /** Custom warning options applied to the automatic unsaved changes modal. */\n dirtyOptions?: DirtyStateOptions;\n}\n\n/** Stores the active layout structures for floating overlays. */\nexport interface PanelState {\n /** The currently open left drawer panel instance, or null. */\n leftPanel: PanelInstance | null;\n /** The currently open right drawer panel instance, or null. */\n rightPanel: PanelInstance | null;\n /** Stack containing all active floating modal instances. */\n modals: PanelInstance[];\n}\n\n/** Exposes methods to trigger state actions on drawers and modals. */\nexport interface PanelActions {\n /** Mounts a panel in the left-side container drawer. */\n openLeftPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Mounts a panel in the right-side container drawer. */\n openRightPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Pushes a new modal component instance to the top of the stack. */\n openModal: <P extends object>(Component: ComponentType<P>, props: P, options?: ModalOptions) => PanelInstanceId;\n /** Closes an instance by ID. */\n close: (id: PanelInstanceId) => void;\n /** Closes all drawers and modals in a single action. */\n closeAll: () => void;\n /** Closes all open modals. */\n closeAllModals: () => void;\n /** Retrieves metadata for an active instance by ID. */\n getInstance: (id: PanelInstanceId) => PanelInstance | undefined;\n /** Updates the props, configuration options, or dirty flag of an active panel. */\n updateInstance: (id: PanelInstanceId, updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>) => void;\n /** Flags an instance as dirty (contains unsaved changes). */\n setDirty: (id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => void;\n /** Subscribes a custom close confirmation intercept handler. */\n registerCloseHandler: (id: PanelInstanceId, handler: () => Promise<boolean>) => void;\n /** Unsubscribes close confirmation handler. */\n unregisterCloseHandler: (id: PanelInstanceId) => void;\n}\n\nlet idCounter = 0;\nconst generateId = (): PanelInstanceId => `panel-${++idCounter}-${Date.now()}`;\n\nconst closeHandlers = new Map<PanelInstanceId, () => Promise<boolean>>();\n\nconst initialState: PanelState = {\n leftPanel: null,\n rightPanel: null,\n modals: [],\n};\n\nconst PanelStateContext = createContext<PanelState | null>(null);\nconst PanelActionsContext = createContext<PanelActions | null>(null);\n\n/**\n * PanelProvider component manages the state and action handlers\n * for drawers (left/right) and active stacked modal overlays.\n */\nexport const PanelProvider: React.FC<{ children: ReactNode }> = ({ children }) => {\n const [state, setState] = useState<PanelState>(initialState);\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const registerCloseHandler = useCallback((id: PanelInstanceId, handler: () => Promise<boolean>) => {\n closeHandlers.set(id, handler);\n }, []);\n\n const unregisterCloseHandler = useCallback((id: PanelInstanceId) => {\n closeHandlers.delete(id);\n }, []);\n\n const openLeftPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.leftPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'left-panel',\n options,\n };\n setState(s => ({ ...s, leftPanel: instance }));\n return id;\n },\n []\n );\n\n const openRightPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.rightPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'right-panel',\n options,\n };\n setState(s => ({ ...s, rightPanel: instance }));\n return id;\n },\n []\n );\n\n const openModal = useCallback(\n <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: ModalOptions = {}\n ): PanelInstanceId => {\n const id = generateId();\n const formTitle = (props as any).title;\n \n const modalOptions: ModalOptions = {\n ...options,\n title: options.title || formTitle || 'Confirmation',\n };\n\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'modal',\n options: modalOptions,\n };\n setState(s => ({ ...s, modals: [...s.modals, instance] }));\n return id;\n },\n []\n );\n\n const close = useCallback((id: PanelInstanceId) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? null : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? null : s.rightPanel,\n modals: s.modals.filter(m => m.id !== id),\n }));\n }, []);\n\n const closeAll = useCallback(() => {\n setState(initialState);\n }, []);\n\n const closeAllModals = useCallback(() => {\n setState(s => ({ ...s, modals: [] }));\n }, []);\n\n const getInstance = useCallback(\n (id: PanelInstanceId): PanelInstance | undefined => {\n if (state.leftPanel?.id === id) return state.leftPanel;\n if (state.rightPanel?.id === id) return state.rightPanel;\n return state.modals.find(m => m.id === id);\n },\n [state]\n );\n\n const updateInstance = useCallback(\n (\n id: PanelInstanceId,\n updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>\n ) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? { ...s.leftPanel, ...updates } : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? { ...s.rightPanel, ...updates } : s.rightPanel,\n modals: s.modals.map(m => m.id === id ? { ...m, ...updates } : m),\n }));\n },\n []\n );\n\n const setDirty = useCallback((id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => {\n updateInstance(id, { dirty, dirtyOptions: options });\n }, [updateInstance]);\n\n const actions = useMemo<PanelActions>(\n () => ({\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n }),\n [\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n ]\n );\n\n return (\n <PanelStateContext.Provider value={state}>\n <PanelActionsContext.Provider value={actions}>\n {children}\n </PanelActionsContext.Provider>\n </PanelStateContext.Provider>\n );\n};\n\n/**\n * React hook to retrieve the active floating/drawer panels state.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelState = (): PanelState => {\n const ctx = useContext(PanelStateContext);\n if (!ctx) throw new Error('usePanelState must be used within PanelProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve actions enabling drawer toggles and modal push actions.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelActions = (): PanelActions => {\n const ctx = useContext(PanelActionsContext);\n if (!ctx) throw new Error('usePanelActions must be used within PanelProvider');\n return ctx;\n};\n","import React, { useEffect, useRef } from 'react';\nimport { useFormContainer } from '../components/FormContainerContext';\nimport { useFormatMessage, usePredefinedMessages } from '../components/WindowManagerContext';\n\n/**\n * Props for the {@link ConfirmationForm} component.\n */\nexport interface ConfirmationFormProps {\n /** Optional custom title text or localizable descriptor for the dialog container. */\n title?: string | { id: string; defaultMessage?: string; values?: any };\n /** Main message text or localizable descriptor to display. */\n message: string | { id: string; defaultMessage?: string; values?: any };\n /** Optional auxiliary top alert notification text. */\n alert?: string;\n /** Type style classification for the alert notice banner. */\n alertType?: 'info' | 'warning' | 'success' | 'danger';\n /** If true, changes action button labels to 'Yes' and 'No' instead of 'OK' and 'Cancel'. */\n useYesNoTitles?: boolean;\n /** Callback fired when the user selects the confirm button. */\n onOK?: () => void;\n /** Callback fired when the user selects the cancel button. */\n onCancel?: () => void;\n}\n\n/**\n * ConfirmationForm component renders a standard dialog content layout,\n * allowing users to confirm actions or abort them. Exposes action callbacks.\n */\nexport const ConfirmationForm: React.FC<ConfirmationFormProps> = ({\n title,\n message,\n alert,\n alertType = 'info',\n useYesNoTitles = false,\n onOK,\n onCancel,\n}) => {\n const { requestClose, setIcon, setTitle } = useFormContainer();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const confirmButtonRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (title) {\n const resolvedTitle = typeof title === 'string' ? title : formatMessage(title);\n setTitle(resolvedTitle);\n }\n \n if (setIcon) {\n setIcon(<span>❓</span>);\n }\n }, [title, setTitle, setIcon, formatMessage]);\n\n useEffect(() => {\n confirmButtonRef.current?.focus();\n }, []);\n\n const resolvedMessage = typeof message === 'string' ? message : formatMessage(message);\n\n const cancelLabel = useYesNoTitles\n ? formatMessage(predefinedMessages.no)\n : formatMessage(predefinedMessages.cancel);\n\n const confirmLabel = useYesNoTitles\n ? formatMessage(predefinedMessages.yes)\n : formatMessage(predefinedMessages.ok);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onOK?.();\n requestClose();\n };\n\n const handleCancel = () => {\n onCancel?.();\n requestClose();\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"p-3 d-flex flex-column gap-3\">\n {alert && (\n <div className={`alert alert-${alertType === 'danger' ? 'danger' : alertType} d-flex align-items-center gap-2 m-0 p-2.5 small`}>\n <span>ℹ️</span>\n <span>{alert}</span>\n </div>\n )}\n\n <div style={{ fontSize: '0.9rem', color: 'inherit', lineHeight: 1.5 }}>\n {resolvedMessage}\n </div>\n\n <hr className=\"my-2 opacity-10\" />\n\n <div className=\"d-flex justify-content-end gap-2\">\n <button\n type=\"button\"\n className=\"btn btn-sm btn-outline-secondary font-monospace\"\n onClick={handleCancel}\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n className=\"btn btn-sm btn-primary font-monospace\"\n ref={confirmButtonRef}\n >\n {confirmLabel}\n </button>\n </div>\n </form>\n );\n};\n\nexport default ConfirmationForm;\n","import React, { useCallback, useRef, useEffect, useState, useMemo } from 'react';\nimport { usePanelState, usePanelActions } from './PanelProviderContext';\nimport { FormContainerProvider, type FormContainerContract, type CloseOptions } from './FormContainerContext';\nimport type { PanelInstance, ModalOptions, PanelTitle } from './PanelProviderContext';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\n\n/**\n * Interface representing props for the internal {@link ModalRenderer} component.\n */\ninterface ModalRendererProps {\n /** The panel instance containing component structure, state, and option flags. */\n modal: PanelInstance;\n /** The 0-based depth index of the modal within the active stack. */\n index: number;\n /** True if this modal is currently at the top of the stack. */\n isTopmost: boolean;\n}\n\n/**\n * ModalRenderer component renders a single modal window wrapped inside\n * the FormContainerProvider context, enabling subcomponents to request closes and set dirty states.\n */\nconst ModalRenderer: React.FC<ModalRendererProps> = ({ modal, index, isTopmost }) => {\n const { close, openModal, updateInstance, setDirty } = usePanelActions();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const { dir } = useWindowManagerState();\n const { modalClass, modalBodyClass } = useStyleClasses();\n const closeHandlerRef = useRef<(() => boolean | Promise<boolean>) | null>(null);\n\n const { id, Component, props, options, dirty, dirtyOptions } = modal;\n const modalOptions = options as ModalOptions;\n\n const [icon, setIconState] = useState<React.ReactNode>(modalOptions.icon || null);\n\n const optionsRef = useRef(modalOptions);\n optionsRef.current = modalOptions;\n\n const baseTitle = formatLabel(modalOptions.title, formatMessage);\n\n const handleClose = useCallback(async (options?: CloseOptions) => {\n if (options?.force) {\n close(id);\n return;\n }\n\n if (closeHandlerRef.current) {\n const canClose = await closeHandlerRef.current();\n if (!canClose) return;\n close(id);\n return;\n }\n\n if (dirty) {\n openModal(\n ConfirmationForm,\n {\n title: dirtyOptions?.title || predefinedMessages.unsavedChangesTitle,\n message: dirtyOptions?.message || {\n id: predefinedMessages.unsavedChangesMessage.id,\n defaultMessage: predefinedMessages.unsavedChangesMessage.defaultMessage,\n values: { title: baseTitle }\n },\n alert: dirtyOptions?.alert,\n alertType: dirtyOptions?.alertType || 'danger',\n useYesNoTitles: true,\n onOK: () => close(id),\n },\n { size: 'small' }\n );\n return;\n }\n\n close(id);\n }, [close, openModal, id, dirty, dirtyOptions, baseTitle, predefinedMessages]);\n\n const handleSetDirty = useCallback((dirty: boolean, options?: any) => setDirty(id, dirty, options), [setDirty, id]);\n const handleSetTitle = useCallback((title: PanelTitle) => updateInstance(id, { options: { ...optionsRef.current, title } }), [updateInstance, id]);\n const handleSetIcon = useCallback((newIcon: React.ReactNode) => setIconState(newIcon), []);\n const handleOnCloseRequested = useCallback((handler: () => boolean | Promise<boolean>) => {\n closeHandlerRef.current = handler;\n return () => { closeHandlerRef.current = null; };\n }, []);\n\n const contract: FormContainerContract = useMemo(() => ({\n requestClose: handleClose,\n setDirty: handleSetDirty,\n setTitle: handleSetTitle,\n setIcon: handleSetIcon,\n onCloseRequested: handleOnCloseRequested,\n containerType: 'modal',\n instanceId: id,\n }), [handleClose, handleSetDirty, handleSetTitle, handleSetIcon, handleOnCloseRequested, id]);\n\n const displayTitle = dirty ? `${baseTitle} *` : baseTitle;\n\n const sizeClass = modalOptions.size ? `v2-modal-size-${modalOptions.size}` : 'v2-modal-size-auto';\n const showCloseButton = modalOptions.closable !== false;\n\n useEffect(() => {\n if (!isTopmost || !showCloseButton) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n handleClose();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [handleClose, showCloseButton, isTopmost]);\n\n const baseZIndex = 10000;\n const modalZIndex = baseZIndex + (index * 10);\n\n return (\n <div className=\"v2-modal-overlay\" style={{ zIndex: modalZIndex }} dir={dir}>\n <div className=\"v2-modal-curtain\" onClick={showCloseButton ? () => handleClose() : undefined} />\n <div className={`v2-modal-window ${sizeClass} ${modalClass ?? ''}`}>\n <div className=\"v2-modal-header\">\n {icon && <div className=\"v2-modal-icon\">{icon}</div>}\n <h4 className=\"v2-modal-title\">{displayTitle}</h4>\n {showCloseButton && (\n <button\n className=\"v2-modal-close-button\"\n onClick={() => handleClose()}\n title={formatMessage(predefinedMessages.closeTooltip)}\n type=\"button\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n <div className={`v2-modal-body ${modalBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\n/**\n * ModalStackRenderer component acts as the global container rendering\n * all active stacked modal windows in the workspace.\n */\nexport const ModalStackRenderer: React.FC = () => {\n const { modals } = usePanelState();\n\n if (modals.length === 0) return null;\n\n return (\n <>\n {modals.map((modal, index) => (\n <ModalRenderer\n key={modal.id}\n modal={modal}\n index={index}\n isTopmost={index === modals.length - 1}\n />\n ))}\n </>\n );\n};\n\nexport default ModalStackRenderer;\n","import React, { useCallback, useRef, useEffect, useState, useMemo } from 'react';\nimport { usePanelState, usePanelActions } from './PanelProviderContext';\nimport { FormContainerProvider, type FormContainerContract, type CloseOptions } from './FormContainerContext';\nimport type { PanelInstance, SidePanelOptions, PanelTitle } from './PanelProviderContext';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\n\n/**\n * Props for the internal {@link SidePanelRendererItem} component.\n */\ninterface SidePanelRendererItemProps {\n /** The panel instance containing metadata, component type, and rendering state. */\n panel: PanelInstance;\n /** Floating anchor edge side for the drawer panel. */\n position: 'left' | 'right';\n /** Default width applied if no panel override configuration is provided. */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRendererItem component renders an individual left or right drawer panel instance\n * wrapped inside the FormContainerProvider context. Handles dirty state verification before close.\n */\nconst SidePanelRendererItem: React.FC<SidePanelRendererItemProps> = ({ panel, position, defaultWidth }) => {\n const { close, openModal, updateInstance, setDirty, registerCloseHandler, unregisterCloseHandler } = usePanelActions();\n const { modals } = usePanelState();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const { dir } = useWindowManagerState();\n const { sidePanelClass, sidePanelBodyClass } = useStyleClasses();\n const closeHandlerRef = useRef<(() => boolean | Promise<boolean>) | null>(null);\n\n const { id, Component, props, options, dirty, dirtyOptions } = panel;\n const panelOptions = options as SidePanelOptions;\n const [icon, setIconState] = useState<React.ReactNode>(panelOptions.icon || null);\n\n const optionsRef = useRef(panelOptions);\n optionsRef.current = panelOptions;\n\n const baseTitle = formatLabel(panelOptions.title, formatMessage);\n\n const handleClose = useCallback(async (options?: CloseOptions) => {\n if (options?.force) {\n close(id);\n return;\n }\n\n if (closeHandlerRef.current) {\n const canClose = await closeHandlerRef.current();\n if (!canClose) return;\n close(id);\n return;\n }\n\n if (dirty) {\n openModal(\n ConfirmationForm,\n {\n title: dirtyOptions?.title || predefinedMessages.unsavedChangesTitle,\n message: dirtyOptions?.message || {\n id: predefinedMessages.unsavedChangesMessage.id,\n defaultMessage: predefinedMessages.unsavedChangesMessage.defaultMessage,\n values: { title: baseTitle }\n },\n alert: dirtyOptions?.alert,\n alertType: dirtyOptions?.alertType || 'danger',\n useYesNoTitles: true,\n onOK: () => close(id),\n },\n { size: 'small' }\n );\n return;\n }\n\n close(id);\n }, [close, openModal, id, dirty, dirtyOptions, baseTitle, predefinedMessages]);\n\n const canClose = useCallback(async (): Promise<boolean> => {\n if (closeHandlerRef.current) {\n return await closeHandlerRef.current();\n }\n return !dirty;\n }, [dirty]);\n\n useEffect(() => {\n registerCloseHandler(id, canClose);\n return () => unregisterCloseHandler(id);\n }, [id, canClose, registerCloseHandler, unregisterCloseHandler]);\n\n const handleSetDirty = useCallback((dirty: boolean, options?: any) => setDirty(id, dirty, options), [setDirty, id]);\n const handleSetTitle = useCallback((title: PanelTitle) => updateInstance(id, { options: { ...optionsRef.current, title } }), [updateInstance, id]);\n const handleSetIcon = useCallback((newIcon: React.ReactNode) => setIconState(newIcon), []);\n const handleOnCloseRequested = useCallback((handler: () => boolean | Promise<boolean>) => {\n closeHandlerRef.current = handler;\n return () => { closeHandlerRef.current = null; };\n }, []);\n\n const contract: FormContainerContract = useMemo(() => ({\n requestClose: handleClose,\n setDirty: handleSetDirty,\n setTitle: handleSetTitle,\n setIcon: handleSetIcon,\n onCloseRequested: handleOnCloseRequested,\n containerType: position === 'left' ? 'left-panel' : 'right-panel',\n instanceId: id,\n }), [handleClose, handleSetDirty, handleSetTitle, handleSetIcon, handleOnCloseRequested, position, id]);\n\n const displayTitle = dirty ? `${baseTitle} *` : baseTitle;\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && modals.length === 0) {\n handleClose();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [handleClose, modals.length]);\n\n const width = panelOptions.width || defaultWidth || 400;\n const widthStyle = typeof width === 'number' ? `${width}px` : width;\n\n return (\n <div \n className={`v2-side-panel v2-side-panel-${position} v2-side-panel-visible ${sidePanelClass ?? ''}`}\n style={{ width: widthStyle }}\n dir={dir}\n >\n <div className=\"v2-side-panel-window\">\n <div className=\"v2-side-panel-header\">\n {icon && <div className=\"v2-side-panel-icon\">{icon}</div>}\n <h4 className=\"v2-side-panel-title\">{displayTitle}</h4>\n <button\n className=\"v2-side-panel-close-button\"\n onClick={() => handleClose()}\n title={formatMessage(predefinedMessages.closeTooltip)}\n type=\"button\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div className={`v2-side-panel-body ${sidePanelBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\nexport interface SidePanelRendererProps {\n /**\n * Default panel width applied when openLeftPanel/openRightPanel do not specify one.\n * Accepts a number (treated as px) or any CSS width string (e.g. '40vw').\n * Falls back to 400px if omitted.\n */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRenderer component acts as the global container rendering both\n * left and right side drawers if they are currently active.\n */\nexport const SidePanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel, rightPanel } = usePanelState();\n return (\n <>\n {leftPanel && <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />}\n {rightPanel && <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />}\n </>\n );\n};\n\n/**\n * LeftPanelRenderer component renders ONLY the left side drawer if it is currently active.\n */\nexport const LeftPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel } = usePanelState();\n if (!leftPanel) return null;\n return <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />;\n};\n\n/**\n * RightPanelRenderer component renders ONLY the right side drawer if it is currently active.\n */\nexport const RightPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { rightPanel } = usePanelState();\n if (!rightPanel) return null;\n return <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />;\n};\n\nexport default SidePanelRenderer;\n","/**\n * @file Sidebar.tsx\n * @description Sidebar navigation strip and drawer container component.\n * Supports eager/lazy mounting, state preservation (display: none), and positioning (left/right).\n */\n\nimport React, {\n useState,\n useEffect,\n useRef,\n useCallback,\n useImperativeHandle,\n forwardRef,\n} from 'react';\nimport { useFormatMessage, usePredefinedMessages } from './WindowManagerContext';\n\n\n// ==========================================\n// Types\n// ==========================================\n\n/**\n * Per-tab configuration supplied by the consuming application.\n */\nexport interface SidebarTab {\n id: string;\n label: string;\n icon: React.ReactNode;\n /**\n * Mount immediately when the Sidebar first renders, not on first user click.\n * Implies `preserveState: true`.\n * Use when other parts of the app need to interact with the panel before\n * the user has opened it (e.g. push data into a context, warm up a WebGL map).\n * Default: false\n */\n eagerMount?: boolean;\n /**\n * Once mounted for the first time, keep the component alive in the DOM\n * behind `display: none` when closed instead of unmounting it.\n * Use for panels with expensive local state (long forms, WebGL scenes, etc.).\n * Ignored when `eagerMount` is true (eagerly mounted panels are always preserved).\n * Default: false\n */\n preserveState?: boolean;\n /**\n * Called to obtain the drawer content for this tab.\n * @param tabId - the id of this tab\n * @param onClose - call to collapse the sidebar drawer\n * @param onOpen - call to expand the drawer and select this tab programmatically\n * (useful when the panel itself detects it has new data to show)\n */\n renderContent: (tabId: string, onClose: () => void, onOpen: () => void) => React.ReactNode;\n}\n\nexport interface SidebarProps {\n /** Which side the tab strip and drawer appear on. Default: 'right' */\n position?: 'left' | 'right';\n tabs: SidebarTab[];\n /** Width of the open drawer. Default: '220px' */\n drawerWidth?: string;\n /** Controlled active tab id. Leave undefined to use internal state. */\n activeTabId?: string | null;\n /** Called when the active tab changes in uncontrolled mode. */\n onActiveTabChange?: (tabId: string | null) => void;\n /** Main workspace content, rendered between the strip and drawer (or around them). */\n children?: React.ReactNode;\n}\n\n/**\n * Imperative handle exposed by <Sidebar ref={...}> via forwardRef.\n * Allows external components (outside the sidebar tree) to control\n * which tab is open without prop drilling.\n */\nexport interface SidebarHandle {\n /** Expand the drawer and activate the tab with the given id. */\n openTab: (tabId: string) => void;\n /** Collapse the drawer (equivalent to clicking the active tab icon). */\n closeDrawer: () => void;\n /** Returns the currently active tab id, or null if the drawer is collapsed. */\n getActiveTab: () => string | null;\n}\n\n// ==========================================\n// Component\n// ==========================================\n\n/**\n * Sidebar component rendering a tab strip and a collapsible content drawer.\n * Supports imperative method bindings like openTab and closeDrawer via forwardRef.\n */\nexport const Sidebar = forwardRef<SidebarHandle, SidebarProps>(function Sidebar(\n {\n position = 'right',\n tabs,\n drawerWidth = '220px',\n activeTabId: controlledActiveTabId,\n onActiveTabChange,\n children,\n },\n ref\n) {\n const isControlled = controlledActiveTabId !== undefined;\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n\n // Internal active tab state (used when uncontrolled)\n const [internalActiveTabId, setInternalActiveTabId] = useState<string | null>(null);\n\n // The effective active tab id — either from props (controlled) or internal state\n const activeTabId = isControlled ? controlledActiveTabId : internalActiveTabId;\n\n // Track which tabs have been mounted at least once\n // Pre-populate with all eagerMount tabs\n const [mountedTabIds, setMountedTabIds] = useState<Set<string>>(() => {\n const initial = new Set<string>();\n for (const tab of tabs) {\n if (tab.eagerMount) initial.add(tab.id);\n }\n return initial;\n });\n\n // When tabs change (e.g. new eagerMount tabs added), mount them immediately\n useEffect(() => {\n const newEager = tabs.filter(t => t.eagerMount && !mountedTabIds.has(t.id));\n if (newEager.length > 0) {\n setMountedTabIds(prev => {\n const next = new Set(prev);\n for (const tab of newEager) next.add(tab.id);\n return next;\n });\n }\n }, [tabs]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Stable ref to active tab for imperative handle\n const activeTabIdRef = useRef<string | null>(activeTabId ?? null);\n useEffect(() => {\n activeTabIdRef.current = activeTabId ?? null;\n }, [activeTabId]);\n\n const setActiveTabId = useCallback(\n (id: string | null) => {\n if (isControlled) {\n onActiveTabChange?.(id);\n } else {\n setInternalActiveTabId(id);\n onActiveTabChange?.(id);\n }\n },\n [isControlled, onActiveTabChange]\n );\n\n // Expose imperative handle\n useImperativeHandle(\n ref,\n () => ({\n openTab: (tabId: string) => setActiveTabId(tabId),\n closeDrawer: () => setActiveTabId(null),\n getActiveTab: () => activeTabIdRef.current,\n }),\n [setActiveTabId]\n );\n\n const handleTabClick = (tabId: string) => {\n setActiveTabId(activeTabId === tabId ? null : tabId);\n };\n\n const handleClose = useCallback(() => setActiveTabId(null), [setActiveTabId]);\n\n // On first open of a non-eager tab, add it to mounted set\n useEffect(() => {\n if (activeTabId && !mountedTabIds.has(activeTabId)) {\n setMountedTabIds(prev => {\n const next = new Set(prev);\n next.add(activeTabId);\n return next;\n });\n }\n }, [activeTabId, mountedTabIds]);\n\n // On close of a standard tab (neither eagerMount nor preserveState), unmount it\n useEffect(() => {\n if (activeTabId !== null) return; // drawer just opened or is still open\n setMountedTabIds(prev => {\n let changed = false;\n const next = new Set(prev);\n for (const id of prev) {\n const tab = tabs.find(t => t.id === id);\n if (tab && !tab.eagerMount && !tab.preserveState) {\n next.delete(id);\n changed = true;\n }\n }\n return changed ? next : prev;\n });\n }, [activeTabId, tabs]);\n\n // ---- Render helpers ----\n\n const tabStrip = (\n <div className={`sidebar-tabs-strip ${position}`} style={{ width: '56px', height: '100%' }}>\n {tabs.map(tab => {\n const isActive = activeTabId === tab.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => handleTabClick(tab.id)}\n className={`sidebar-tab-btn ${isActive ? 'active' : ''}`}\n title={tab.label}\n aria-pressed={isActive}\n >\n {tab.icon}\n </button>\n );\n })}\n </div>\n );\n\n const drawer = (\n <div\n className={`sidebar-content-drawer h-100 ${position}`}\n style={{\n width: activeTabId ? drawerWidth : '0px',\n minWidth: activeTabId ? drawerWidth : '0px',\n overflow: 'hidden',\n flexShrink: 0,\n }}\n >\n {/* Render all mounted tabs; only the active one is visible */}\n {tabs.map(tab => {\n const isMounted = mountedTabIds.has(tab.id);\n if (!isMounted) return null;\n\n const isCurrent = activeTabId === tab.id;\n\n // Stable onOpen per tab id\n const onOpen = () => setActiveTabId(tab.id);\n\n return (\n <div\n key={tab.id}\n style={{\n display: isCurrent ? 'flex' : 'none',\n flexDirection: 'column',\n height: '100%',\n width: '100%',\n }}\n >\n {/* Drawer header */}\n <div\n className=\"d-flex align-items-center justify-content-between border-bottom border-secondary-subtle px-3 py-2 flex-shrink-0\"\n style={{ background: 'rgba(0,0,0,0.08)', minHeight: '38px' }}\n >\n <span className=\"sidebar-header-title\">{tab.label}</span>\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"btn btn-link p-0 text-secondary d-flex align-items-center\"\n style={{ textDecoration: 'none' }}\n title={formatMessage(predefinedMessages.closePanelTooltip)}\n aria-label={formatMessage(predefinedMessages.closePanelTooltip)}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n {/* Drawer body — consumer-supplied content */}\n <div className=\"flex-grow-1 overflow-auto\">\n {tab.renderContent(tab.id, handleClose, onOpen)}\n </div>\n </div>\n );\n })}\n </div>\n );\n\n return (\n <>\n {position === 'left' && tabStrip}\n {position === 'left' && drawer}\n {children}\n {position === 'right' && drawer}\n {position === 'right' && tabStrip}\n </>\n );\n});\n\nexport default Sidebar;\n"],"mappings":"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","names":["React","useState","useRef","useEffect","createPortal","createContext","useContext","useState","useRef","useMemo","useCallback","useEffect","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","jsx","WindowStateContext","createContext","WindowActionsContext","WindowI18nContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","useContext","PanelEventBus","event","callback","cb","data","initialLayout","initialPanels","initialFloating","WindowManagerProvider","children","formatMessage","predefinedMessages","dirProp","modalClass","modalBodyClass","sidePanelClass","sidePanelBodyClass","windowClass","windowBodyClass","state","setState","useState","stateRef","useRef","closeGuardsRef","mergedMessages","useMemo","eventBusRef","maxZRef","subscribe","useCallback","publish","getCascadedPosition","fav","currentFloating","x","y","width","height","isOverlapping","pos","w","wx","wy","attempts","viewW","viewH","bringToFront","id","z","prev","panel","selectActiveInTree","node","removePanelFromTree","idx","panels","p","activePanelId","updatedLeaf","c","sizes","sum","a","b","s","addPanelToLeaf","leafId","panelId","findFirstLeafId","child","openPanel","component","options","exists","entry","PanelRegistry","title","target","favPos","nextMinimized","m","cascaded","firstLeaf","newPanelInfo","nextPanels","stickyRight","stickyBottom","winW","winH","initialX","initialY","GAP","closePanel","cleanRoot","registerCloseGuard","guard","unregisterCloseGuard","setPanelDirty","dirty","updatePanelTitle","requestClosePanel","minimizePanel","lastFloatingRect","lastLeafId","win","findLeafForPanel","res","restorePanel","leafExists","targetId","parentLeafExists","canDrag","targetLeafId","floatPanel","rect","dockPanel","nextFloating","splitLeafInTree","position","newLeaf","setDraggedPanelId","dockPanelToGroup","newRoot","dockPanelToWorkspaceEdge","orientation","movePanelOrder","targetIndex","insertInLeaf","remaining","index","newPanels","closeLeafGroup","removeLeafFromTree","maximizePanel","updateSplitSizes","path","updateInTree","depth","i","updateFloatingPosition","updates","saveLayout","loadLayout","layoutJson","parsed","firstActive","e","setActivePanel","setDirection","dir","useEffect","actions","defaultFormatMessage","msg","text","key","value","styleClasses","useWindowManagerState","ctx","useWindowManagerActions","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","isElementRtl","el","closestDirEl","JsonContextMenu","createContext","useContext","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","createContext","useContext","useState","useCallback","useMemo","useRef","jsx","idCounter","generateId","closeHandlers","initialState","PanelStateContext","PanelActionsContext","PanelProvider","children","state","setState","stateRef","registerCloseHandler","id","handler","unregisterCloseHandler","openLeftPanel","Component","props","options","currentPanel","instance","s","openRightPanel","openModal","formTitle","modalOptions","close","m","closeAll","closeAllModals","getInstance","updateInstance","updates","setDirty","dirty","actions","usePanelState","ctx","usePanelActions","useEffect","useRef","jsx","jsxs","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","useRef","useEffect","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","Fragment","jsx","jsxs","domCache","hiddenContainerId","DefaultGridIcon","getOrCreateDomCacheElement","id","el","renderPanelContent","componentKey","registryEntry","PanelRegistry","Component","activePanelDimensions","panelLifecycleRegistry","getOrCreateLifecycleRegistry","panelId","entry","PreservedDOMWrapper","hostRef","useRef","useEffect","host","cachedEl","resizeObserver","entries","width","height","lifecycle","h","hiddenContainer","PreviewDOMWrapper","state","useWindowManagerState","formatMessage","useFormatMessage","panel","regEntry","disableLivePreview","lastSize","origW","origH","scale","displayW","displayH","rawTitle","title","formatLabel","initialChar","FormContainerProviderWrapper","children","requestClosePanel","setPanelDirty","registerCloseGuard","unregisterCloseGuard","updatePanelTitle","useWindowManagerActions","isMin","m","prevMinRef","contract","React","options","dirty","handler","reg","FormContainerProvider","WorkspaceGrid","node","path","onTabRightClick","activeDropZone","onHoverDropZone","onTabDragStart","hoveredTab","onTabHover","defaultPanelIcon","onRequestClosePanel","updateSplitSizes","LeafGroup","isRow","handleResizerMouseDown","idx","e","startOffset","startSizes","resizerEl","parentEl","parentSize","handleMouseMove","moveEvent","deltaPercentage","newSizes","handleMouseUp","child","size","leaf","openPanel","closeLeafGroup","setActivePanel","messages","usePredefinedMessages","windowClass","windowBodyClass","useStyleClasses","selectTab","isSelected","isGloballyActive","isHovered","isLast","isHoveredEmpty","sideClass","rect","side","WindowManager","skin","restorePanel","minimizePanel","maximizePanel","updateFloatingPosition","bringToFront","floatPanel","setDraggedPanelId","dockPanelToGroup","movePanelOrder","dockPanelToWorkspaceEdge","setDirection","openModal","usePanelActions","handleRequestClose","customOpts","resolve","opts","baseTitle","ConfirmationForm_default","taskbarRef","contextMenuRef","hoveredMinimized","setHoveredMinimized","useState","minimizedTooltipTimeoutRef","isContextMenuOpen","setIsContextMenuOpen","setActiveDropZone","activeDropZoneRef","dragPos","setDragPos","activeEdgeDrop","setActiveEdgeDropState","activeEdgeDropRef","setActiveEdgeDrop","val","setHoveredTab","hoveredTabRef","handleTabHover","leafId","index","handleHoverDropZone","position","handleTabDragStart","startX","startY","dragStarted","dx","dy","handleMouseUpWrapper","dropZone","targetTab","edgeDrop","targetIndex","handleTabRightClick","items","handleMinimizedRightClick","keys","cachedId","handleWindowBlur","workspaceRef","workspaceSize","setWorkspaceSize","observer","updateDir","isRtl","isElementRtl","closestDir","viewW","viewH","w","winW","winH","winX","winY","newWidth","newHeight","newX","newY","changed","GAP","maxX","maxY","handleMouseDownGlobal","target","windowEl","winId","panelEl","startDrag","floatingWin","startPosX","startPosY","startResize","startW","startH","dw","dh","parsedX","parsedY","parsedW","parsedH","isRightSnapped","isBottomSnapped","scrollTaskbar","direction","amount","currentBsTheme","setCurrentBsTheme","updateThemeState","activeTheme","obs","isMaximized","isDragged","isFocused","isRight","isBottom","icon","createPortal","targetEl","JsonContextMenu","WindowManager_default","useCallback","useRef","useEffect","useState","useMemo","Fragment","jsx","jsxs","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","sizeClass","showCloseButton","useEffect","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","useCallback","useRef","useEffect","useState","useMemo","Fragment","jsx","jsxs","SidePanelRendererItem","panel","position","defaultWidth","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","canClose","useEffect","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","handleKeyDown","e","width","widthStyle","FormContainerProvider","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","useState","useEffect","useRef","useCallback","useImperativeHandle","forwardRef","Fragment","jsx","jsxs","Sidebar","forwardRef","position","tabs","drawerWidth","controlledActiveTabId","onActiveTabChange","children","ref","isControlled","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","internalActiveTabId","setInternalActiveTabId","useState","activeTabId","mountedTabIds","setMountedTabIds","initial","tab","useEffect","newEager","t","prev","next","activeTabIdRef","useRef","setActiveTabId","useCallback","id","useImperativeHandle","tabId","handleTabClick","handleClose","changed","tabStrip","isActive","drawer","isCurrent","onOpen"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/WindowManager.tsx","../src/components/WindowManagerContext.tsx","../src/components/PanelRegistry.ts","../src/components/predefinedMessages.ts","../src/utils/rtl.ts","../src/components/FormContainerContext.ts","../src/components/PanelProviderContext.tsx","../src/forms/ConfirmationForm.tsx","../src/WorkspaceClient.ts","../src/components/ModalStackRenderer.tsx","../src/components/SidePanelRenderer.tsx","../src/components/Sidebar.tsx"],"sourcesContent":["/**\n * @file WindowManager.tsx\n * @description Core component for react-dockable-desktop layout engine.\n * Renders the workspace desktop containing docked splits, tabbed panels, floated windows,\n * resize handles, context menus, and taskbar docks. Exposes lifecycle event listeners.\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useWindowManagerState, useWindowManagerActions, useFormatMessage, formatLabel, usePredefinedMessages, useStyleClasses, useRegistry } from './WindowManagerContext';\nimport type { LayoutNode, LayoutLeafNode } from './WindowManagerContext';\nimport type { PanelRegistryClass } from './PanelRegistry';\nimport { isElementRtl } from '../utils/rtl';\nimport { JsonContextMenu, type JsonContextMenuRef } from 'replace-react-contexify';\nimport 'replace-react-contexify/styles.css';\nimport { FormContainerProvider } from './FormContainerContext';\nimport type { FormContainerContract } from './FormContainerContext';\nimport { usePanelActions } from './PanelProviderContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\n\n// DOM Element Cache for preserving contexts (WebGL map, text area etc.)\nconst domCache = new Map<string, HTMLDivElement>();\nconst hiddenContainerId = 'preserved-dom-container';\n\nconst DefaultGridIcon = (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ display: 'block' }}>\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"9\" rx=\"1\" />\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"5\" rx=\"1\" />\n <rect x=\"14\" y=\"12\" width=\"7\" height=\"9\" rx=\"1\" />\n <rect x=\"3\" y=\"16\" width=\"7\" height=\"5\" rx=\"1\" />\n </svg>\n);\n\nconst getOrCreateDomCacheElement = (id: string): HTMLDivElement => {\n let el = domCache.get(id);\n if (!el) {\n el = document.createElement('div');\n el.style.width = '100%';\n el.style.height = '100%';\n domCache.set(id, el);\n }\n return el;\n};\n\n\n// ==========================================\n// 3. Persistent DOM Container Host & Slot\n// ==========================================\n\nconst renderPanelContent = (id: string, componentKey: string, registry: PanelRegistryClass) => {\n const registryEntry = registry.get(componentKey);\n if (!registryEntry) {\n return (\n <div className=\"dw-unregistered-panel\" style={{ border: '2px dashed #dc3545' }}>\n <h6 style={{ fontWeight: 700, marginBottom: '0.25rem' }}>⚠️ Component Unregistered</h6>\n <span style={{ fontSize: '0.875rem', color: 'var(--text-secondary, #94a3b8)' }}>Key: {componentKey}</span>\n </div>\n );\n }\n const Component = registryEntry.Component;\n return <Component panelId={id} />;\n};\n\nconst activePanelDimensions = new Map<string, { width: number; height: number }>();\n\nconst panelLifecycleRegistry = new Map<string, {\n onClose: Set<() => void>;\n onMinimize: Set<() => void>;\n onRestore: Set<() => void>;\n onResize: Set<(w: number, h: number) => void>;\n}>();\n\nconst getOrCreateLifecycleRegistry = (panelId: string) => {\n let entry = panelLifecycleRegistry.get(panelId);\n if (!entry) {\n entry = {\n onClose: new Set(),\n onMinimize: new Set(),\n onRestore: new Set(),\n onResize: new Set(),\n };\n panelLifecycleRegistry.set(panelId, entry);\n }\n return entry;\n};\n\nconst PreservedDOMWrapper: React.FC<{ panelId: string }> = ({ panelId }) => {\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const cachedEl = getOrCreateDomCacheElement(panelId);\n host.appendChild(cachedEl);\n\n const resizeObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n const { width, height } = entry.contentRect;\n if (width > 0 && height > 0) {\n activePanelDimensions.set(panelId, { width, height });\n const lifecycle = panelLifecycleRegistry.get(panelId);\n if (lifecycle) {\n lifecycle.onResize.forEach(h => h(width, height));\n }\n }\n }\n });\n resizeObserver.observe(host);\n\n return () => {\n resizeObserver.disconnect();\n let hiddenContainer = document.getElementById(hiddenContainerId);\n if (!hiddenContainer) {\n hiddenContainer = document.createElement('div');\n hiddenContainer.id = hiddenContainerId;\n hiddenContainer.style.display = 'none';\n document.body.appendChild(hiddenContainer);\n }\n hiddenContainer.appendChild(cachedEl);\n };\n }, [panelId]);\n\n return <div ref={hostRef} style={{ width: '100%', height: '100%' }} />;\n};\n\nconst PreviewDOMWrapper: React.FC<{ panelId: string }> = ({ panelId }) => {\n const state = useWindowManagerState();\n const registry = useRegistry();\n const formatMessage = useFormatMessage();\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n const panel = state.panels[panelId];\n const regEntry = panel ? registry.get(panel.component) : null;\n const disableLivePreview = regEntry?.defaultOptions?.disableLivePreview || false;\n\n const lastSize = activePanelDimensions.get(panelId) || { width: 800, height: 500 };\n const origW = lastSize.width;\n const origH = lastSize.height;\n const maxW = 220;\n const maxH = 140;\n const scale = Math.min(maxW / origW, maxH / origH);\n\n useEffect(() => {\n if (disableLivePreview) return;\n\n const host = hostRef.current;\n if (!host) return;\n\n const cachedEl = domCache.get(panelId);\n if (!cachedEl) return;\n\n host.appendChild(cachedEl);\n\n return () => {\n let hiddenContainer = document.getElementById(hiddenContainerId);\n if (!hiddenContainer) {\n hiddenContainer = document.createElement('div');\n hiddenContainer.id = hiddenContainerId;\n hiddenContainer.style.display = 'none';\n document.body.appendChild(hiddenContainer);\n }\n hiddenContainer.appendChild(cachedEl);\n };\n }, [panelId, disableLivePreview]);\n\n if (disableLivePreview) {\n const displayW = origW * scale;\n const displayH = origH * scale;\n const rawTitle = panel?.title || regEntry?.defaultOptions?.title || 'Panel';\n const title = formatLabel(rawTitle, formatMessage);\n const initialChar = (Array.from(title)[0] || 'P').toUpperCase();\n\n return (\n <div\n className=\"taskbar-item-preview-frame\"\n style={{\n width: `${displayW}px`,\n height: `${displayH}px`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(108, 117, 125, 0.15)',\n border: '1px dashed var(--taskbar-item-border, rgba(255, 255, 255, 0.15))'\n }}\n >\n <div\n style={{\n fontSize: '2rem',\n fontWeight: 600,\n color: 'var(--panel-title-color, var(--panel-text, rgba(255, 255, 255, 0.85)))',\n userSelect: 'none'\n }}\n >\n {initialChar}\n </div>\n </div>\n );\n }\n\n return (\n <div\n className=\"taskbar-item-preview-frame\"\n style={{\n width: `${origW * scale}px`,\n height: `${origH * scale}px`,\n }}\n >\n <div\n ref={hostRef}\n className=\"taskbar-item-preview-host\"\n style={{\n width: `${origW}px`,\n height: `${origH}px`,\n transform: `scale(${scale})`,\n transformOrigin: 'top left',\n position: 'absolute',\n top: 0,\n left: 0,\n ['--preview-scale' as string]: scale\n }}\n />\n </div>\n );\n};\n\nconst FormContainerProviderWrapper: React.FC<{ panelId: string; children: React.ReactNode }> = ({ panelId, children }) => {\n const state = useWindowManagerState();\n const { requestClosePanel, setPanelDirty, registerCloseGuard, unregisterCloseGuard, updatePanelTitle } = useWindowManagerActions();\n\n const isMin = state.minimized.some(m => m.id === panelId);\n const prevMinRef = useRef(isMin);\n\n useEffect(() => {\n const entry = panelLifecycleRegistry.get(panelId);\n if (!entry) return;\n\n if (isMin && !prevMinRef.current) {\n entry.onMinimize.forEach(h => h());\n } else if (!isMin && prevMinRef.current) {\n entry.onRestore.forEach(h => h());\n }\n prevMinRef.current = isMin;\n }, [isMin, panelId]);\n\n useEffect(() => {\n return () => {\n const entry = panelLifecycleRegistry.get(panelId);\n if (entry) {\n entry.onClose.forEach(h => h());\n panelLifecycleRegistry.delete(panelId);\n }\n };\n }, [panelId]);\n\n const contract = React.useMemo<FormContainerContract>(() => ({\n requestClose: (options) => requestClosePanel(panelId, options),\n setDirty: (dirty) => setPanelDirty(panelId, dirty),\n onCloseRequested: (handler) => {\n registerCloseGuard(panelId, handler);\n return () => unregisterCloseGuard(panelId);\n },\n setTitle: (title) => updatePanelTitle(panelId, title),\n instanceId: panelId,\n onClose: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onClose.add(handler);\n return () => reg.onClose.delete(handler);\n },\n onMinimize: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onMinimize.add(handler);\n return () => reg.onMinimize.delete(handler);\n },\n onRestore: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onRestore.add(handler);\n return () => reg.onRestore.delete(handler);\n },\n onResize: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onResize.add(handler);\n return () => reg.onResize.delete(handler);\n }\n }), [panelId, requestClosePanel, setPanelDirty, registerCloseGuard, unregisterCloseGuard, updatePanelTitle]);\n\n return (\n <FormContainerProvider value={contract}>\n {children}\n </FormContainerProvider>\n );\n};\n\n\n\n\n// ==========================================\n// 4. Panel Tab Headers & Split Layout Component\n// ==========================================\n\ninterface WorkspaceGridProps {\n node: LayoutNode;\n path: number[];\n onTabRightClick: (id: string, e: React.MouseEvent) => void;\n activeDropZone: { leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null;\n onHoverDropZone: (leafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center' | null) => void;\n onTabDragStart: (id: string, e: React.MouseEvent) => void;\n hoveredTab: { leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null;\n onTabHover: (leafId: string, panelId: string, index: number, side: 'left' | 'right' | null) => void;\n defaultPanelIcon?: React.ReactNode;\n onRequestClosePanel: (id: string) => void;\n}\n\nconst WorkspaceGrid: React.FC<WorkspaceGridProps> = ({ node, path, onTabRightClick, activeDropZone, onHoverDropZone, onTabDragStart, hoveredTab, onTabHover, defaultPanelIcon, onRequestClosePanel }) => {\n const { updateSplitSizes } = useWindowManagerActions();\n\n if (node.type === 'leaf') {\n return <LeafGroup leaf={node} onTabRightClick={onTabRightClick} activeDropZone={activeDropZone} onHoverDropZone={onHoverDropZone} onTabDragStart={onTabDragStart} hoveredTab={hoveredTab} onTabHover={onTabHover} defaultPanelIcon={defaultPanelIcon} onRequestClosePanel={onRequestClosePanel} />;\n }\n\n const isRow = node.orientation === 'horizontal';\n\n const handleResizerMouseDown = (idx: number, e: React.MouseEvent) => {\n e.preventDefault();\n const startOffset = isRow ? e.clientX : e.clientY;\n const startSizes = [...node.sizes];\n\n // Add active classes directly for zero-latency DOM responsiveness during drag\n const resizerEl = e.currentTarget as HTMLDivElement;\n resizerEl.classList.add('active');\n document.body.classList.add('resizing-active', isRow ? 'resizing-row-active' : 'resizing-col-active');\n\n // Capture the parent element and its size synchronously on mousedown\n const parentEl = e.currentTarget.parentElement;\n const parentSize = parentEl\n ? (isRow ? parentEl.clientWidth : parentEl.clientHeight)\n : (isRow ? 1000 : 800);\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const currentOffset = isRow ? moveEvent.clientX : moveEvent.clientY;\n const delta = currentOffset - startOffset;\n\n const deltaPercentage = delta / parentSize;\n\n const newSizes = [...startSizes];\n newSizes[idx] += deltaPercentage;\n newSizes[idx + 1] -= deltaPercentage;\n\n // Restrict range bounds\n if (newSizes[idx] > 0.1 && newSizes[idx + 1] > 0.1) {\n updateSplitSizes(path, newSizes);\n }\n };\n\n const handleMouseUp = () => {\n resizerEl.classList.remove('active');\n document.body.classList.remove('resizing-active', 'resizing-row-active', 'resizing-col-active');\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n };\n\n return (\n <div\n style={{ display: 'flex', flexDirection: isRow ? 'row' : 'column', width: '100%', height: '100%', overflow: 'hidden', position: 'relative' }}\n >\n {node.children.map((child, idx) => {\n const size = node.sizes[idx] * 100;\n return (\n <React.Fragment key={idx}>\n <div style={{ flexGrow: node.sizes[idx], flexBasis: `${size}%`, overflow: 'hidden', position: 'relative' }}>\n <WorkspaceGrid node={child} path={[...path, idx]} onTabRightClick={onTabRightClick} activeDropZone={activeDropZone} onHoverDropZone={onHoverDropZone} onTabDragStart={onTabDragStart} hoveredTab={hoveredTab} onTabHover={onTabHover} defaultPanelIcon={defaultPanelIcon} onRequestClosePanel={onRequestClosePanel} />\n </div>\n {idx < node.children.length - 1 && (\n <div\n onMouseDown={(e) => handleResizerMouseDown(idx, e)}\n style={{\n cursor: isRow ? 'col-resize' : 'row-resize',\n width: isRow ? '1px' : '100%',\n height: isRow ? '100%' : '1px',\n zIndex: 20,\n }}\n className=\"resizer-bar\"\n />\n )}\n </React.Fragment>\n );\n })}\n </div>\n );\n};\n\ninterface LeafGroupProps {\n leaf: LayoutLeafNode;\n onTabRightClick: (id: string, e: React.MouseEvent) => void;\n activeDropZone: { leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null;\n onHoverDropZone: (leafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center' | null) => void;\n onTabDragStart: (id: string, e: React.MouseEvent) => void;\n hoveredTab: { leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null;\n onTabHover: (leafId: string, panelId: string, index: number, side: 'left' | 'right' | null) => void;\n defaultPanelIcon?: React.ReactNode;\n onRequestClosePanel: (id: string) => void;\n}\n\nconst LeafGroup: React.FC<LeafGroupProps> = ({ leaf, onTabRightClick, activeDropZone, onHoverDropZone, onTabDragStart, hoveredTab, onTabHover, defaultPanelIcon, onRequestClosePanel }) => {\n const state = useWindowManagerState();\n const registry = useRegistry();\n const { openPanel, closeLeafGroup, setActivePanel } = useWindowManagerActions();\n const formatMessage = useFormatMessage();\n const messages = usePredefinedMessages();\n const { windowClass, windowBodyClass } = useStyleClasses();\n\n const selectTab = (id: string) => {\n openPanel(id, state.panels[id].component);\n setActivePanel(id);\n };\n\n return (\n <div\n data-active-panel-id={leaf.activePanelId || ''}\n className={`workspace-panel ${windowClass ?? ''}`}\n style={{ overflow: 'hidden', position: 'relative' }}\n >\n {/* Tab Headers */}\n <div className=\"workspace-tab-bar\" style={{ minHeight: '38px' }}>\n <div\n className=\"tab-headers-container\"\n style={{ scrollbarWidth: 'none' }}\n onMouseMove={(e) => {\n if (state.draggedPanelId && e.target === e.currentTarget) {\n onTabHover(leaf.id, 'EMPTY', leaf.panels.length, 'right');\n }\n }}\n onMouseLeave={(e) => {\n if (state.draggedPanelId && e.target === e.currentTarget) {\n onTabHover(leaf.id, '', -1, null);\n }\n }}\n >\n {leaf.panels.map((id, idx) => {\n const panel = state.panels[id];\n if (!panel) return null;\n const isSelected = leaf.activePanelId === id;\n const isGloballyActive = state.activePanelId === id;\n\n const registryEntry = registry.get(panel.component);\n const options = registryEntry?.defaultOptions;\n\n const isHovered = hoveredTab && hoveredTab.leafId === leaf.id && hoveredTab.panelId === id;\n const isLast = idx === leaf.panels.length - 1;\n const isHoveredEmpty = hoveredTab && hoveredTab.leafId === leaf.id && hoveredTab.panelId === 'EMPTY' && isLast;\n const sideClass = isHovered\n ? (hoveredTab.side === 'left' ? 'drag-hover-left' : 'drag-hover-right')\n : (isHoveredEmpty ? 'drag-hover-right' : '');\n\n const tabFocusClass = isSelected\n ? (isGloballyActive ? 'active workspace-tab-active-focused' : 'active workspace-tab-active-unfocused')\n : 'workspace-tab-inactive';\n\n return (\n <div\n key={id}\n onClick={() => selectTab(id)}\n onMouseDown={(e) => {\n if (options?.canDrag !== false) {\n onTabDragStart(id, e);\n }\n }}\n onContextMenu={(e) => onTabRightClick(id, e)}\n onMouseMove={(e) => {\n if (state.draggedPanelId) {\n const rect = e.currentTarget.getBoundingClientRect();\n const relativeX = e.clientX - rect.left;\n const side = relativeX < rect.width / 2 ? 'left' : 'right';\n onTabHover(leaf.id, id, idx, side);\n }\n }}\n onMouseLeave={() => {\n if (state.draggedPanelId) {\n onTabHover(leaf.id, '', -1, null);\n }\n }}\n className={`workspace-tab ${tabFocusClass} ${sideClass}`}\n style={{ cursor: options?.canDrag === false ? 'default' : 'pointer' }}\n >\n <span className=\"text-truncate\" style={{ maxWidth: '120px', display: 'flex', alignItems: 'center' }}>\n <span className=\"workspace-tab-icon\">{options?.icon || defaultPanelIcon || DefaultGridIcon}</span>\n <span>\n {formatLabel(panel.title, formatMessage)}\n {panel.dirty ? ' *' : ''}\n </span>\n </span>\n {options?.renderHeaderActions && (\n <span\n className=\"tab-header-actions\"\n onClick={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n >\n {options.renderHeaderActions(id)}\n </span>\n )}\n {options?.canClose !== false && (\n <span\n onClick={(e) => {\n e.stopPropagation();\n onRequestClosePanel(id);\n }}\n title={formatLabel(messages.closeTab, formatMessage)}\n className=\"close-tab-x\"\n style={{ width: '18px', height: '18px', ...(options?.renderHeaderActions ? {} : { marginInlineStart: 'auto' }) }}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n )}\n </div>\n );\n })}\n </div>\n\n {/* Empty group close button — only visible when keepOnEmpty keeps the group alive */}\n {leaf.panels.length === 0 && leaf.keepOnEmpty && leaf.canClose !== false && (\n <span\n onClick={() => closeLeafGroup(leaf.id)}\n className=\"close-tab-x header-close-empty-group\"\n style={{ width: '18px', height: '18px', cursor: 'pointer' }}\n title={formatLabel(messages.closeEmptyGroup, formatMessage)}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n )}\n </div>\n\n {/* Tab Content Display Area */}\n <div className={`dw-panel-body ${windowBodyClass ?? ''}`} style={{ position: 'relative', overflow: 'hidden' }}>\n {leaf.activePanelId && state.panels[leaf.activePanelId] ? (\n <PreservedDOMWrapper key={leaf.activePanelId} panelId={leaf.activePanelId} />\n ) : (\n <div className=\"empty-leaf-placeholder\">\n <span>Empty Workspace Section</span>\n </div>\n )}\n\n {/* Drag overlay targets cross */}\n {state.draggedPanelId !== null && (\n <div className=\"dock-drop-zone-overlay\">\n <div className=\"dock-target-cross\">\n {/* Top target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'top')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-top\"\n >\n ▲\n </div>\n {/* Bottom target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'bottom')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-bottom\"\n >\n ▼\n </div>\n {/* Left target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'left')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-left\"\n >\n ◀\n </div>\n {/* Right target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'right')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-right\"\n >\n ▶\n </div>\n {/* Center target */}\n <div\n onMouseEnter={() => onHoverDropZone(leaf.id, 'center')}\n onMouseLeave={() => onHoverDropZone(leaf.id, null)}\n className=\"dock-target-box dock-target-center\"\n >\n ▣\n </div>\n </div>\n </div>\n )}\n\n {/* Visual preview highlight overlay */}\n {state.draggedPanelId !== null && activeDropZone !== null && activeDropZone.leafId === leaf.id && (\n <div\n className=\"dock-preview-highlight\"\n style={{\n left: activeDropZone.position === 'right' ? '50%' : '0',\n top: activeDropZone.position === 'bottom' ? '50%' : '0',\n width: (activeDropZone.position === 'left' || activeDropZone.position === 'right') ? '50%' : '100%',\n height: (activeDropZone.position === 'top' || activeDropZone.position === 'bottom') ? '50%' : '100%',\n }}\n />\n )}\n </div>\n </div>\n );\n};\n\n\n// ==========================================\n// 5. WindowManager (Main Render Component)\n// ==========================================\n\nexport interface WindowManagerProps {\n skin?: string;\n defaultPanelIcon?: React.ReactNode;\n}\n\nexport const WindowManager: React.FC<WindowManagerProps> = ({ skin = 'vscode', defaultPanelIcon }) => {\n const state = useWindowManagerState();\n const registry = useRegistry();\n const { restorePanel, minimizePanel, requestClosePanel, maximizePanel, updateFloatingPosition, bringToFront, floatPanel, setDraggedPanelId, dockPanelToGroup, movePanelOrder, dockPanelToWorkspaceEdge, setActivePanel, setDirection } = useWindowManagerActions();\n const { openModal } = usePanelActions();\n const formatMessage = useFormatMessage();\n const messages = usePredefinedMessages();\n\n const handleRequestClose = React.useCallback((id: string) => {\n const panel = state.panels[id];\n requestClosePanel(id, {\n onConfirm: (customOpts) => new Promise<boolean>((resolve) => {\n const opts = customOpts || panel?.dirtyOptions;\n const baseTitle = panel ? formatLabel(panel.title, formatMessage) : 'Panel';\n openModal(\n ConfirmationForm,\n {\n title: opts?.title || messages.unsavedChangesTitle,\n message: opts?.message || {\n id: messages.unsavedChangesMessage.id,\n defaultMessage: messages.unsavedChangesMessage.defaultMessage,\n values: { title: baseTitle }\n },\n alert: opts?.alert,\n alertType: opts?.alertType || 'danger',\n useYesNoTitles: true,\n onOK: () => resolve(true),\n onCancel: () => resolve(false),\n },\n { size: 'small' }\n );\n })\n });\n }, [requestClosePanel, state.panels, formatMessage, openModal, messages]);\n\n const { windowClass, windowBodyClass } = useStyleClasses();\n const taskbarRef = useRef<HTMLDivElement | null>(null);\n const contextMenuRef = useRef<JsonContextMenuRef>(null);\n\n const [hoveredMinimized, setHoveredMinimized] = useState<{ id: string; rect: DOMRect; title: string | any; component: string } | null>(null);\n const minimizedTooltipTimeoutRef = useRef<number>(null);\n const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);\n\n useEffect(() => {\n return () => {\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n if (hoveredMinimized) {\n const isStillMinimized = state.minimized.some(m => m.id === hoveredMinimized.id);\n if (!isStillMinimized) {\n setHoveredMinimized(null);\n }\n }\n }, [state.minimized, hoveredMinimized]);\n\n const [activeDropZone, setActiveDropZone] = useState<{ leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null>(null);\n const activeDropZoneRef = useRef<{ leafId: string; position: 'left' | 'right' | 'top' | 'bottom' | 'center' } | null>(null);\n const [dragPos, setDragPos] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n\n const [activeEdgeDrop, setActiveEdgeDropState] = useState<'left' | 'right' | 'top' | 'bottom' | null>(null);\n const activeEdgeDropRef = useRef<'left' | 'right' | 'top' | 'bottom' | null>(null);\n const setActiveEdgeDrop = (val: 'left' | 'right' | 'top' | 'bottom' | null) => {\n setActiveEdgeDropState(val);\n activeEdgeDropRef.current = val;\n };\n\n const [hoveredTab, setHoveredTab] = useState<{ leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null>(null);\n const hoveredTabRef = useRef<{ leafId: string; panelId: string; index: number; side: 'left' | 'right' } | null>(null);\n\n const handleTabHover = (leafId: string, panelId: string, index: number, side: 'left' | 'right' | null) => {\n const val = side ? { leafId, panelId, index, side } : null;\n setHoveredTab(val);\n hoveredTabRef.current = val;\n };\n\n const handleHoverDropZone = (leafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center' | null) => {\n const val = position ? { leafId, position } : null;\n setActiveDropZone(val);\n activeDropZoneRef.current = val;\n };\n\n const handleTabDragStart = (id: string, e: React.MouseEvent) => {\n // Only handle left click drags\n if (e.button !== 0) return;\n\n const startX = e.clientX;\n const startY = e.clientY;\n let dragStarted = false;\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const dx = moveEvent.clientX - startX;\n const dy = moveEvent.clientY - startY;\n\n // Threshold trigger (5px)\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n\n if (dragStarted) {\n setDragPos({ x: moveEvent.clientX, y: moveEvent.clientY });\n }\n };\n\n const handleMouseUp = (moveEvent: MouseEvent) => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUpWrapper);\n\n if (dragStarted) {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n\n if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, edgeDrop);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') {\n targetIndex += 1;\n }\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, dropZone.position);\n } else {\n // Float at dropped coordinates\n floatPanel(id, {\n x: moveEvent.clientX - 150,\n y: moveEvent.clientY - 15,\n width: 450,\n height: 350\n });\n }\n setDraggedPanelId(null);\n setActiveDropZone(null);\n activeDropZoneRef.current = null;\n setHoveredTab(null);\n hoveredTabRef.current = null;\n setActiveEdgeDrop(null);\n }\n };\n\n const handleMouseUpWrapper = (moveEvent: MouseEvent) => {\n handleMouseUp(moveEvent);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUpWrapper);\n };\n\n const handleTabRightClick = (id: string, e: React.MouseEvent) => {\n e.preventDefault();\n const panel = state.panels[id];\n if (!panel) return;\n const registryEntry = registry.get(panel.component);\n const options = registryEntry?.defaultOptions;\n\n const items = [];\n if (options?.canDrag !== false) {\n items.push({\n label: formatLabel(messages.floatWindow, formatMessage),\n action: () => floatPanel(id)\n });\n }\n if (options?.canMinimize !== false) {\n items.push({\n label: formatLabel(messages.minimizePanel, formatMessage),\n action: () => minimizePanel(id)\n });\n }\n if (items.length > 0 && options?.canClose !== false) {\n items.push({ separator: true as const });\n }\n if (options?.canClose !== false) {\n items.push({\n label: formatLabel(messages.closeTab, formatMessage),\n action: () => handleRequestClose(id)\n });\n }\n\n if (items.length === 0) return;\n\n contextMenuRef.current?.show({\n event: e,\n contextMenu: { items }\n });\n };\n\n const handleMinimizedRightClick = (id: string, e: React.MouseEvent) => {\n e.preventDefault();\n setHoveredMinimized(null);\n contextMenuRef.current?.show({\n event: e,\n contextMenu: {\n items: [\n {\n label: formatLabel(messages.restorePanel, formatMessage),\n action: () => restorePanel(id)\n },\n {\n label: formatLabel(messages.maximizePanel, formatMessage),\n action: () => maximizePanel(id)\n },\n { separator: true },\n {\n label: formatLabel(messages.closePanel, formatMessage),\n action: () => handleRequestClose(id)\n }\n ]\n }\n });\n };\n\n // Clean up domCache for panels that are no longer in state.panels\n useEffect(() => {\n const keys = Object.keys(state.panels);\n for (const cachedId of Array.from(domCache.keys())) {\n if (!keys.includes(cachedId)) {\n domCache.delete(cachedId);\n }\n }\n }, [state.panels]);\n\n // Safe window blur handler to cancel sticky dragging states when iframe/webview loses focus\n useEffect(() => {\n const handleWindowBlur = () => {\n if (state.draggedPanelId !== null) {\n setDraggedPanelId(null);\n setActiveDropZone(null);\n setHoveredTab(null);\n }\n };\n window.addEventListener('blur', handleWindowBlur);\n return () => {\n window.removeEventListener('blur', handleWindowBlur);\n };\n }, [state.draggedPanelId]);\n\n const workspaceRef = useRef<HTMLDivElement | null>(null);\n const [workspaceSize, setWorkspaceSize] = useState({ width: 1024, height: 768 });\n\n // Dynamically observe the workspace container bounds (accounts for sidebar expanding/collapsing and taskbar showing/hiding)\n useEffect(() => {\n const el = workspaceRef.current;\n if (!el) return;\n\n const observer = new ResizeObserver((entries) => {\n if (!entries || entries.length === 0) return;\n const rect = entries[0].contentRect;\n setWorkspaceSize({\n width: Math.max(100, rect.width),\n height: Math.max(100, rect.height)\n });\n });\n\n observer.observe(el);\n return () => {\n observer.disconnect();\n };\n }, []);\n\n // Dynamically observe document/container direction changes\n useEffect(() => {\n const el = workspaceRef.current;\n if (!el) return;\n\n const updateDir = () => {\n const isRtl = isElementRtl(el);\n setDirection(isRtl ? 'rtl' : 'ltr');\n };\n\n updateDir();\n\n const observer = new MutationObserver(updateDir);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] });\n observer.observe(document.body, { attributes: true, attributeFilter: ['dir'] });\n\n const closestDir = el.closest('[dir]');\n if (closestDir && closestDir !== document.documentElement && closestDir !== document.body) {\n observer.observe(closestDir, { attributes: true, attributeFilter: ['dir'] });\n }\n\n return () => {\n observer.disconnect();\n };\n }, [setDirection]);\n\n // Sync / Realignment Effect when actual workspace size changes\n useEffect(() => {\n const viewW = workspaceSize.width;\n const viewH = workspaceSize.height;\n\n state.floating.forEach(w => {\n const winW = typeof w.width === 'string' ? parseFloat(w.width) : w.width;\n const winH = typeof w.height === 'string' ? parseFloat(w.height) : w.height;\n const winX = typeof w.x === 'string' ? parseFloat(w.x) : w.x;\n const winY = typeof w.y === 'string' ? parseFloat(w.y) : w.y;\n\n let newWidth = winW;\n let newHeight = winH;\n let newX = winX;\n let newY = winY;\n let changed = false;\n\n // Clamp window size if it exceeds the new workspace size\n if (newWidth > viewW) {\n newWidth = Math.max(200, viewW - 20);\n changed = true;\n }\n if (newHeight > viewH) {\n newHeight = Math.max(150, viewH - 40);\n changed = true;\n }\n\n const GAP = 10;\n\n // Align sticky borders\n if (w.stickyRight) {\n newX = viewW - newWidth - GAP;\n changed = true;\n } else {\n // Bounding clamp for non-sticky windows to prevent falling off-screen\n const maxX = viewW - 100; // Keep at least 100px of titlebar visible\n if (newX > maxX) {\n newX = Math.max(0, maxX);\n changed = true;\n }\n }\n\n if (w.stickyBottom) {\n newY = viewH - newHeight - GAP;\n changed = true;\n } else {\n const maxY = viewH - 40; // Keep titlebar clickable\n if (newY > maxY) {\n newY = Math.max(0, maxY);\n changed = true;\n }\n }\n\n if (changed) {\n updateFloatingPosition(w.id, {\n x: newX,\n y: newY,\n width: newWidth,\n height: newHeight\n });\n }\n });\n }, [workspaceSize, state.floating, updateFloatingPosition]);\n\n // Global Window Focus Event Delegation (Left-click anywhere inside a window or grid panel focuses it)\n useEffect(() => {\n const handleMouseDownGlobal = (e: MouseEvent) => {\n // Only handle left clicks (button === 0)\n if (e.button !== 0) return;\n\n const target = e.target as HTMLElement | null;\n if (!target) return;\n\n // 1. Check if click is inside a floating window\n const windowEl = target.closest('.floating-window') as HTMLElement | null;\n if (windowEl) {\n const winId = windowEl.getAttribute('data-window-id');\n if (winId) {\n setActivePanel(winId);\n bringToFront(winId);\n }\n return;\n }\n\n // 2. Check if click is inside a grid split pane\n const panelEl = target.closest('.workspace-panel') as HTMLElement | null;\n if (panelEl) {\n const panelId = panelEl.getAttribute('data-active-panel-id');\n if (panelId) {\n setActivePanel(panelId);\n }\n }\n };\n\n document.addEventListener('mousedown', handleMouseDownGlobal);\n return () => {\n document.removeEventListener('mousedown', handleMouseDownGlobal);\n };\n }, [bringToFront, setActivePanel]);\n\n // Floating Window dragging handler\n const startDrag = (id: string, e: React.MouseEvent) => {\n const floatingWin = state.floating.find(w => w.id === id);\n if (!floatingWin || floatingWin.maximized) return;\n bringToFront(id);\n\n const startX = e.clientX;\n const startY = e.clientY;\n const titlebarEl = e.currentTarget as HTMLDivElement;\n const windowEl = titlebarEl.closest('.floating-window') as HTMLDivElement | null;\n const startPosX = windowEl ? windowEl.offsetLeft : 0;\n const startPosY = windowEl ? windowEl.offsetTop : 0;\n let dragStarted = false;\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const dx = moveEvent.clientX - startX;\n const dy = moveEvent.clientY - startY;\n\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n\n if (dragStarted) {\n const newX = startPosX + dx;\n const newY = startPosY + dy;\n\n // Dragging clears all sticky anchoring\n updateFloatingPosition(id, {\n x: newX,\n y: newY,\n stickyRight: false,\n stickyBottom: false\n });\n }\n };\n\n const handleMouseUp = () => {\n if (dragStarted) {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n\n if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, edgeDrop);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') {\n targetIndex += 1;\n }\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, dropZone.position);\n }\n setDraggedPanelId(null);\n setActiveDropZone(null);\n activeDropZoneRef.current = null;\n setHoveredTab(null);\n hoveredTabRef.current = null;\n setActiveEdgeDrop(null);\n }\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n };\n\n // Floating Window resizing handler\n const startResize = (id: string, e: React.MouseEvent) => {\n e.stopPropagation();\n const floatingWin = state.floating.find(w => w.id === id);\n if (!floatingWin || floatingWin.maximized) return;\n bringToFront(id);\n\n const startX = e.clientX;\n const startY = e.clientY;\n const handleEl = e.currentTarget as HTMLDivElement;\n const windowEl = handleEl.closest('.floating-window') as HTMLDivElement | null;\n const startW = windowEl ? windowEl.offsetWidth : 400;\n const startH = windowEl ? windowEl.offsetHeight : 300;\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const dw = moveEvent.clientX - startX;\n const dh = moveEvent.clientY - startY;\n\n let newWidth = Math.max(200, startW + dw);\n let newHeight = Math.max(150, startH + dh);\n\n let newX = floatingWin.x;\n let newY = floatingWin.y;\n\n const viewW = workspaceSize.width;\n const viewH = workspaceSize.height;\n\n const parsedX = typeof floatingWin.x === 'string' ? parseFloat(floatingWin.x) : floatingWin.x;\n const parsedY = typeof floatingWin.y === 'string' ? parseFloat(floatingWin.y) : floatingWin.y;\n const parsedW = typeof floatingWin.width === 'string' ? parseFloat(floatingWin.width) : floatingWin.width;\n const parsedH = typeof floatingWin.height === 'string' ? parseFloat(floatingWin.height) : floatingWin.height;\n\n const isRightSnapped = Math.abs(parsedX + parsedW - viewW) < 4;\n const isBottomSnapped = Math.abs(parsedY + parsedH - viewH) < 4;\n\n if (isRightSnapped) {\n newX = viewW - newWidth;\n if (newX < 0) {\n newX = 0;\n newWidth = viewW;\n }\n }\n\n if (isBottomSnapped) {\n newY = viewH - newHeight;\n if (newY < 0) {\n newY = 0;\n newHeight = viewH;\n }\n }\n\n updateFloatingPosition(id, {\n x: newX,\n y: newY,\n width: newWidth,\n height: newHeight,\n stickyRight: isRightSnapped,\n stickyBottom: isBottomSnapped\n });\n };\n\n const handleMouseUp = () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n };\n\n // horizontal scroll for minimized taskbar\n const scrollTaskbar = (direction: 'left' | 'right') => {\n if (taskbarRef.current) {\n const amount = direction === 'left' ? -150 : 150;\n taskbarRef.current.scrollBy({ left: amount, behavior: 'smooth' });\n }\n };\n\n // Fetch the active color-scheme from documentElement to make sure nested variables resolve correctly\n const [currentColorScheme, setCurrentColorScheme] = useState<'dark' | 'light'>('dark');\n useEffect(() => {\n const updateThemeState = () => {\n const activeTheme = document.documentElement.getAttribute('data-color-scheme') === 'light' ? 'light' : 'dark';\n setCurrentColorScheme(activeTheme);\n };\n updateThemeState();\n const obs = new MutationObserver(updateThemeState);\n obs.observe(document.documentElement, { attributes: true, attributeFilter: ['data-color-scheme'] });\n return () => obs.disconnect();\n }, []);\n\n return (\n <div\n data-workspace-skin={skin}\n data-color-scheme={currentColorScheme}\n style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%', overflow: 'hidden', userSelect: 'none' }}\n dir={state.dir}\n >\n\n {/* 1. Main Workspace Viewport (Grids & Floating Panels) */}\n <div\n ref={workspaceRef}\n className={state.draggedPanelId ? 'dragging-active' : undefined}\n style={{ flexGrow: 1, width: '100%', position: 'relative', overflow: 'hidden' }}\n >\n {/* Workspace outer edge drop zone targets */}\n {state.draggedPanelId !== null && (\n <>\n <div\n className=\"workspace-edge-trigger edge-trigger-left\"\n onMouseEnter={() => setActiveEdgeDrop('left')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n className=\"workspace-edge-trigger edge-trigger-right\"\n onMouseEnter={() => setActiveEdgeDrop('right')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n className=\"workspace-edge-trigger edge-trigger-top\"\n onMouseEnter={() => setActiveEdgeDrop('top')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n className=\"workspace-edge-trigger edge-trigger-bottom\"\n onMouseEnter={() => setActiveEdgeDrop('bottom')}\n onMouseLeave={() => setActiveEdgeDrop(null)}\n />\n </>\n )}\n\n {/* Edge drop visual preview overlay */}\n {state.draggedPanelId !== null && activeEdgeDrop !== null && (\n <div className={`workspace-edge-preview edge-preview-${activeEdgeDrop}`} />\n )}\n\n {/* 1.1 Viewport Split Grid Layout */}\n <div style={{ width: '100%', height: '100%', overflow: 'hidden', position: 'relative' }}>\n {state.gridRoot ? (\n <WorkspaceGrid\n node={state.gridRoot}\n path={[]}\n onTabRightClick={handleTabRightClick}\n activeDropZone={activeDropZone}\n onHoverDropZone={handleHoverDropZone}\n onTabDragStart={handleTabDragStart}\n hoveredTab={hoveredTab}\n onTabHover={handleTabHover}\n defaultPanelIcon={defaultPanelIcon}\n onRequestClosePanel={handleRequestClose}\n />\n ) : (\n <div className=\"empty-workspace-grid\">\n Grid Empty\n </div>\n )}\n </div>\n\n {(() => {\n return state.floating.map(w => {\n const panel = state.panels[w.id];\n if (!panel) return null;\n\n const isMaximized = w.maximized;\n const isDragged = state.draggedPanelId === w.id;\n const isFocused = state.activePanelId === w.id;\n\n const registryEntry = registry.get(panel.component);\n const options = registryEntry?.defaultOptions;\n\n return (\n <div\n key={w.id}\n data-window-id={w.id}\n dir={state.dir}\n onMouseDownCapture={() => {\n setActivePanel(w.id);\n bringToFront(w.id);\n }}\n className={`floating-window ${isMaximized ? 'maximized' : ''} ${isFocused ? 'v2-window-focused' : ''} ${windowClass ?? ''}`}\n style={{\n position: 'absolute',\n left: isMaximized ? 0 : (typeof w.x === 'number' ? `${w.x}px` : w.x),\n top: isMaximized ? 0 : (typeof w.y === 'number' ? `${w.y}px` : w.y),\n width: isMaximized ? '100%' : (typeof w.width === 'number' ? `${w.width}px` : w.width),\n height: isMaximized ? '100%' : (typeof w.height === 'number' ? `${w.height}px` : w.height),\n zIndex: w.z,\n pointerEvents: isDragged ? 'none' : 'auto',\n }}\n >\n {/* Title Bar */}\n <div\n onDoubleClick={() => maximizePanel(w.id)}\n onMouseDown={(e) => {\n if (options?.canDrag !== false) {\n startDrag(w.id, e);\n }\n }}\n className=\"floating-window-titlebar cursor-move\"\n style={{ cursor: isMaximized || options?.canDrag === false ? 'default' : 'move' }}\n >\n <span className=\"floating-window-title\">\n <span className=\"window-title-icon\">{options?.icon || defaultPanelIcon || DefaultGridIcon}</span>\n <span>\n {formatLabel(panel.title, formatMessage)}\n {panel.dirty ? ' *' : ''}\n </span>\n </span>\n <div className=\"fw-titlebar-actions\" style={{ gap: 'var(--header-button-gap, 4px)' }} onMouseDown={(e) => e.stopPropagation()}>\n {options?.renderHeaderActions && (\n <div className=\"window-header-actions\">\n {options.renderHeaderActions(w.id)}\n </div>\n )}\n {options?.canDrag !== false && (\n <button\n type=\"button\"\n title={formatLabel(messages.windowAnchoringOptions, formatMessage)}\n onClick={(e) => {\n const isRight = !!w.stickyRight;\n const isBottom = !!w.stickyBottom;\n contextMenuRef.current?.show({\n event: e,\n contextMenu: {\n items: [\n {\n label: formatLabel(messages.anchorToRightEdge, formatMessage),\n checkbox: {\n active: true,\n enabled: true,\n value: isRight\n },\n action: () => {\n const viewW = workspaceSize.width;\n const winW = typeof w.width === 'string' ? parseFloat(w.width) : w.width;\n const GAP = 10;\n if (!isRight) {\n updateFloatingPosition(w.id, { x: viewW - winW - GAP, stickyRight: true });\n } else {\n updateFloatingPosition(w.id, { stickyRight: false });\n }\n }\n },\n {\n label: formatLabel(messages.anchorToBottomEdge, formatMessage),\n checkbox: {\n active: true,\n enabled: true,\n value: isBottom\n },\n action: () => {\n const viewH = workspaceSize.height;\n const winH = typeof w.height === 'string' ? parseFloat(w.height) : w.height;\n const GAP = 10;\n if (!isBottom) {\n updateFloatingPosition(w.id, { y: viewH - winH - GAP, stickyBottom: true });\n } else {\n updateFloatingPosition(w.id, { stickyBottom: false });\n }\n }\n }\n ]\n }\n });\n }}\n className=\"custom-tab-btn btn-anchor-tab\"\n >\n <svg className={`anchor-icon ${(w.stickyRight && w.stickyBottom) ? 'anchor-sticky-both' : w.stickyRight ? 'anchor-sticky-right' : w.stickyBottom ? 'anchor-sticky-bottom' : ''}`} width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <circle cx=\"12\" cy=\"5\" r=\"2\" />\n <path d=\"M12 7v7m0 0a4 4 0 0 1-4-4M12 14a4 4 0 0 0 4-4M5 18h14\" />\n </svg>\n </button>\n )}\n <button\n type=\"button\"\n title={isMaximized\n ? formatLabel(messages.restoreSize, formatMessage)\n : formatLabel(messages.maximize, formatMessage)}\n onClick={() => maximizePanel(w.id)}\n className=\"custom-tab-btn btn-maximize-tab\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1.5\"/>\n </svg>\n </button>\n {options?.canMinimize !== false && (\n <button\n type=\"button\"\n title={formatLabel(messages.minimize, formatMessage)}\n onClick={() => minimizePanel(w.id)}\n className=\"custom-tab-btn btn-minimize-tab\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\">\n <path d=\"M5 12h14\"/>\n </svg>\n </button>\n )}\n {options?.canClose !== false && (\n <button\n type=\"button\"\n title={formatLabel(messages.close, formatMessage)}\n onClick={() => handleRequestClose(w.id)}\n className=\"custom-tab-btn btn-close-tab\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {/* Window Content */}\n <div className={windowBodyClass ?? undefined} style={{ flexGrow: 1, width: '100%', overflow: 'hidden', position: 'relative', isolation: 'isolate' }}>\n <PreservedDOMWrapper key={w.id} panelId={w.id} />\n </div>\n\n {/* Resize Handle */}\n {!isMaximized && (\n <div\n onMouseDown={(e) => startResize(w.id, e)}\n style={{\n position: 'absolute',\n right: 0,\n bottom: 0,\n width: '14px',\n height: '14px',\n cursor: 'se-resize',\n zIndex: 30,\n background: 'linear-gradient(135deg, transparent 50%, rgba(255,255,255,0.2) 50%)'\n }}\n />\n )}\n </div>\n );\n });\n })()}\n </div>\n\n {/* 2. macOS / Windows 11-style Taskbar Sibling Footer (Flex-shrinked at bottom) */}\n {state.minimized.length > 0 && (\n <div className=\"taskbar-footer-container\" style={{ height: '48px', zIndex: 100 }}>\n <button\n type=\"button\"\n onClick={() => scrollTaskbar('left')}\n className=\"taskbar-nav-btn\"\n style={{ display: state.minimized.length > 4 ? 'block' : 'none' }}\n >\n ◀\n </button>\n\n <div\n ref={taskbarRef}\n className=\"taskbar-items-container\"\n style={{ scrollSnapType: 'x mandatory' }}\n >\n {state.minimized.map(m => {\n const regEntry = registry.get(m.component);\n const icon = regEntry?.defaultOptions?.icon || defaultPanelIcon || DefaultGridIcon;\n\n return (\n <div\n key={m.id}\n onClick={() => {\n setHoveredMinimized(null);\n restorePanel(m.id);\n }}\n onContextMenu={(e) => handleMinimizedRightClick(m.id, e)}\n onMouseEnter={(e) => {\n if (isContextMenuOpen) return;\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n const rect = e.currentTarget.getBoundingClientRect();\n const isInside = (\n e.clientX >= rect.left &&\n e.clientX <= rect.right &&\n e.clientY >= rect.top &&\n e.clientY <= rect.bottom\n );\n if (!isInside) return;\n setHoveredMinimized({ id: m.id, rect, title: m.title, component: m.component });\n }}\n onMouseLeave={() => {\n minimizedTooltipTimeoutRef.current = setTimeout(() => {\n setHoveredMinimized(null);\n }, 150);\n }}\n className=\"taskbar-glassmorphic-item\"\n style={{\n backdropFilter: 'blur(6px)',\n transition: 'all 0.2s',\n cursor: 'pointer',\n scrollSnapAlign: 'start',\n width: '38px',\n height: '38px',\n position: 'relative',\n padding: 0\n }}\n >\n <span className=\"taskbar-item-icon\">\n {icon}\n </span>\n </div>\n );\n })}\n </div>\n\n {hoveredMinimized && createPortal(\n <div\n className=\"taskbar-item-tooltip\"\n dir={state.dir}\n style={{\n position: 'fixed',\n left: `${hoveredMinimized.rect.left + hoveredMinimized.rect.width / 2}px`,\n top: `${hoveredMinimized.rect.top - 8}px`,\n transform: 'translateX(-50%) translateY(-100%)',\n opacity: 1,\n pointerEvents: 'auto',\n zIndex: 999999\n }}\n onMouseEnter={() => {\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n }}\n onMouseLeave={() => {\n setHoveredMinimized(null);\n }}\n onClick={() => {\n restorePanel(hoveredMinimized.id);\n setHoveredMinimized(null);\n }}\n >\n <div className=\"tooltip-header-row\">\n <span className=\"tooltip-title-text text-truncate\" style={{ maxWidth: '140px' }}>\n {formatLabel(hoveredMinimized.title, formatMessage)}\n {state.panels[hoveredMinimized.id]?.dirty ? ' *' : ''}\n </span>\n <span\n onClick={(e) => {\n e.stopPropagation();\n handleRequestClose(hoveredMinimized.id);\n setHoveredMinimized(null);\n }}\n title={formatLabel(messages.closePanel, formatMessage)}\n className=\"tooltip-close-x\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n </div>\n <PreviewDOMWrapper panelId={hoveredMinimized.id} />\n </div>,\n document.body\n )}\n\n <button\n type=\"button\"\n onClick={() => scrollTaskbar('right')}\n className=\"taskbar-nav-btn\"\n style={{ display: state.minimized.length > 4 ? 'block' : 'none' }}\n >\n ▶\n </button>\n </div>\n )}\n\n {/* 3. Persistence Port: Portals rendering panels into off-screen elements */}\n {Object.keys(state.panels).map((id) => {\n const panel = state.panels[id];\n if (!panel) return null;\n const targetEl = getOrCreateDomCacheElement(id);\n return createPortal(\n <FormContainerProviderWrapper panelId={id}>\n <div style={{ width: '100%', height: '100%' }}>\n {renderPanelContent(id, panel.component, registry)}\n </div>\n </FormContainerProviderWrapper>,\n targetEl,\n id\n );\n })}\n\n {/* 4. Context Menu (replace-react-contexify JSON mode) */}\n <JsonContextMenu\n ref={contextMenuRef}\n id=\"workspace-context-menu\"\n theme=\"dark\"\n onShow={() => setIsContextMenuOpen(true)}\n onHide={() => setIsContextMenuOpen(false)}\n />\n\n {/* 5. Dragging Tab Ghost Representation */}\n {state.draggedPanelId !== null && !state.floating.some(w => w.id === state.draggedPanelId) && (\n <div\n className=\"drag-ghost-tab\"\n style={{\n left: dragPos.x + 12,\n top: dragPos.y + 12,\n zIndex: 100000,\n }}\n >\n 📄 {formatLabel(state.panels[state.draggedPanelId]?.title, formatMessage) || 'Tab'}\n </div>\n )}\n\n\n\n </div>\n );\n};\n\nexport default WindowManager;\n","import React, { createContext, useContext, useState, useRef, useMemo, useCallback, useEffect } from 'react';\nimport { PanelRegistry, type PanelRegistryClass } from './PanelRegistry';\nimport type { WorkspaceClient } from '../WorkspaceClient';\nimport { defaultPredefinedMessages } from './predefinedMessages';\nimport type { PredefinedMessageKey } from './predefinedMessages';\nexport type { PredefinedMessageKey } from './predefinedMessages';\nexport { defaultPredefinedMessages } from './predefinedMessages';\nimport type { DirtyStateOptions } from './dirtyOptions';\nexport type { DirtyStateOptions };\n\n/**\n * Structure representing localizable message descriptors used in context menus.\n */\nexport interface ContextMenuPredefinedMessage {\n /** Translation dictionary key. */\n id: string;\n /** Fallback label text if translation key is missing. */\n defaultMessage?: string;\n /** Values injected into the translated text placeholder. */\n values?: Record<string, string | number>;\n}\n\n/** Function type interface responsible for resolving localizable messages to flat strings. */\nexport type MessageFormatter = (msg: ContextMenuPredefinedMessage) => string;\n\n/** Orientation modifier indicating split directions. */\nexport type SplitOrientation = 'horizontal' | 'vertical';\n\n/**\n * Grid layout branch node containing nested splits and relative flex sizes.\n */\nexport interface LayoutGridNode {\n type: 'branch';\n /** Split orientation orientation indicator. */\n orientation: SplitOrientation;\n /** Children branches or leaf panels. */\n children: LayoutNode[];\n /** Relative percentage sizes of each child layout block. */\n sizes: number[];\n}\n\n/**\n * Grid layout leaf node containing active tab groups and panel arrays.\n */\nexport interface LayoutLeafNode {\n type: 'leaf';\n /** Unique leaf identifier. */\n id: string;\n /** Array of panel IDs mounted inside this group. */\n panels: string[];\n /** The currently active panel tab ID. */\n activePanelId: string | null;\n /** If false, close menu buttons are disabled for this group's tabs. */\n canClose?: boolean;\n /** When true, the group persists in the layout even after its last panel is closed. */\n keepOnEmpty?: boolean;\n}\n\n/** Union type representing either a branch or a leaf node in the layout grid. */\nexport type LayoutNode = LayoutGridNode | LayoutLeafNode;\n\n/**\n * Bounds and depth metadata for floated panel windows.\n */\nexport interface FloatingWindow {\n /** Unique ID of the floating window. */\n id: string;\n /** CSS left position offset (supports number/px or percentage strings). */\n x: number | string;\n /** CSS top position offset. */\n y: number | string;\n /** CSS width value. */\n width: number | string;\n /** CSS height value. */\n height: number | string;\n /** Rendering depth stack index layer. */\n z: number;\n /** True if the window is currently maximized to full workspace bounds. */\n maximized?: boolean;\n /** Sticky right flag. */\n stickyRight?: boolean;\n /** Sticky bottom flag. */\n stickyBottom?: boolean;\n}\n\n/**\n * Stores active runtime properties and status metadata for individual panel instances.\n */\nexport interface PanelInfo {\n /** Unique panel identifier. */\n id: string;\n /** Plain text label or localizable message descriptor. */\n title: string | ContextMenuPredefinedMessage;\n /** String matching the component registration ID in the {@link PanelRegistry}. */\n component: string;\n /** Current workspace placement mode. */\n state: 'docked' | 'floating' | 'minimized';\n /** Last state held before panel was minimized. */\n previousState?: 'docked' | 'floating';\n /** Saved position boundaries used when returning the panel to a floating state. */\n lastFloatingRect?: { x: number; y: number; width: number; height: number; stickyRight?: boolean; stickyBottom?: boolean };\n /** The leaf group ID this panel was docked in prior to being floated. */\n lastLeafId?: string;\n /** True if the panel contains unsaved user edits. */\n dirty?: boolean;\n /** Custom options applied to the automatic unsaved changes modal. */\n dirtyOptions?: DirtyStateOptions;\n}\n\n/**\n * Global window manager state tree representing grid nodes, windows, and panels.\n */\nexport interface WindowState {\n /** Root branch node representing the grid. */\n gridRoot: LayoutNode;\n /** Array of active floated windows. */\n floating: FloatingWindow[];\n /** Array of minimized panels waiting in the taskbar dock. */\n minimized: { id: string; title: string | ContextMenuPredefinedMessage; component: string }[];\n /** Map indexing panel metadata descriptors. */\n panels: Record<string, PanelInfo>;\n /** The ID of the panel tab currently being dragged. */\n draggedPanelId: string | null;\n /** The ID of the active/focused panel. */\n activePanelId: string | null;\n /** Current layout direction ('ltr' or 'rtl') */\n dir: 'ltr' | 'rtl';\n /** Convenient boolean flag indicating RTL direction */\n isRtl: boolean;\n}\n\n/**\n * Interface mapping layout actions, event bus handles, and serialization methods.\n */\nexport interface WindowActions {\n /** Instantiates a registered panel into the workspace. */\n openPanel: (id: string, component: string, options?: { title?: string | ContextMenuPredefinedMessage; initialTarget?: 'floating' | 'docked' | 'tabbed'; stickyRight?: boolean; stickyBottom?: boolean }) => void;\n /** Directly closes a panel by ID, bypassing close confirmation dialogs. */\n closePanel: (id: string) => void;\n /** Minimizes a panel to the bottom taskbar, saving its current layout positioning. */\n minimizePanel: (id: string) => void;\n /** Restores a minimized panel back to its previous position in the grid or as a float. */\n restorePanel: (id: string) => void;\n /** Detaches a docked panel, turning it into a floating resizable window. */\n floatPanel: (id: string, rect?: { x: number; y: number; width: number; height: number }) => void;\n /** Returns a floating window back to a docked grid tab group. */\n dockPanel: (id: string, targetLeafId?: string) => void;\n /** Maximizes a floating window to cover the entire layout screen boundaries. */\n maximizePanel: (id: string) => void;\n /** Resizes flex dimensions of children inside split layout rows/columns. */\n updateSplitSizes: (path: number[], sizes: number[]) => void;\n /** Updates bounds or positioning attributes on a floating window. */\n updateFloatingPosition: (id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'stickyRight' | 'stickyBottom'>>) => void;\n /** Pushes a floating window z-index layer to render on top of others. */\n bringToFront: (id: string) => void;\n /** Serializes the active grid node structures and panel targets to JSON. */\n saveLayout: () => string;\n /** Rebuilds the grid layouts and floating window placements from a JSON string. */\n loadLayout: (layoutJson: string) => void;\n /** Publishes an event to the global inter-panel message bus. */\n publish: (event: string, data: any) => void;\n /** Subscribes callback listeners to inter-panel event messages. */\n subscribe: (event: string, callback: (data: any) => void) => () => void;\n /** Stores reference to the active tab ID being dragged. */\n setDraggedPanelId: (id: string | null) => void;\n /** Splits an existing tab group to dock a dragged panel next to it. */\n dockPanelToGroup: (id: string, targetLeafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center') => void;\n /** Reorders tab indices inside a docked leaf group. */\n movePanelOrder: (panelId: string, targetLeafId: string, targetIndex: number) => void;\n /** Closes an empty split group. */\n closeLeafGroup: (leafId: string) => void;\n /** Binds a close intercept confirmation guard. */\n registerCloseGuard: (id: string, guard: () => boolean | Promise<boolean>) => void;\n /** Removes close confirmation guards. */\n unregisterCloseGuard: (id: string) => void;\n /** Set panel dirty state flag. */\n setPanelDirty: (id: string, dirty: boolean, options?: DirtyStateOptions) => void;\n /** Change title header. */\n updatePanelTitle: (id: string, title: string | ContextMenuPredefinedMessage) => void;\n /** Intercepts close panel requests, prompting warning dialogs if dirty. */\n requestClosePanel: (id: string, options?: { force?: boolean; onConfirm?: (opts?: DirtyStateOptions) => Promise<boolean> }) => Promise<void>;\n /** Docks a panel directly to workspace edges. */\n dockPanelToWorkspaceEdge: (id: string, position: 'left' | 'right' | 'top' | 'bottom') => void;\n /** Update active focused tab reference. */\n setActivePanel: (id: string | null) => void;\n /** Explicitly set or override layout direction */\n setDirection: (dir: 'ltr' | 'rtl') => void;\n}\n\nconst WindowStateContext = createContext<WindowState | null>(null);\nconst WindowActionsContext = createContext<WindowActions | null>(null);\nconst WindowI18nContext = createContext<MessageFormatter | null>(null);\n\nconst WindowPredefinedMessagesContext = createContext<Record<PredefinedMessageKey, ContextMenuPredefinedMessage>>(defaultPredefinedMessages);\n\n/** Represents custom CSS classes injected into layout parts. */\nexport interface StyleClasses {\n modalClass?: string;\n modalBodyClass?: string;\n sidePanelClass?: string;\n sidePanelBodyClass?: string;\n windowClass?: string;\n windowBodyClass?: string;\n}\n\nconst StyleClassContext = createContext<StyleClasses>({});\n\n/** Custom hook to read configured style class contexts. */\nexport const useStyleClasses = () => useContext(StyleClassContext);\n\nconst RegistryContext = createContext<PanelRegistryClass>(PanelRegistry);\n\n/** Custom hook to read the scoped panel registry for the current provider. */\nexport const useRegistry = () => useContext(RegistryContext);\n\n// Event Bus class for pub-sub communication between panels\nclass PanelEventBus {\n private listeners: Record<string, ((data: any) => void)[]> = {};\n\n subscribe(event: string, callback: (data: any) => void) {\n if (!this.listeners[event]) {\n this.listeners[event] = [];\n }\n this.listeners[event].push(callback);\n return () => {\n this.listeners[event] = this.listeners[event].filter(cb => cb !== callback);\n };\n }\n\n publish(event: string, data: any) {\n if (this.listeners[event]) {\n this.listeners[event].forEach(cb => cb(data));\n }\n }\n}\n\nconst EMPTY_LEAF: LayoutLeafNode = {\n type: 'leaf',\n id: 'group-default',\n panels: [],\n activePanelId: null,\n};\n\nfunction parseInitialState(json: string | null): Pick<WindowState, 'gridRoot' | 'floating' | 'minimized' | 'panels' | 'activePanelId'> {\n if (json) {\n try {\n const parsed = JSON.parse(json);\n if (parsed.gridRoot && Array.isArray(parsed.floating) && Array.isArray(parsed.minimized) && parsed.panels) {\n return {\n gridRoot: parsed.gridRoot,\n floating: parsed.floating,\n minimized: parsed.minimized,\n panels: parsed.panels,\n activePanelId: Object.keys(parsed.panels)[0] ?? null,\n };\n }\n } catch {\n // fall through to empty canvas\n }\n }\n return { gridRoot: EMPTY_LEAF, floating: [], minimized: [], panels: {}, activePanelId: null };\n}\n\nexport interface WindowManagerProviderProps {\n children: React.ReactNode;\n /** WorkspaceClient instance created outside the React tree. When provided, its registry\n * and config take precedence over the individual props below. */\n client?: WorkspaceClient;\n formatMessage?: MessageFormatter;\n predefinedMessages?: Record<string, ContextMenuPredefinedMessage>;\n dir?: 'ltr' | 'rtl';\n modalClass?: string;\n modalBodyClass?: string;\n sidePanelClass?: string;\n sidePanelBodyClass?: string;\n windowClass?: string;\n windowBodyClass?: string;\n}\n\nexport const WindowManagerProvider: React.FC<WindowManagerProviderProps> = ({\n children,\n client,\n formatMessage,\n predefinedMessages,\n dir: dirProp,\n modalClass,\n modalBodyClass,\n sidePanelClass,\n sidePanelBodyClass,\n windowClass,\n windowBodyClass\n}) => {\n // Scoped registry: client's own instance, or fall back to the global singleton for backward compat\n const registry = useRef(client?.registry ?? PanelRegistry).current;\n\n // Effective config: client props take precedence over individual provider props\n const effectiveFormatMessage = client?.config.formatMessage ?? formatMessage;\n const effectivePredefinedMessages = client?.config.predefinedMessages ?? predefinedMessages;\n const effectiveDir = client?.config.dir ?? dirProp;\n\n const [state, setState] = useState<WindowState>(() => {\n const layout = parseInitialState(client?.initialState ?? null);\n return {\n ...layout,\n draggedPanelId: null,\n dir: effectiveDir || 'ltr',\n isRtl: effectiveDir === 'rtl',\n };\n });\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const closeGuardsRef = useRef<Record<string, () => boolean | Promise<boolean>>>({});\n\n const mergedMessages = useMemo(() => ({\n ...defaultPredefinedMessages,\n ...effectivePredefinedMessages\n }), [effectivePredefinedMessages]);\n\n const eventBusRef = useRef(new PanelEventBus());\n const maxZRef = useRef(1000);\n\n const subscribe = useCallback((event: string, callback: (data: any) => void) => {\n return eventBusRef.current.subscribe(event, callback);\n }, []);\n\n const publish = useCallback((event: string, data: any) => {\n eventBusRef.current.publish(event, data);\n }, []);\n\n // Helper: Find free cascading location for floating window\n const getCascadedPosition = useCallback((\n fav: { x: number | string; y: number | string; width: number | string; height: number | string },\n currentFloating: FloatingWindow[]\n ) => {\n let x = typeof fav.x === 'string' ? parseFloat(fav.x) : fav.x;\n let y = typeof fav.y === 'string' ? parseFloat(fav.y) : fav.y;\n let width = typeof fav.width === 'string' ? parseFloat(fav.width) : fav.width;\n let height = typeof fav.height === 'string' ? parseFloat(fav.height) : fav.height;\n\n // Fallbacks if parseFloat fails and returns NaN\n if (isNaN(x)) x = 300;\n if (isNaN(y)) y = 150;\n if (isNaN(width)) width = 450;\n if (isNaN(height)) height = 350;\n\n const isOverlapping = (pos: { x: number; y: number }) => {\n return currentFloating.some(w => {\n const wx = typeof w.x === 'string' ? parseFloat(w.x) : w.x;\n const wy = typeof w.y === 'string' ? parseFloat(w.y) : w.y;\n return !w.maximized && Math.abs(wx - pos.x) < 20 && Math.abs(wy - pos.y) < 20;\n });\n };\n\n let attempts = 0;\n while (isOverlapping({ x, y }) && attempts < 10) {\n x += 30;\n y += 30;\n attempts++;\n }\n\n // Capture safe viewport boundaries (min 1024x768 fallback if not measured or in headless environments)\n const viewW = Math.max(100, window.innerWidth || 1024);\n const viewH = Math.max(100, window.innerHeight || 768);\n\n if (x + width > viewW || y + height > viewH) {\n x = 100 + (attempts % 5) * 30;\n y = 100 + (attempts % 5) * 30;\n }\n\n // Final safety clamp to make sure window title bar is always visible and clickable\n x = Math.max(0, Math.min(x, viewW - 100));\n y = Math.max(0, Math.min(y, viewH - 40));\n\n return { x, y, width, height };\n }, []);\n\n const bringToFront = useCallback((id: string) => {\n maxZRef.current += 1;\n const z = maxZRef.current;\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n if (panel.state === 'floating') {\n return {\n ...prev,\n floating: prev.floating.map(w => w.id === id ? { ...w, z } : w),\n activePanelId: id\n };\n } else if (panel.state === 'docked') {\n const selectActiveInTree = (node: LayoutNode): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.panels.includes(id)) {\n return { ...node, activePanelId: id };\n }\n return node;\n } else {\n return { ...node, children: node.children.map(selectActiveInTree) };\n }\n };\n return {\n ...prev,\n gridRoot: selectActiveInTree(prev.gridRoot),\n activePanelId: id\n };\n }\n return { ...prev, activePanelId: id };\n });\n }, []);\n\n // Recursive helpers to manipulate layout tree\n const removePanelFromTree = (node: LayoutNode, id: string): LayoutNode | null => {\n if (node.type === 'leaf') {\n const idx = node.panels.indexOf(id);\n if (idx === -1) return node;\n const panels = node.panels.filter(p => p !== id);\n const activePanelId = node.activePanelId === id\n ? (panels[idx] || panels[idx - 1] || panels[0] || null)\n : node.activePanelId;\n const updatedLeaf = { ...node, panels, activePanelId };\n // Auto-remove this leaf when it becomes empty, unless keepOnEmpty is set\n if (panels.length === 0 && !node.keepOnEmpty) return null;\n return updatedLeaf;\n } else {\n const children = node.children\n .map(c => removePanelFromTree(c, id))\n .filter((c): c is LayoutNode => c !== null);\n\n if (children.length === 0) return null;\n if (children.length === 1) return children[0];\n\n // Re-normalize sizes\n const sizes = node.sizes.slice(0, children.length);\n const sum = sizes.reduce((a, b) => a + b, 0);\n return {\n ...node,\n children,\n sizes: sizes.map(s => s / sum)\n };\n }\n };\n\n const addPanelToLeaf = (node: LayoutNode, leafId: string, panelId: string): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.id === leafId) {\n const panels = node.panels.includes(panelId) ? node.panels : [...node.panels, panelId];\n return { ...node, panels, activePanelId: panelId };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(c => addPanelToLeaf(c, leafId, panelId))\n };\n }\n };\n\n const findFirstLeafId = (node: LayoutNode): string | null => {\n if (node.type === 'leaf') return node.id;\n for (const child of node.children) {\n const id = findFirstLeafId(child);\n if (id) return id;\n }\n return null;\n };\n\n const openPanel = useCallback((id: string, component: string, options?: { title?: string | ContextMenuPredefinedMessage; initialTarget?: 'floating' | 'docked' | 'tabbed'; stickyRight?: boolean; stickyBottom?: boolean }) => {\n setState(prev => {\n const exists = prev.panels[id];\n const entry = registry.get(component);\n const title = options?.title || options?.title || entry?.defaultOptions?.title || id;\n const target = options?.initialTarget || entry?.defaultOptions?.initialTarget || 'docked';\n const favPos = entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n\n // Case 1: Already exists\n if (exists) {\n if (exists.state === 'minimized') {\n // Restore\n const nextMinimized = prev.minimized.filter(m => m.id !== id);\n if (target === 'floating' || !prev.gridRoot) {\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n return {\n ...prev,\n minimized: nextMinimized,\n floating: [...prev.floating, { ...cascaded, id, z: maxZRef.current }],\n panels: { ...prev.panels, [id]: { ...exists, state: 'floating' } }\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-default';\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, id),\n panels: { ...prev.panels, [id]: { ...exists, state: 'docked' } }\n };\n }\n } else if (exists.state === 'floating') {\n bringToFront(id);\n return prev;\n } else {\n // Focus in tab group\n const selectActiveInTree = (node: LayoutNode): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.panels.includes(id)) {\n return { ...node, activePanelId: id };\n }\n return node;\n } else {\n return { ...node, children: node.children.map(selectActiveInTree) };\n }\n };\n return {\n ...prev,\n gridRoot: selectActiveInTree(prev.gridRoot)\n };\n }\n }\n\n // Case 2: New panel\n const targetState = target === 'tabbed' ? 'docked' : target;\n const newPanelInfo: PanelInfo = { id, title, component, state: targetState };\n const nextPanels = { ...prev.panels, [id]: newPanelInfo };\n\n if (target === 'floating') {\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n\n const stickyRight = options?.stickyRight ?? entry?.defaultOptions?.defaultStickyRight ?? false;\n const stickyBottom = options?.stickyBottom ?? entry?.defaultOptions?.defaultStickyBottom ?? false;\n\n const viewW = Math.max(100, window.innerWidth || 1024);\n const viewH = Math.max(100, window.innerHeight || 768);\n const winW = typeof cascaded.width === 'string' ? parseFloat(cascaded.width) : cascaded.width;\n const winH = typeof cascaded.height === 'string' ? parseFloat(cascaded.height) : cascaded.height;\n\n let initialX = cascaded.x;\n let initialY = cascaded.y;\n\n const GAP = 10;\n if (stickyRight) {\n initialX = viewW - winW - GAP;\n }\n if (stickyBottom) {\n initialY = viewH - winH - GAP;\n }\n\n return {\n ...prev,\n floating: [...prev.floating, { ...cascaded, id, z: maxZRef.current, x: initialX, y: initialY, stickyRight, stickyBottom }],\n panels: nextPanels\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-default';\n return {\n ...prev,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, id),\n panels: nextPanels\n };\n }\n });\n }, [getCascadedPosition, bringToFront]);\n\n const closePanel = useCallback((id: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const registryEntry = registry.get(panel.component);\n if (registryEntry?.defaultOptions?.canClose === false) {\n return prev;\n }\n\n delete closeGuardsRef.current[id];\n\n const nextPanels = { ...prev.panels };\n delete nextPanels[id];\n\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: prev.minimized.filter(m => m.id !== id),\n panels: nextPanels\n };\n });\n }, []);\n\n const registerCloseGuard = useCallback((id: string, guard: () => boolean | Promise<boolean>) => {\n closeGuardsRef.current[id] = guard;\n }, []);\n\n const unregisterCloseGuard = useCallback((id: string) => {\n delete closeGuardsRef.current[id];\n }, []);\n\n const setPanelDirty = useCallback((id: string, dirty: boolean, options?: DirtyStateOptions) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n return {\n ...prev,\n panels: {\n ...prev.panels,\n [id]: { ...panel, dirty, dirtyOptions: options }\n }\n };\n });\n }, []);\n\n const updatePanelTitle = useCallback((id: string, title: string | ContextMenuPredefinedMessage) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n return {\n ...prev,\n panels: {\n ...prev.panels,\n [id]: { ...panel, title }\n }\n };\n });\n }, []);\n\n const requestClosePanel = useCallback(async (id: string, options?: { force?: boolean; onConfirm?: (opts?: DirtyStateOptions) => Promise<boolean> }) => {\n if (options?.force) {\n closePanel(id);\n return;\n }\n\n // 1. Check custom close guard\n const guard = closeGuardsRef.current[id];\n if (guard) {\n const canClose = await guard();\n if (!canClose) return;\n }\n\n // 2. Check automatic dirty flag\n const panel = stateRef.current.panels[id];\n if (panel?.dirty) {\n if (options?.onConfirm) {\n const discard = await options.onConfirm(panel.dirtyOptions);\n if (!discard) return;\n } else {\n return;\n }\n }\n\n closePanel(id);\n }, [closePanel]);\n\n const minimizePanel = useCallback((id: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel || panel.state === 'minimized') return prev;\n\n const registryEntry = registry.get(panel.component);\n if (registryEntry?.defaultOptions?.canMinimize === false) {\n return prev;\n }\n\n let lastFloatingRect: any = undefined;\n let lastLeafId: any = undefined;\n\n if (panel.state === 'floating') {\n const win = prev.floating.find(w => w.id === id);\n if (win) {\n lastFloatingRect = { \n x: win.x, \n y: win.y, \n width: win.width, \n height: win.height,\n stickyRight: win.stickyRight,\n stickyBottom: win.stickyBottom\n };\n }\n } else if (panel.state === 'docked') {\n const findLeafForPanel = (node: LayoutNode): string | null => {\n if (node.type === 'leaf') {\n return node.panels.includes(id) ? node.id : null;\n } else {\n for (const child of node.children) {\n const res = findLeafForPanel(child);\n if (res) return res;\n }\n return null;\n }\n };\n lastLeafId = findLeafForPanel(prev.gridRoot);\n }\n\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: [...prev.minimized, { id, title: panel.title, component: panel.component }],\n panels: {\n ...prev.panels,\n [id]: {\n ...panel,\n state: 'minimized',\n previousState: panel.state,\n lastFloatingRect,\n lastLeafId\n }\n }\n };\n });\n }, []);\n\n const restorePanel = useCallback((id: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel || panel.state !== 'minimized') return prev;\n\n const nextMinimized = prev.minimized.filter(m => m.id !== id);\n const prevState = panel.previousState || 'docked';\n\n if (prevState === 'floating') {\n maxZRef.current += 1;\n const entry = registry.get(panel.component);\n const favPos = panel.lastFloatingRect || entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n const cascaded = getCascadedPosition(favPos, prev.floating);\n return {\n ...prev,\n minimized: nextMinimized,\n floating: [\n ...prev.floating, \n { \n ...cascaded, \n id, \n z: maxZRef.current,\n stickyRight: !!panel.lastFloatingRect?.stickyRight,\n stickyBottom: !!panel.lastFloatingRect?.stickyBottom\n }\n ],\n panels: { ...prev.panels, [id]: { ...panel, state: 'floating' } }\n };\n } else {\n const leafExists = (node: LayoutNode, targetId: string): boolean => {\n if (node.type === 'leaf') return node.id === targetId;\n return node.children.some(c => leafExists(c, targetId));\n };\n\n const parentLeafExists = panel.lastLeafId && leafExists(prev.gridRoot, panel.lastLeafId);\n const entry = registry.get(panel.component);\n const canDrag = entry?.defaultOptions?.canDrag !== false;\n\n if (parentLeafExists) {\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, panel.lastLeafId!, id),\n panels: { ...prev.panels, [id]: { ...panel, state: 'docked' } }\n };\n } else if (canDrag) {\n // Leaf group ceased to exist: float it instead if floatable!\n maxZRef.current += 1;\n const favPos = panel.lastFloatingRect || entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n const cascaded = getCascadedPosition(favPos, prev.floating);\n return {\n ...prev,\n minimized: nextMinimized,\n floating: [\n ...prev.floating, \n { \n ...cascaded, \n id, \n z: maxZRef.current,\n stickyRight: !!panel.lastFloatingRect?.stickyRight,\n stickyBottom: !!panel.lastFloatingRect?.stickyBottom\n }\n ],\n panels: { ...prev.panels, [id]: { ...panel, state: 'floating' } }\n };\n } else {\n // Leaf group ceased to exist but not floatable: dock into fallback leaf group\n const targetLeafId = findFirstLeafId(prev.gridRoot) || 'group-default';\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, targetLeafId, id),\n panels: { ...prev.panels, [id]: { ...panel, state: 'docked' } }\n };\n }\n }\n });\n }, [getCascadedPosition]);\n\n const floatPanel = useCallback((id: string, rect?: { x: number; y: number; width: number; height: number }) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const registryEntry = registry.get(panel.component);\n if (registryEntry?.defaultOptions?.canDrag === false) {\n return prev;\n }\n\n const entry = registry.get(panel.component);\n const favPos = rect || entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: [...prev.floating, { ...cascaded, id, z: maxZRef.current }],\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'floating' }\n }\n };\n });\n }, [getCascadedPosition]);\n\n const dockPanel = useCallback((id: string, targetLeafId?: string) => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n const leafId = targetLeafId || findFirstLeafId(cleanRoot || prev.gridRoot) || 'group-default';\n\n return {\n ...prev,\n gridRoot: addPanelToLeaf(cleanRoot || prev.gridRoot, leafId, id),\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'docked' }\n }\n };\n });\n }, []);\n\n // Helper to split a layout leaf node into a branch (for drag split targets)\n const splitLeafInTree = (\n node: LayoutNode,\n leafId: string,\n panelId: string,\n position: 'left' | 'right' | 'top' | 'bottom'\n ): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.id === leafId) {\n const newLeaf: LayoutLeafNode = {\n type: 'leaf',\n id: `group-split-${Date.now()}-${Math.floor(Math.random() * 1000)}`,\n panels: [panelId],\n activePanelId: panelId\n };\n const orientation: SplitOrientation = (position === 'left' || position === 'right') ? 'horizontal' : 'vertical';\n const children = (position === 'left' || position === 'top') ? [newLeaf, node] : [node, newLeaf];\n return {\n type: 'branch',\n orientation,\n sizes: [0.5, 0.5],\n children\n };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(c => splitLeafInTree(c, leafId, panelId, position))\n };\n }\n };\n\n const setDraggedPanelId = useCallback((id: string | null) => {\n setState(prev => ({ ...prev, draggedPanelId: id }));\n }, []);\n\n const dockPanelToGroup = useCallback((id: string, targetLeafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center') => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n\n let newRoot: LayoutNode;\n if (position === 'center') {\n newRoot = addPanelToLeaf(cleanRoot || prev.gridRoot, targetLeafId, id);\n } else {\n newRoot = splitLeafInTree(cleanRoot || prev.gridRoot, targetLeafId, id, position);\n }\n\n return {\n ...prev,\n gridRoot: newRoot,\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'docked' }\n },\n draggedPanelId: null\n };\n });\n }, []);\n\n const dockPanelToWorkspaceEdge = useCallback((id: string, position: 'left' | 'right' | 'top' | 'bottom') => {\n setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const cleanRoot = removePanelFromTree(prev.gridRoot, id);\n\n const newLeaf: LayoutLeafNode = {\n type: 'leaf',\n id: `group-edge-${Date.now()}-${Math.floor(Math.random() * 1000)}`,\n panels: [id],\n activePanelId: id\n };\n\n const orientation: SplitOrientation = (position === 'left' || position === 'right') ? 'horizontal' : 'vertical';\n const children = (position === 'left' || position === 'top')\n ? [newLeaf, cleanRoot || prev.gridRoot]\n : [cleanRoot || prev.gridRoot, newLeaf];\n\n const newRoot: LayoutNode = {\n type: 'branch',\n orientation,\n sizes: (position === 'left' || position === 'top') ? [0.3, 0.7] : [0.7, 0.3],\n children\n };\n\n return {\n ...prev,\n gridRoot: newRoot,\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [id]: { ...panel, state: 'docked' }\n },\n draggedPanelId: null\n };\n });\n }, []);\n\n const movePanelOrder = useCallback((panelId: string, targetLeafId: string, targetIndex: number) => {\n setState(prev => {\n const panel = prev.panels[panelId];\n if (!panel) return prev;\n\n // 1. Remove panel from its current group in the layout tree\n const cleanRoot = removePanelFromTree(prev.gridRoot, panelId);\n\n // 2. Insert panel at specific index in target leaf ID\n const insertInLeaf = (node: LayoutNode): LayoutNode => {\n if (node.type === 'leaf') {\n if (node.id === targetLeafId) {\n const remaining = node.panels.filter(p => p !== panelId);\n const index = Math.max(0, Math.min(targetIndex, remaining.length));\n const newPanels = [...remaining];\n newPanels.splice(index, 0, panelId);\n return {\n ...node,\n panels: newPanels,\n activePanelId: panelId\n };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(insertInLeaf)\n };\n }\n };\n\n const newRoot = insertInLeaf(cleanRoot || prev.gridRoot);\n const nextFloating = prev.floating.filter(w => w.id !== panelId);\n\n return {\n ...prev,\n gridRoot: newRoot,\n floating: nextFloating,\n panels: {\n ...prev.panels,\n [panelId]: { ...panel, state: 'docked' }\n },\n draggedPanelId: null\n };\n });\n }, []);\n\n const closeLeafGroup = useCallback((leafId: string) => {\n setState(prev => {\n const removeLeafFromTree = (node: LayoutNode): LayoutNode | null => {\n if (node.type === 'leaf') {\n if (node.id === leafId && node.canClose !== false) {\n return null;\n }\n return node;\n } else {\n const children = node.children\n .map(c => removeLeafFromTree(c))\n .filter((c): c is LayoutNode => c !== null);\n\n if (children.length === 0) return null;\n if (children.length === 1) return children[0];\n\n // Re-normalize sizes\n const sizes = node.sizes.slice(0, children.length);\n const sum = sizes.reduce((a, b) => a + b, 0);\n return {\n ...node,\n children,\n sizes: sizes.map(s => s / sum)\n };\n }\n };\n\n const newRoot = removeLeafFromTree(prev.gridRoot);\n return {\n ...prev,\n gridRoot: newRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null }\n };\n });\n }, []);\n\n const maximizePanel = useCallback((id: string) => {\n setState(prev => ({\n ...prev,\n floating: prev.floating.map(w => w.id === id ? { ...w, maximized: !w.maximized } : w)\n }));\n }, []);\n\n const updateSplitSizes = useCallback((path: number[], sizes: number[]) => {\n const updateInTree = (node: LayoutNode, depth: number): LayoutNode => {\n if (node.type === 'leaf') return node;\n if (depth === path.length) {\n return { ...node, sizes };\n }\n const idx = path[depth];\n const children = node.children.map((c, i) => i === idx ? updateInTree(c, depth + 1) : c);\n return { ...node, children };\n };\n\n setState(prev => ({\n ...prev,\n gridRoot: updateInTree(prev.gridRoot, 0)\n }));\n }, []);\n\n const updateFloatingPosition = useCallback((id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'stickyRight' | 'stickyBottom'>>) => {\n setState(prev => ({\n ...prev,\n floating: prev.floating.map(w => w.id === id ? { ...w, ...updates } : w)\n }));\n }, []);\n\n const saveLayout = useCallback(() => {\n return JSON.stringify({\n gridRoot: stateRef.current.gridRoot,\n floating: stateRef.current.floating,\n minimized: stateRef.current.minimized,\n panels: stateRef.current.panels\n });\n }, []);\n\n const loadLayout = useCallback((layoutJson: string) => {\n try {\n const parsed = JSON.parse(layoutJson);\n if (parsed.gridRoot && parsed.floating && parsed.minimized && parsed.panels) {\n const firstActive = Object.keys(parsed.panels)[0] || null;\n setState(prev => ({\n ...prev,\n gridRoot: parsed.gridRoot,\n floating: parsed.floating,\n minimized: parsed.minimized,\n panels: parsed.panels,\n draggedPanelId: null,\n activePanelId: firstActive\n }));\n }\n } catch (e) {\n console.error('Failed to parse layout configuration:', e);\n }\n }, []);\n\n const setActivePanel = useCallback((id: string | null) => {\n setState(prev => {\n if (prev.activePanelId === id) return prev;\n return { ...prev, activePanelId: id };\n });\n }, []);\n\n const setDirection = useCallback((dir: 'ltr' | 'rtl') => {\n setState(prev => {\n if (prev.dir === dir) return prev;\n return { ...prev, dir, isRtl: dir === 'rtl' };\n });\n }, []);\n\n useEffect(() => {\n if (effectiveDir) {\n setState(prev => {\n if (prev.dir === effectiveDir) return prev;\n return { ...prev, dir: effectiveDir, isRtl: effectiveDir === 'rtl' };\n });\n }\n }, [effectiveDir]);\n\n const actions = useMemo<WindowActions>(() => ({\n openPanel,\n closePanel,\n minimizePanel,\n restorePanel,\n floatPanel,\n dockPanel,\n maximizePanel,\n updateSplitSizes,\n updateFloatingPosition,\n bringToFront,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection\n }), [\n openPanel,\n closePanel,\n minimizePanel,\n restorePanel,\n floatPanel,\n dockPanel,\n maximizePanel,\n updateSplitSizes,\n updateFloatingPosition,\n bringToFront,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection\n ]);\n\n const defaultFormatMessage: MessageFormatter = (msg) => {\n let text = msg.defaultMessage || msg.id;\n if (msg.values) {\n Object.entries(msg.values).forEach(([key, value]) => {\n text = text.replace(`{${key}}`, String(value));\n });\n }\n return text;\n };\n\n const styleClasses = useMemo(() => ({\n modalClass,\n modalBodyClass,\n sidePanelClass,\n sidePanelBodyClass,\n windowClass,\n windowBodyClass\n }), [modalClass, modalBodyClass, sidePanelClass, sidePanelBodyClass, windowClass, windowBodyClass]);\n\n useEffect(() => {\n if (client) {\n client._connect(actions);\n return () => { client._disconnect(); };\n }\n }, [client, actions]);\n\n return (\n <StyleClassContext.Provider value={styleClasses}>\n <RegistryContext.Provider value={registry}>\n <WindowStateContext.Provider value={state}>\n <WindowActionsContext.Provider value={actions}>\n <WindowI18nContext.Provider value={effectiveFormatMessage || defaultFormatMessage}>\n <WindowPredefinedMessagesContext.Provider value={mergedMessages}>\n {children}\n </WindowPredefinedMessagesContext.Provider>\n </WindowI18nContext.Provider>\n </WindowActionsContext.Provider>\n </WindowStateContext.Provider>\n </RegistryContext.Provider>\n </StyleClassContext.Provider>\n );\n};\n\n/**\n * React hook to retrieve the active Window Manager layout state.\n * @throws Error if used outside of a {@link WindowManagerProvider}.\n */\nexport const useWindowManagerState = () => {\n const ctx = useContext(WindowStateContext);\n if (!ctx) throw new Error('useWindowManagerState must be used within WindowManagerProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve layouts mutation actions (dock, float, minimize, save/load).\n * @throws Error if used outside of a {@link WindowManagerProvider}.\n */\nexport const useWindowManagerActions = () => {\n const ctx = useContext(WindowActionsContext);\n if (!ctx) throw new Error('useWindowManagerActions must be used within WindowManagerProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve the active i18n formatter.\n */\nexport const useFormatMessage = () => {\n const formatter = useContext(WindowI18nContext);\n return formatter || ((msg) => {\n let text = msg.defaultMessage || msg.id;\n if (msg.values) {\n Object.entries(msg.values).forEach(([key, value]) => {\n text = text.replace(`{${key}}`, String(value));\n });\n }\n return text;\n });\n};\n\n/**\n * Helper to resolve dynamic label strings or localizable descriptor objects into text.\n */\nexport const formatLabel = (\n label: string | ContextMenuPredefinedMessage | undefined,\n formatter: MessageFormatter\n): string => {\n if (!label) return '';\n if (typeof label === 'string') return label;\n return formatter(label);\n};\n\n/**\n * React hook providing pub-sub helper methods for inter-panel event messaging.\n */\nexport const usePanelContext = () => {\n const { publish, subscribe } = useWindowManagerActions();\n return { publish, subscribe };\n};\n\n/**\n * React hook to fetch the localizable predefined message map catalog.\n */\nexport const usePredefinedMessages = () => {\n return useContext(WindowPredefinedMessagesContext);\n};\n","import type { ComponentType } from 'react';\n\n/**\n * Represents a registered component configuration template inside the panel catalog registry.\n */\nexport interface PanelRegistryEntry {\n /** The React component type registered. */\n Component: ComponentType<any>;\n /** Default metadata settings configuration applied on instantiation. */\n defaultOptions?: {\n /** Tab and window headers text — plain string or i18n descriptor. */\n title?: string | { id: string; defaultMessage?: string; values?: Record<string, string | number> };\n /** Icon placed next to title tags. */\n icon?: React.ReactNode;\n /** Initial mounting state inside the desktop layout grid. */\n initialTarget?: 'floating' | 'docked' | 'tabbed';\n /** Custom default bounds applied when the container is floated. */\n favoritePosition?: { x: number | string; y: number | string; width: number | string; height: number | string };\n /** Enables/disables window drag interactions. */\n canDrag?: boolean;\n /** Enables/disables minimizing of the panel instance. */\n canMinimize?: boolean;\n /** Enables/disables closing actions for the tab/window. */\n canClose?: boolean;\n /** Affixes the panel to the right edge. */\n defaultStickyRight?: boolean;\n /** Affixes the panel to the bottom edge. */\n defaultStickyBottom?: boolean;\n /** Disables live WebGL rendering canvas thumbnails inside the taskbar hover popup previews. */\n disableLivePreview?: boolean;\n /** Custom header actions renderer, placing custom components in the window/tab titlebar. */\n renderHeaderActions?: (panelId: string) => React.ReactNode;\n };\n}\n\n/**\n * Registry mapping catalog entries to allow programmatic panel instantiation\n * inside dynamic layout cells or floating windows.\n * Exported so WorkspaceClient can create scoped, per-instance registries.\n */\nexport class PanelRegistryClass {\n private registry = new Map<string, PanelRegistryEntry>();\n\n /**\n * Register a new component to the panel catalog registry.\n * @param id - Unique string identifier.\n * @param Component - React component instance template.\n * @param defaultOptions - Custom default settings configuration.\n */\n register<P extends object>(\n id: string,\n Component: ComponentType<P>,\n defaultOptions?: PanelRegistryEntry['defaultOptions']\n ): void {\n this.registry.set(id, {\n Component: Component as ComponentType<any>,\n defaultOptions\n });\n }\n\n /**\n * Retrieve a registered panel configuration by identifier.\n */\n get(id: string): PanelRegistryEntry | undefined {\n return this.registry.get(id);\n }\n\n /**\n * Returns a list of all registered panel entry identifiers.\n */\n getRegisteredIds(): string[] {\n return Array.from(this.registry.keys());\n }\n}\n\n/** Global singleton instance of the Panel Registry. */\nexport const PanelRegistry = new PanelRegistryClass();\nexport default PanelRegistry;\n","/**\n * @file predefinedMessages.ts\n * @description Provides the default localizable message catalogs and translation keys\n * utilized by Dockable Desktop's context menus, headers, and tooltips.\n *\n * Each value's `id` is the react-intl message ID that the consumer should\n * define in their IntlProvider messages table. The `defaultMessage` is used\n * as a fallback when no external formatter is provided.\n *\n * Pass a partial or full override to <WindowManagerProvider predefinedMessages={…} />\n * to customise labels without replacing the whole table.\n */\nexport const defaultPredefinedMessages = {\n floatWindow: { id: 'dockable-desktop-floatWindow', defaultMessage: 'Float Window' },\n minimizePanel: { id: 'dockable-desktop-minimizePanel', defaultMessage: 'Minimize Panel' },\n closeTab: { id: 'dockable-desktop-closeTab', defaultMessage: 'Close Tab' },\n restorePanel: { id: 'dockable-desktop-restorePanel', defaultMessage: 'Restore Panel' },\n maximizePanel: { id: 'dockable-desktop-maximizePanel', defaultMessage: 'Maximize Panel' },\n closePanel: { id: 'dockable-desktop-closePanel', defaultMessage: 'Close Panel' },\n dockWindow: { id: 'dockable-desktop-dockWindow', defaultMessage: 'Dock Window' },\n minimize: { id: 'dockable-desktop-minimize', defaultMessage: 'Minimize' },\n maximize: { id: 'dockable-desktop-maximize', defaultMessage: 'Maximize' },\n restoreSize: { id: 'dockable-desktop-restoreSize', defaultMessage: 'Restore Size' },\n close: { id: 'dockable-desktop-close', defaultMessage: 'Close' },\n closeEmptyGroup: { id: 'dockable-desktop-closeEmptyGroup', defaultMessage: 'Close empty split group' },\n anchorToRightEdge: { id: 'dockable-desktop-anchorToRightEdge', defaultMessage: 'Anchor to Right Edge' },\n anchorToBottomEdge: { id: 'dockable-desktop-anchorToBottomEdge', defaultMessage: 'Anchor to Bottom Edge' },\n windowAnchoringOptions: { id: 'dockable-desktop-windowAnchoringOptions', defaultMessage: 'Window Anchoring Options' },\n unsavedChangesTitle: { id: 'dockable-desktop-unsavedChangesTitle', defaultMessage: 'Unsaved Changes' },\n unsavedChangesMessage: { id: 'dockable-desktop-unsavedChangesMessage', defaultMessage: '\"{title}\" has unsaved changes. Do you want to discard your changes and close?' },\n discardChanges: { id: 'dockable-desktop-discardChanges', defaultMessage: 'Discard Changes' },\n cancel: { id: 'dockable-desktop-cancel', defaultMessage: 'Cancel' },\n yes: { id: 'dockable-desktop-yes', defaultMessage: 'Yes' },\n no: { id: 'dockable-desktop-no', defaultMessage: 'No' },\n ok: { id: 'dockable-desktop-ok', defaultMessage: 'OK' },\n closePanelTooltip: { id: 'dockable-desktop-closePanelTooltip', defaultMessage: 'Close panel' },\n closeTooltip: { id: 'dockable-desktop-closeTooltip', defaultMessage: 'Close' },\n} as const;\n\n/**\n * Union of every key in `defaultPredefinedMessages`.\n *\n * Import this type in your i18n message tables to get a compile-time\n * guarantee that all keys are present and no typos exist:\n *\n * import type { PredefinedMessageKey } from 'react-dockable-desktop';\n *\n * const myMessages: Record<PredefinedMessageKey, string> = { ... };\n */\nexport type PredefinedMessageKey = keyof typeof defaultPredefinedMessages;\n","export function isElementRtl(el: HTMLElement | null): boolean {\n if (!el) {\n if (typeof document !== 'undefined') {\n return (\n document.documentElement.dir?.toLowerCase() === 'rtl' ||\n document.body.dir?.toLowerCase() === 'rtl'\n );\n }\n return false;\n }\n\n // Check closest element with dir attribute\n const closestDirEl = el.closest('[dir]');\n if (closestDirEl) {\n return closestDirEl.getAttribute('dir')?.toLowerCase() === 'rtl';\n }\n\n // Fallback to document rules\n return (\n document.documentElement.dir?.toLowerCase() === 'rtl' ||\n document.body.dir?.toLowerCase() === 'rtl'\n );\n}\n","import { createContext, useContext } from 'react';\nimport type { DirtyStateOptions } from './dirtyOptions';\n\n/**\n * Options used when requesting to close a container.\n */\nexport interface CloseOptions {\n /** If true, bypasses any dirty state warnings or custom close guards. */\n force?: boolean;\n}\n\n/** Represents the type of container context a panel/form is currently rendered inside. */\nexport type ContainerType = 'left-panel' | 'right-panel' | 'modal' | 'dockable-panel' | 'standalone';\n\n/**\n * Contract interface exposed by a container (like a tab, window, modal, or side-panel)\n * to its children forms, enabling them to control or listen to container events.\n */\nexport interface FormContainerContract {\n /** Request the container to close itself. Bypassed by default unless options.force is true. */\n requestClose: (options?: CloseOptions) => void;\n /** Mark the form's content as dirty (having unsaved changes), triggering alert dialogs on close. */\n setDirty: (dirty: boolean, options?: DirtyStateOptions) => void;\n /** Register a custom close guard handler. Returning false or a promise resolving to false blocks closing. */\n onCloseRequested: (handler: () => boolean | Promise<boolean>) => (() => void);\n /** Change the display title of the containing tab or window dynamically. */\n setTitle: (title: string | { id: string; defaultMessage: string; values?: Record<string, any> }) => void;\n /** Change the tab or window icon dynamically. */\n setIcon?: (icon: React.ReactNode) => void;\n /** The type of container the panel is mounted in. */\n containerType?: ContainerType;\n /** Unique identifier of the panel or window instance. */\n instanceId: string;\n /** Subscribe to the container's close event. Returns an unsubscribe function. */\n onClose?: (handler: () => void) => () => void;\n /** Subscribe to the container's minimize event. Returns an unsubscribe function. */\n onMinimize?: (handler: () => void) => () => void;\n /** Subscribe to the container's restore event. Returns an unsubscribe function. */\n onRestore?: (handler: () => void) => () => void;\n /** Subscribe to the container's window resize event, returning width and height. */\n onResize?: (handler: (width: number, height: number) => void) => () => void;\n}\n\nconst defaultContract: FormContainerContract = {\n requestClose: () => {\n console.warn('FormContainerContract: requestClose called but no container is present');\n },\n setDirty: () => {},\n onCloseRequested: () => () => {},\n setTitle: () => {},\n setIcon: () => {},\n containerType: 'standalone',\n instanceId: 'standalone',\n onClose: () => () => {},\n onMinimize: () => () => {},\n onRestore: () => () => {},\n onResize: () => () => {},\n};\n\n/**\n * Context that supplies the {@link FormContainerContract} to panels inside the Window Manager.\n */\nexport const FormContainerContext = createContext<FormContainerContract>(defaultContract);\nexport const FormContainerProvider = FormContainerContext.Provider;\n\n/**\n * React hook to retrieve the current {@link FormContainerContract} from context.\n * Enables sub-forms to trigger close requests, mark themselves dirty, rename their tabs, or listen to resize events.\n */\nexport const useFormContainer = (): FormContainerContract => {\n return useContext(FormContainerContext);\n};\n\n","import React, { createContext, useContext, useState, useCallback, useMemo, useRef } from 'react';\nimport type { ComponentType, ReactNode } from 'react';\nimport type { DirtyStateOptions } from './dirtyOptions';\nexport type { DirtyStateOptions };\n\n/** Unique string identifier for panel/modal instances. */\nexport type PanelInstanceId = string;\n\n/**\n * Descriptor object for localizable panel titles, supporting context translation systems.\n */\nexport interface PanelTitleDescriptor {\n /** The translation dictionary key. */\n id: string;\n /** Fallback string if translation key is missing. */\n defaultMessage?: string;\n /** Parameters to inject into the translated text string. */\n values?: Record<string, string | number>;\n}\n\n/** Union type representing either a plain string or a localizable title descriptor. */\nexport type PanelTitle = string | PanelTitleDescriptor;\n\n/** Configuration options applied when opening a SidePanel. */\nexport interface SidePanelOptions {\n /** Display title for the side-panel header. */\n title?: PanelTitle;\n /** Icon displayed next to the panel title. */\n icon?: React.ReactNode;\n /** Specific CSS width (e.g. 300, '40%') for the panel container. */\n width?: number | string;\n}\n\n/** Configuration options applied when opening a Modal. */\nexport interface ModalOptions {\n /** Display title for the modal header. */\n title?: PanelTitle;\n /** Icon displayed in the modal title bar. */\n icon?: React.ReactNode;\n /** Size modifier affecting CSS max-width rules. */\n size?: 'small' | 'medium' | 'large' | 'fullscreen' | 'auto';\n /** If false, hides the modal backdrop exit click and header close button. */\n closable?: boolean;\n}\n\n/**\n * Represents a rendered instance of a panel or modal in the layout.\n */\nexport interface PanelInstance {\n /** Unique ID generated for this instance. */\n id: PanelInstanceId;\n /** React Component to mount inside the panel. */\n Component: ComponentType<any>;\n /** Property props passed to the Component. */\n props: Record<string, any>;\n /** The target rendering layout zone. */\n containerType: 'left-panel' | 'right-panel' | 'modal';\n /** Configuration metadata settings. */\n options: SidePanelOptions | ModalOptions;\n /** True if the form container has unsaved user edits. */\n dirty?: boolean;\n /** Custom warning options applied to the automatic unsaved changes modal. */\n dirtyOptions?: DirtyStateOptions;\n}\n\n/** Stores the active layout structures for floating overlays. */\nexport interface PanelState {\n /** The currently open left drawer panel instance, or null. */\n leftPanel: PanelInstance | null;\n /** The currently open right drawer panel instance, or null. */\n rightPanel: PanelInstance | null;\n /** Stack containing all active floating modal instances. */\n modals: PanelInstance[];\n}\n\n/** Exposes methods to trigger state actions on drawers and modals. */\nexport interface PanelActions {\n /** Mounts a panel in the left-side container drawer. */\n openLeftPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Mounts a panel in the right-side container drawer. */\n openRightPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Pushes a new modal component instance to the top of the stack. */\n openModal: <P extends object>(Component: ComponentType<P>, props: P, options?: ModalOptions) => PanelInstanceId;\n /** Closes an instance by ID. */\n close: (id: PanelInstanceId) => void;\n /** Closes all drawers and modals in a single action. */\n closeAll: () => void;\n /** Closes all open modals. */\n closeAllModals: () => void;\n /** Retrieves metadata for an active instance by ID. */\n getInstance: (id: PanelInstanceId) => PanelInstance | undefined;\n /** Updates the props, configuration options, or dirty flag of an active panel. */\n updateInstance: (id: PanelInstanceId, updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>) => void;\n /** Flags an instance as dirty (contains unsaved changes). */\n setDirty: (id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => void;\n /** Subscribes a custom close confirmation intercept handler. */\n registerCloseHandler: (id: PanelInstanceId, handler: () => Promise<boolean>) => void;\n /** Unsubscribes close confirmation handler. */\n unregisterCloseHandler: (id: PanelInstanceId) => void;\n}\n\nlet idCounter = 0;\nconst generateId = (): PanelInstanceId => `panel-${++idCounter}-${Date.now()}`;\n\nconst closeHandlers = new Map<PanelInstanceId, () => Promise<boolean>>();\n\nconst initialState: PanelState = {\n leftPanel: null,\n rightPanel: null,\n modals: [],\n};\n\nconst PanelStateContext = createContext<PanelState | null>(null);\nconst PanelActionsContext = createContext<PanelActions | null>(null);\n\n/**\n * PanelProvider component manages the state and action handlers\n * for drawers (left/right) and active stacked modal overlays.\n */\nexport const PanelProvider: React.FC<{ children: ReactNode }> = ({ children }) => {\n const [state, setState] = useState<PanelState>(initialState);\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const registerCloseHandler = useCallback((id: PanelInstanceId, handler: () => Promise<boolean>) => {\n closeHandlers.set(id, handler);\n }, []);\n\n const unregisterCloseHandler = useCallback((id: PanelInstanceId) => {\n closeHandlers.delete(id);\n }, []);\n\n const openLeftPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.leftPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'left-panel',\n options,\n };\n setState(s => ({ ...s, leftPanel: instance }));\n return id;\n },\n []\n );\n\n const openRightPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.rightPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'right-panel',\n options,\n };\n setState(s => ({ ...s, rightPanel: instance }));\n return id;\n },\n []\n );\n\n const openModal = useCallback(\n <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: ModalOptions = {}\n ): PanelInstanceId => {\n const id = generateId();\n const formTitle = (props as any).title;\n \n const modalOptions: ModalOptions = {\n ...options,\n title: options.title || formTitle || 'Confirmation',\n };\n\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'modal',\n options: modalOptions,\n };\n setState(s => ({ ...s, modals: [...s.modals, instance] }));\n return id;\n },\n []\n );\n\n const close = useCallback((id: PanelInstanceId) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? null : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? null : s.rightPanel,\n modals: s.modals.filter(m => m.id !== id),\n }));\n }, []);\n\n const closeAll = useCallback(() => {\n setState(initialState);\n }, []);\n\n const closeAllModals = useCallback(() => {\n setState(s => ({ ...s, modals: [] }));\n }, []);\n\n const getInstance = useCallback(\n (id: PanelInstanceId): PanelInstance | undefined => {\n if (state.leftPanel?.id === id) return state.leftPanel;\n if (state.rightPanel?.id === id) return state.rightPanel;\n return state.modals.find(m => m.id === id);\n },\n [state]\n );\n\n const updateInstance = useCallback(\n (\n id: PanelInstanceId,\n updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>\n ) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? { ...s.leftPanel, ...updates } : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? { ...s.rightPanel, ...updates } : s.rightPanel,\n modals: s.modals.map(m => m.id === id ? { ...m, ...updates } : m),\n }));\n },\n []\n );\n\n const setDirty = useCallback((id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => {\n updateInstance(id, { dirty, dirtyOptions: options });\n }, [updateInstance]);\n\n const actions = useMemo<PanelActions>(\n () => ({\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n }),\n [\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n ]\n );\n\n return (\n <PanelStateContext.Provider value={state}>\n <PanelActionsContext.Provider value={actions}>\n {children}\n </PanelActionsContext.Provider>\n </PanelStateContext.Provider>\n );\n};\n\n/**\n * React hook to retrieve the active floating/drawer panels state.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelState = (): PanelState => {\n const ctx = useContext(PanelStateContext);\n if (!ctx) throw new Error('usePanelState must be used within PanelProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve actions enabling drawer toggles and modal push actions.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelActions = (): PanelActions => {\n const ctx = useContext(PanelActionsContext);\n if (!ctx) throw new Error('usePanelActions must be used within PanelProvider');\n return ctx;\n};\n","import React, { useEffect, useRef } from 'react';\nimport { useFormContainer } from '../components/FormContainerContext';\nimport { useFormatMessage, usePredefinedMessages } from '../components/WindowManagerContext';\n\n/**\n * Props for the {@link ConfirmationForm} component.\n */\nexport interface ConfirmationFormProps {\n /** Optional custom title text or localizable descriptor for the dialog container. */\n title?: string | { id: string; defaultMessage?: string; values?: any };\n /** Main message text or localizable descriptor to display. */\n message: string | { id: string; defaultMessage?: string; values?: any };\n /** Optional auxiliary top alert notification text. */\n alert?: string;\n /** Type style classification for the alert notice banner. */\n alertType?: 'info' | 'warning' | 'success' | 'danger';\n /** If true, changes action button labels to 'Yes' and 'No' instead of 'OK' and 'Cancel'. */\n useYesNoTitles?: boolean;\n /** Callback fired when the user selects the confirm button. */\n onOK?: () => void;\n /** Callback fired when the user selects the cancel button. */\n onCancel?: () => void;\n}\n\n/**\n * ConfirmationForm component renders a standard dialog content layout,\n * allowing users to confirm actions or abort them. Exposes action callbacks.\n */\nexport const ConfirmationForm: React.FC<ConfirmationFormProps> = ({\n title,\n message,\n alert,\n alertType = 'info',\n useYesNoTitles = false,\n onOK,\n onCancel,\n}) => {\n const { requestClose, setIcon, setTitle } = useFormContainer();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const confirmButtonRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (title) {\n const resolvedTitle = typeof title === 'string' ? title : formatMessage(title);\n setTitle(resolvedTitle);\n }\n \n if (setIcon) {\n setIcon(<span>❓</span>);\n }\n }, [title, setTitle, setIcon, formatMessage]);\n\n useEffect(() => {\n confirmButtonRef.current?.focus();\n }, []);\n\n const resolvedMessage = typeof message === 'string' ? message : formatMessage(message);\n\n const cancelLabel = useYesNoTitles\n ? formatMessage(predefinedMessages.no)\n : formatMessage(predefinedMessages.cancel);\n\n const confirmLabel = useYesNoTitles\n ? formatMessage(predefinedMessages.yes)\n : formatMessage(predefinedMessages.ok);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onOK?.();\n requestClose();\n };\n\n const handleCancel = () => {\n onCancel?.();\n requestClose();\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"confirmation-form-body\">\n {alert && (\n <div className={`confirmation-alert confirmation-alert-${alertType}`}>\n <span>ℹ️</span>\n <span>{alert}</span>\n </div>\n )}\n\n <div style={{ fontSize: '0.9rem', color: 'inherit', lineHeight: 1.5 }}>\n {resolvedMessage}\n </div>\n\n <hr style={{ marginTop: '0.5rem', marginBottom: '0.5rem', opacity: 0.1 }} />\n\n <div className=\"confirmation-actions\">\n <button\n type=\"button\"\n className=\"dw-btn dw-btn-sm dw-btn-outline\"\n onClick={handleCancel}\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n className=\"dw-btn dw-btn-sm dw-btn-primary\"\n ref={confirmButtonRef}\n >\n {confirmLabel}\n </button>\n </div>\n </form>\n );\n};\n\nexport default ConfirmationForm;\n","import type { ComponentType } from 'react';\nimport { PanelRegistryClass } from './components/PanelRegistry';\nimport type { PanelRegistryEntry } from './components/PanelRegistry';\nimport type { WindowActions, MessageFormatter, ContextMenuPredefinedMessage } from './components/WindowManagerContext';\n\n/** Per-panel definition supplied to WorkspaceClient constructor. */\nexport interface PanelDefinition {\n component: ComponentType<any>;\n defaultOptions?: PanelRegistryEntry['defaultOptions'];\n}\n\n/** Configuration object accepted by the WorkspaceClient constructor. */\nexport interface WorkspaceClientConfig {\n /**\n * Declarative panel catalog. Replaces imperative PanelRegistry.register() calls.\n * Keys are the component identifiers used in openPanel() and serialised layouts.\n */\n panels?: Record<string, PanelDefinition>;\n /**\n * Serialised layout produced by a previous saveLayout() call.\n * Pass null or omit to start with an empty canvas.\n */\n initialState?: string | null;\n /** Custom i18n formatter for all internal strings. */\n formatMessage?: MessageFormatter;\n /** Override any subset of the built-in predefined message catalog. */\n predefinedMessages?: Record<string, ContextMenuPredefinedMessage>;\n /** Initial layout direction. */\n dir?: 'ltr' | 'rtl';\n}\n\n/**\n * WorkspaceClient is the central configuration and imperative API object for\n * react-dockable-desktop. Create one instance outside the React tree and pass\n * it to <WindowManagerProvider client={client}>.\n *\n * Pattern: TanStack QueryClient / Redux store — configuration and imperative\n * access live on the client; rendering is delegated to the thin React provider.\n *\n * @example\n * const workspace = new WorkspaceClient({\n * panels: {\n * map: { component: MapPanel },\n * editor: { component: EditorPanel, defaultOptions: { title: 'Code Editor' } },\n * },\n * initialState: localStorage.getItem('layout'),\n * });\n *\n * <WindowManagerProvider client={workspace}>\n * <WindowManager />\n * </WindowManagerProvider>\n *\n * // Imperative access from anywhere:\n * workspace.saveLayout();\n * workspace.openPanel('map', 'map');\n */\nexport class WorkspaceClient {\n /** Scoped panel registry — fully independent from the global singleton. */\n readonly registry: PanelRegistryClass;\n\n /** Serialised layout to restore on mount, or null to start with an empty canvas. */\n readonly initialState: string | null;\n\n /** Non-rendering configuration forwarded to the provider. */\n readonly config: Pick<WorkspaceClientConfig, 'formatMessage' | 'predefinedMessages' | 'dir'>;\n\n private _actions: WindowActions | null = null;\n\n constructor(config: WorkspaceClientConfig = {}) {\n this.registry = new PanelRegistryClass();\n this.initialState = config.initialState ?? null;\n this.config = {\n formatMessage: config.formatMessage,\n predefinedMessages: config.predefinedMessages,\n dir: config.dir,\n };\n\n if (config.panels) {\n for (const [id, def] of Object.entries(config.panels)) {\n this.registry.register(id, def.component, def.defaultOptions);\n }\n }\n }\n\n /** @internal Called by WindowManagerProvider after mount. */\n _connect(actions: WindowActions): void {\n this._actions = actions;\n }\n\n /** @internal Called by WindowManagerProvider on unmount. */\n _disconnect(): void {\n this._actions = null;\n }\n\n /** True while the provider is mounted and React state is accessible. */\n get isConnected(): boolean {\n return this._actions !== null;\n }\n\n // ── Forwarding methods — mirrors the WindowActions interface ──────────────\n\n saveLayout(): string { return this._actions?.saveLayout() ?? ''; }\n loadLayout(json: string): void { this._actions?.loadLayout(json); }\n\n openPanel(...args: Parameters<WindowActions['openPanel']>): void {\n this._actions?.openPanel(...args);\n }\n closePanel(id: string): void { this._actions?.closePanel(id); }\n minimizePanel(id: string): void { this._actions?.minimizePanel(id); }\n restorePanel(id: string): void { this._actions?.restorePanel(id); }\n\n floatPanel(...args: Parameters<WindowActions['floatPanel']>): void {\n this._actions?.floatPanel(...args);\n }\n dockPanel(...args: Parameters<WindowActions['dockPanel']>): void {\n this._actions?.dockPanel(...args);\n }\n maximizePanel(id: string): void { this._actions?.maximizePanel(id); }\n bringToFront(id: string): void { this._actions?.bringToFront(id); }\n\n setDirection(dir: 'ltr' | 'rtl'): void { this._actions?.setDirection(dir); }\n\n publish(event: string, data: unknown): void { this._actions?.publish(event, data); }\n subscribe(event: string, callback: (data: unknown) => void): () => void {\n return this._actions?.subscribe(event, callback) ?? (() => {});\n }\n}\n","import React, { useCallback, useRef, useEffect, useState, useMemo } from 'react';\nimport { usePanelState, usePanelActions } from './PanelProviderContext';\nimport { FormContainerProvider, type FormContainerContract, type CloseOptions } from './FormContainerContext';\nimport type { PanelInstance, ModalOptions, PanelTitle } from './PanelProviderContext';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\n\n/**\n * Interface representing props for the internal {@link ModalRenderer} component.\n */\ninterface ModalRendererProps {\n /** The panel instance containing component structure, state, and option flags. */\n modal: PanelInstance;\n /** The 0-based depth index of the modal within the active stack. */\n index: number;\n /** True if this modal is currently at the top of the stack. */\n isTopmost: boolean;\n}\n\n/**\n * ModalRenderer component renders a single modal window wrapped inside\n * the FormContainerProvider context, enabling subcomponents to request closes and set dirty states.\n */\nconst ModalRenderer: React.FC<ModalRendererProps> = ({ modal, index, isTopmost }) => {\n const { close, openModal, updateInstance, setDirty } = usePanelActions();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const { dir } = useWindowManagerState();\n const { modalClass, modalBodyClass } = useStyleClasses();\n const closeHandlerRef = useRef<(() => boolean | Promise<boolean>) | null>(null);\n\n const { id, Component, props, options, dirty, dirtyOptions } = modal;\n const modalOptions = options as ModalOptions;\n\n const [icon, setIconState] = useState<React.ReactNode>(modalOptions.icon || null);\n\n const optionsRef = useRef(modalOptions);\n optionsRef.current = modalOptions;\n\n const baseTitle = formatLabel(modalOptions.title, formatMessage);\n\n const handleClose = useCallback(async (options?: CloseOptions) => {\n if (options?.force) {\n close(id);\n return;\n }\n\n if (closeHandlerRef.current) {\n const canClose = await closeHandlerRef.current();\n if (!canClose) return;\n close(id);\n return;\n }\n\n if (dirty) {\n openModal(\n ConfirmationForm,\n {\n title: dirtyOptions?.title || predefinedMessages.unsavedChangesTitle,\n message: dirtyOptions?.message || {\n id: predefinedMessages.unsavedChangesMessage.id,\n defaultMessage: predefinedMessages.unsavedChangesMessage.defaultMessage,\n values: { title: baseTitle }\n },\n alert: dirtyOptions?.alert,\n alertType: dirtyOptions?.alertType || 'danger',\n useYesNoTitles: true,\n onOK: () => close(id),\n },\n { size: 'small' }\n );\n return;\n }\n\n close(id);\n }, [close, openModal, id, dirty, dirtyOptions, baseTitle, predefinedMessages]);\n\n const handleSetDirty = useCallback((dirty: boolean, options?: any) => setDirty(id, dirty, options), [setDirty, id]);\n const handleSetTitle = useCallback((title: PanelTitle) => updateInstance(id, { options: { ...optionsRef.current, title } }), [updateInstance, id]);\n const handleSetIcon = useCallback((newIcon: React.ReactNode) => setIconState(newIcon), []);\n const handleOnCloseRequested = useCallback((handler: () => boolean | Promise<boolean>) => {\n closeHandlerRef.current = handler;\n return () => { closeHandlerRef.current = null; };\n }, []);\n\n const contract: FormContainerContract = useMemo(() => ({\n requestClose: handleClose,\n setDirty: handleSetDirty,\n setTitle: handleSetTitle,\n setIcon: handleSetIcon,\n onCloseRequested: handleOnCloseRequested,\n containerType: 'modal',\n instanceId: id,\n }), [handleClose, handleSetDirty, handleSetTitle, handleSetIcon, handleOnCloseRequested, id]);\n\n const displayTitle = dirty ? `${baseTitle} *` : baseTitle;\n\n const sizeClass = modalOptions.size ? `v2-modal-size-${modalOptions.size}` : 'v2-modal-size-auto';\n const showCloseButton = modalOptions.closable !== false;\n\n useEffect(() => {\n if (!isTopmost || !showCloseButton) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n handleClose();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [handleClose, showCloseButton, isTopmost]);\n\n const baseZIndex = 10000;\n const modalZIndex = baseZIndex + (index * 10);\n\n return (\n <div className=\"v2-modal-overlay\" style={{ zIndex: modalZIndex }} dir={dir}>\n <div className=\"v2-modal-curtain\" onClick={showCloseButton ? () => handleClose() : undefined} />\n <div className={`v2-modal-window ${sizeClass} ${modalClass ?? ''}`}>\n <div className=\"v2-modal-header\">\n {icon && <div className=\"v2-modal-icon\">{icon}</div>}\n <h4 className=\"v2-modal-title\">{displayTitle}</h4>\n {showCloseButton && (\n <button\n className=\"v2-modal-close-button\"\n onClick={() => handleClose()}\n title={formatMessage(predefinedMessages.closeTooltip)}\n type=\"button\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n <div className={`v2-modal-body ${modalBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\n/**\n * ModalStackRenderer component acts as the global container rendering\n * all active stacked modal windows in the workspace.\n */\nexport const ModalStackRenderer: React.FC = () => {\n const { modals } = usePanelState();\n\n if (modals.length === 0) return null;\n\n return (\n <>\n {modals.map((modal, index) => (\n <ModalRenderer\n key={modal.id}\n modal={modal}\n index={index}\n isTopmost={index === modals.length - 1}\n />\n ))}\n </>\n );\n};\n\nexport default ModalStackRenderer;\n","import React, { useCallback, useRef, useEffect, useState, useMemo } from 'react';\nimport { usePanelState, usePanelActions } from './PanelProviderContext';\nimport { FormContainerProvider, type FormContainerContract, type CloseOptions } from './FormContainerContext';\nimport type { PanelInstance, SidePanelOptions, PanelTitle } from './PanelProviderContext';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\n\n/**\n * Props for the internal {@link SidePanelRendererItem} component.\n */\ninterface SidePanelRendererItemProps {\n /** The panel instance containing metadata, component type, and rendering state. */\n panel: PanelInstance;\n /** Floating anchor edge side for the drawer panel. */\n position: 'left' | 'right';\n /** Default width applied if no panel override configuration is provided. */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRendererItem component renders an individual left or right drawer panel instance\n * wrapped inside the FormContainerProvider context. Handles dirty state verification before close.\n */\nconst SidePanelRendererItem: React.FC<SidePanelRendererItemProps> = ({ panel, position, defaultWidth }) => {\n const { close, openModal, updateInstance, setDirty, registerCloseHandler, unregisterCloseHandler } = usePanelActions();\n const { modals } = usePanelState();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const { dir } = useWindowManagerState();\n const { sidePanelClass, sidePanelBodyClass } = useStyleClasses();\n const closeHandlerRef = useRef<(() => boolean | Promise<boolean>) | null>(null);\n\n const { id, Component, props, options, dirty, dirtyOptions } = panel;\n const panelOptions = options as SidePanelOptions;\n const [icon, setIconState] = useState<React.ReactNode>(panelOptions.icon || null);\n\n const optionsRef = useRef(panelOptions);\n optionsRef.current = panelOptions;\n\n const baseTitle = formatLabel(panelOptions.title, formatMessage);\n\n const handleClose = useCallback(async (options?: CloseOptions) => {\n if (options?.force) {\n close(id);\n return;\n }\n\n if (closeHandlerRef.current) {\n const canClose = await closeHandlerRef.current();\n if (!canClose) return;\n close(id);\n return;\n }\n\n if (dirty) {\n openModal(\n ConfirmationForm,\n {\n title: dirtyOptions?.title || predefinedMessages.unsavedChangesTitle,\n message: dirtyOptions?.message || {\n id: predefinedMessages.unsavedChangesMessage.id,\n defaultMessage: predefinedMessages.unsavedChangesMessage.defaultMessage,\n values: { title: baseTitle }\n },\n alert: dirtyOptions?.alert,\n alertType: dirtyOptions?.alertType || 'danger',\n useYesNoTitles: true,\n onOK: () => close(id),\n },\n { size: 'small' }\n );\n return;\n }\n\n close(id);\n }, [close, openModal, id, dirty, dirtyOptions, baseTitle, predefinedMessages]);\n\n const canClose = useCallback(async (): Promise<boolean> => {\n if (closeHandlerRef.current) {\n return await closeHandlerRef.current();\n }\n return !dirty;\n }, [dirty]);\n\n useEffect(() => {\n registerCloseHandler(id, canClose);\n return () => unregisterCloseHandler(id);\n }, [id, canClose, registerCloseHandler, unregisterCloseHandler]);\n\n const handleSetDirty = useCallback((dirty: boolean, options?: any) => setDirty(id, dirty, options), [setDirty, id]);\n const handleSetTitle = useCallback((title: PanelTitle) => updateInstance(id, { options: { ...optionsRef.current, title } }), [updateInstance, id]);\n const handleSetIcon = useCallback((newIcon: React.ReactNode) => setIconState(newIcon), []);\n const handleOnCloseRequested = useCallback((handler: () => boolean | Promise<boolean>) => {\n closeHandlerRef.current = handler;\n return () => { closeHandlerRef.current = null; };\n }, []);\n\n const contract: FormContainerContract = useMemo(() => ({\n requestClose: handleClose,\n setDirty: handleSetDirty,\n setTitle: handleSetTitle,\n setIcon: handleSetIcon,\n onCloseRequested: handleOnCloseRequested,\n containerType: position === 'left' ? 'left-panel' : 'right-panel',\n instanceId: id,\n }), [handleClose, handleSetDirty, handleSetTitle, handleSetIcon, handleOnCloseRequested, position, id]);\n\n const displayTitle = dirty ? `${baseTitle} *` : baseTitle;\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && modals.length === 0) {\n handleClose();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [handleClose, modals.length]);\n\n const width = panelOptions.width || defaultWidth || 400;\n const widthStyle = typeof width === 'number' ? `${width}px` : width;\n\n return (\n <div \n className={`v2-side-panel v2-side-panel-${position} v2-side-panel-visible ${sidePanelClass ?? ''}`}\n style={{ width: widthStyle }}\n dir={dir}\n >\n <div className=\"v2-side-panel-window\">\n <div className=\"v2-side-panel-header\">\n {icon && <div className=\"v2-side-panel-icon\">{icon}</div>}\n <h4 className=\"v2-side-panel-title\">{displayTitle}</h4>\n <button\n className=\"v2-side-panel-close-button\"\n onClick={() => handleClose()}\n title={formatMessage(predefinedMessages.closeTooltip)}\n type=\"button\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div className={`v2-side-panel-body ${sidePanelBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\nexport interface SidePanelRendererProps {\n /**\n * Default panel width applied when openLeftPanel/openRightPanel do not specify one.\n * Accepts a number (treated as px) or any CSS width string (e.g. '40vw').\n * Falls back to 400px if omitted.\n */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRenderer component acts as the global container rendering both\n * left and right side drawers if they are currently active.\n */\nexport const SidePanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel, rightPanel } = usePanelState();\n return (\n <>\n {leftPanel && <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />}\n {rightPanel && <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />}\n </>\n );\n};\n\n/**\n * LeftPanelRenderer component renders ONLY the left side drawer if it is currently active.\n */\nexport const LeftPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel } = usePanelState();\n if (!leftPanel) return null;\n return <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />;\n};\n\n/**\n * RightPanelRenderer component renders ONLY the right side drawer if it is currently active.\n */\nexport const RightPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { rightPanel } = usePanelState();\n if (!rightPanel) return null;\n return <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />;\n};\n\nexport default SidePanelRenderer;\n","/**\n * @file Sidebar.tsx\n * @description Sidebar navigation strip and drawer container component.\n * Supports eager/lazy mounting, state preservation (display: none), and positioning (left/right).\n */\n\nimport React, {\n useState,\n useEffect,\n useRef,\n useCallback,\n useImperativeHandle,\n forwardRef,\n} from 'react';\nimport { useFormatMessage, usePredefinedMessages } from './WindowManagerContext';\n\n\n// ==========================================\n// Types\n// ==========================================\n\n/**\n * Per-tab configuration supplied by the consuming application.\n */\nexport interface SidebarTab {\n id: string;\n label: string;\n icon: React.ReactNode;\n /**\n * Mount immediately when the Sidebar first renders, not on first user click.\n * Implies `preserveState: true`.\n * Use when other parts of the app need to interact with the panel before\n * the user has opened it (e.g. push data into a context, warm up a WebGL map).\n * Default: false\n */\n eagerMount?: boolean;\n /**\n * Once mounted for the first time, keep the component alive in the DOM\n * behind `display: none` when closed instead of unmounting it.\n * Use for panels with expensive local state (long forms, WebGL scenes, etc.).\n * Ignored when `eagerMount` is true (eagerly mounted panels are always preserved).\n * Default: false\n */\n preserveState?: boolean;\n /**\n * Called to obtain the drawer content for this tab.\n * @param tabId - the id of this tab\n * @param onClose - call to collapse the sidebar drawer\n * @param onOpen - call to expand the drawer and select this tab programmatically\n * (useful when the panel itself detects it has new data to show)\n */\n renderContent: (tabId: string, onClose: () => void, onOpen: () => void) => React.ReactNode;\n}\n\nexport interface SidebarProps {\n /** Which side the tab strip and drawer appear on. Default: 'right' */\n position?: 'left' | 'right';\n tabs: SidebarTab[];\n /** Width of the open drawer. Default: '220px' */\n drawerWidth?: string;\n /** Controlled active tab id. Leave undefined to use internal state. */\n activeTabId?: string | null;\n /** Called when the active tab changes in uncontrolled mode. */\n onActiveTabChange?: (tabId: string | null) => void;\n /** Main workspace content, rendered between the strip and drawer (or around them). */\n children?: React.ReactNode;\n}\n\n/**\n * Imperative handle exposed by <Sidebar ref={...}> via forwardRef.\n * Allows external components (outside the sidebar tree) to control\n * which tab is open without prop drilling.\n */\nexport interface SidebarHandle {\n /** Expand the drawer and activate the tab with the given id. */\n openTab: (tabId: string) => void;\n /** Collapse the drawer (equivalent to clicking the active tab icon). */\n closeDrawer: () => void;\n /** Returns the currently active tab id, or null if the drawer is collapsed. */\n getActiveTab: () => string | null;\n}\n\n// ==========================================\n// Component\n// ==========================================\n\n/**\n * Sidebar component rendering a tab strip and a collapsible content drawer.\n * Supports imperative method bindings like openTab and closeDrawer via forwardRef.\n */\nexport const Sidebar = forwardRef<SidebarHandle, SidebarProps>(function Sidebar(\n {\n position = 'right',\n tabs,\n drawerWidth = '220px',\n activeTabId: controlledActiveTabId,\n onActiveTabChange,\n children,\n },\n ref\n) {\n const isControlled = controlledActiveTabId !== undefined;\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n\n // Internal active tab state (used when uncontrolled)\n const [internalActiveTabId, setInternalActiveTabId] = useState<string | null>(null);\n\n // The effective active tab id — either from props (controlled) or internal state\n const activeTabId = isControlled ? controlledActiveTabId : internalActiveTabId;\n\n // Track which tabs have been mounted at least once\n // Pre-populate with all eagerMount tabs\n const [mountedTabIds, setMountedTabIds] = useState<Set<string>>(() => {\n const initial = new Set<string>();\n for (const tab of tabs) {\n if (tab.eagerMount) initial.add(tab.id);\n }\n return initial;\n });\n\n // When tabs change (e.g. new eagerMount tabs added), mount them immediately\n useEffect(() => {\n const newEager = tabs.filter(t => t.eagerMount && !mountedTabIds.has(t.id));\n if (newEager.length > 0) {\n setMountedTabIds(prev => {\n const next = new Set(prev);\n for (const tab of newEager) next.add(tab.id);\n return next;\n });\n }\n }, [tabs]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Stable ref to active tab for imperative handle\n const activeTabIdRef = useRef<string | null>(activeTabId ?? null);\n useEffect(() => {\n activeTabIdRef.current = activeTabId ?? null;\n }, [activeTabId]);\n\n const setActiveTabId = useCallback(\n (id: string | null) => {\n if (isControlled) {\n onActiveTabChange?.(id);\n } else {\n setInternalActiveTabId(id);\n onActiveTabChange?.(id);\n }\n },\n [isControlled, onActiveTabChange]\n );\n\n // Expose imperative handle\n useImperativeHandle(\n ref,\n () => ({\n openTab: (tabId: string) => setActiveTabId(tabId),\n closeDrawer: () => setActiveTabId(null),\n getActiveTab: () => activeTabIdRef.current,\n }),\n [setActiveTabId]\n );\n\n const handleTabClick = (tabId: string) => {\n setActiveTabId(activeTabId === tabId ? null : tabId);\n };\n\n const handleClose = useCallback(() => setActiveTabId(null), [setActiveTabId]);\n\n // On first open of a non-eager tab, add it to mounted set\n useEffect(() => {\n if (activeTabId && !mountedTabIds.has(activeTabId)) {\n setMountedTabIds(prev => {\n const next = new Set(prev);\n next.add(activeTabId);\n return next;\n });\n }\n }, [activeTabId, mountedTabIds]);\n\n // On close of a standard tab (neither eagerMount nor preserveState), unmount it\n useEffect(() => {\n if (activeTabId !== null) return; // drawer just opened or is still open\n setMountedTabIds(prev => {\n let changed = false;\n const next = new Set(prev);\n for (const id of prev) {\n const tab = tabs.find(t => t.id === id);\n if (tab && !tab.eagerMount && !tab.preserveState) {\n next.delete(id);\n changed = true;\n }\n }\n return changed ? next : prev;\n });\n }, [activeTabId, tabs]);\n\n // ---- Render helpers ----\n\n const tabStrip = (\n <div className={`sidebar-tabs-strip ${position}`} style={{ width: '56px', height: '100%' }}>\n {tabs.map(tab => {\n const isActive = activeTabId === tab.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => handleTabClick(tab.id)}\n className={`sidebar-tab-btn ${isActive ? 'active' : ''}`}\n title={tab.label}\n aria-pressed={isActive}\n >\n {tab.icon}\n </button>\n );\n })}\n </div>\n );\n\n const drawer = (\n <div\n className={`sidebar-content-drawer h-100 ${position}`}\n style={{\n width: activeTabId ? drawerWidth : '0px',\n minWidth: activeTabId ? drawerWidth : '0px',\n overflow: 'hidden',\n flexShrink: 0,\n }}\n >\n {/* Render all mounted tabs; only the active one is visible */}\n {tabs.map(tab => {\n const isMounted = mountedTabIds.has(tab.id);\n if (!isMounted) return null;\n\n const isCurrent = activeTabId === tab.id;\n\n // Stable onOpen per tab id\n const onOpen = () => setActiveTabId(tab.id);\n\n return (\n <div\n key={tab.id}\n style={{\n display: isCurrent ? 'flex' : 'none',\n flexDirection: 'column',\n height: '100%',\n width: '100%',\n }}\n >\n {/* Drawer header */}\n <div className=\"sidebar-drawer-header\">\n <span className=\"sidebar-header-title\">{tab.label}</span>\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"sidebar-close-btn\"\n title={formatMessage(predefinedMessages.closePanelTooltip)}\n aria-label={formatMessage(predefinedMessages.closePanelTooltip)}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n {/* Drawer body — consumer-supplied content */}\n <div className=\"sidebar-drawer-body\">\n {tab.renderContent(tab.id, handleClose, onOpen)}\n </div>\n </div>\n );\n })}\n </div>\n );\n\n return (\n <>\n {position === 'left' && tabStrip}\n {position === 'left' && drawer}\n {children}\n {position === 'right' && drawer}\n {position === 'right' && tabStrip}\n </>\n );\n});\n\nexport default Sidebar;\n"],"mappings":"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","names":["React","useState","useRef","useEffect","createPortal","createContext","useContext","useState","useRef","useMemo","useCallback","useEffect","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","jsx","WindowStateContext","createContext","WindowActionsContext","WindowI18nContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","useContext","RegistryContext","PanelRegistry","useRegistry","PanelEventBus","event","callback","cb","data","EMPTY_LEAF","parseInitialState","json","parsed","WindowManagerProvider","children","client","formatMessage","predefinedMessages","dirProp","modalClass","modalBodyClass","sidePanelClass","sidePanelBodyClass","windowClass","windowBodyClass","registry","useRef","effectiveFormatMessage","effectivePredefinedMessages","effectiveDir","state","setState","useState","stateRef","closeGuardsRef","mergedMessages","useMemo","eventBusRef","maxZRef","subscribe","useCallback","publish","getCascadedPosition","fav","currentFloating","x","y","width","height","isOverlapping","pos","w","wx","wy","attempts","viewW","viewH","bringToFront","id","z","prev","panel","selectActiveInTree","node","removePanelFromTree","idx","panels","p","activePanelId","updatedLeaf","sizes","sum","a","s","addPanelToLeaf","leafId","panelId","c","findFirstLeafId","child","openPanel","component","options","exists","entry","title","target","favPos","nextMinimized","m","cascaded","firstLeaf","newPanelInfo","nextPanels","stickyRight","stickyBottom","winW","winH","initialX","initialY","GAP","closePanel","cleanRoot","registerCloseGuard","guard","unregisterCloseGuard","setPanelDirty","dirty","updatePanelTitle","requestClosePanel","minimizePanel","lastFloatingRect","lastLeafId","win","findLeafForPanel","res","restorePanel","leafExists","targetId","parentLeafExists","canDrag","targetLeafId","floatPanel","rect","dockPanel","nextFloating","splitLeafInTree","position","newLeaf","setDraggedPanelId","dockPanelToGroup","newRoot","dockPanelToWorkspaceEdge","orientation","movePanelOrder","targetIndex","insertInLeaf","remaining","index","newPanels","closeLeafGroup","removeLeafFromTree","b","maximizePanel","updateSplitSizes","path","updateInTree","depth","i","updateFloatingPosition","updates","saveLayout","loadLayout","layoutJson","firstActive","e","setActivePanel","setDirection","dir","useEffect","actions","defaultFormatMessage","msg","text","key","value","styleClasses","useWindowManagerState","ctx","useWindowManagerActions","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","isElementRtl","el","closestDirEl","JsonContextMenu","createContext","useContext","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","createContext","useContext","useState","useCallback","useMemo","useRef","jsx","idCounter","generateId","closeHandlers","initialState","PanelStateContext","PanelActionsContext","PanelProvider","children","state","setState","stateRef","registerCloseHandler","id","handler","unregisterCloseHandler","openLeftPanel","Component","props","options","currentPanel","instance","s","openRightPanel","openModal","formTitle","modalOptions","close","closeAll","closeAllModals","getInstance","m","updateInstance","updates","setDirty","dirty","actions","usePanelState","ctx","usePanelActions","useEffect","useRef","jsx","jsxs","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","useRef","useEffect","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","Fragment","jsx","jsxs","domCache","hiddenContainerId","DefaultGridIcon","getOrCreateDomCacheElement","id","el","renderPanelContent","componentKey","registry","registryEntry","Component","activePanelDimensions","panelLifecycleRegistry","getOrCreateLifecycleRegistry","panelId","entry","PreservedDOMWrapper","hostRef","useRef","useEffect","host","cachedEl","resizeObserver","entries","width","height","lifecycle","h","hiddenContainer","PreviewDOMWrapper","state","useWindowManagerState","useRegistry","formatMessage","useFormatMessage","panel","regEntry","disableLivePreview","lastSize","origW","origH","scale","displayW","displayH","rawTitle","title","formatLabel","initialChar","FormContainerProviderWrapper","children","requestClosePanel","setPanelDirty","registerCloseGuard","unregisterCloseGuard","updatePanelTitle","useWindowManagerActions","isMin","m","prevMinRef","contract","React","options","dirty","handler","reg","FormContainerProvider","WorkspaceGrid","node","path","onTabRightClick","activeDropZone","onHoverDropZone","onTabDragStart","hoveredTab","onTabHover","defaultPanelIcon","onRequestClosePanel","updateSplitSizes","LeafGroup","isRow","handleResizerMouseDown","idx","e","startOffset","startSizes","resizerEl","parentEl","parentSize","handleMouseMove","moveEvent","deltaPercentage","newSizes","handleMouseUp","child","size","leaf","openPanel","closeLeafGroup","setActivePanel","messages","usePredefinedMessages","windowClass","windowBodyClass","useStyleClasses","selectTab","isSelected","isGloballyActive","isHovered","isLast","isHoveredEmpty","sideClass","rect","side","WindowManager","skin","restorePanel","minimizePanel","maximizePanel","updateFloatingPosition","bringToFront","floatPanel","setDraggedPanelId","dockPanelToGroup","movePanelOrder","dockPanelToWorkspaceEdge","setDirection","openModal","usePanelActions","handleRequestClose","customOpts","resolve","opts","baseTitle","ConfirmationForm_default","taskbarRef","contextMenuRef","hoveredMinimized","setHoveredMinimized","useState","minimizedTooltipTimeoutRef","isContextMenuOpen","setIsContextMenuOpen","setActiveDropZone","activeDropZoneRef","dragPos","setDragPos","activeEdgeDrop","setActiveEdgeDropState","activeEdgeDropRef","setActiveEdgeDrop","val","setHoveredTab","hoveredTabRef","handleTabHover","leafId","index","handleHoverDropZone","position","handleTabDragStart","startX","startY","dragStarted","dx","dy","handleMouseUpWrapper","dropZone","targetTab","edgeDrop","targetIndex","handleTabRightClick","items","handleMinimizedRightClick","keys","cachedId","handleWindowBlur","workspaceRef","workspaceSize","setWorkspaceSize","observer","updateDir","isRtl","isElementRtl","closestDir","viewW","viewH","w","winW","winH","winX","winY","newWidth","newHeight","newX","newY","changed","GAP","maxX","maxY","handleMouseDownGlobal","target","windowEl","winId","panelEl","startDrag","floatingWin","startPosX","startPosY","startResize","startW","startH","dw","dh","parsedX","parsedY","parsedW","parsedH","isRightSnapped","isBottomSnapped","scrollTaskbar","direction","amount","currentColorScheme","setCurrentColorScheme","updateThemeState","activeTheme","obs","isMaximized","isDragged","isFocused","isRight","isBottom","icon","createPortal","targetEl","JsonContextMenu","WindowManager_default","WorkspaceClient","config","PanelRegistryClass","id","def","actions","json","args","dir","event","data","callback","useCallback","useRef","useEffect","useState","useMemo","Fragment","jsx","jsxs","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","sizeClass","showCloseButton","useEffect","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","useCallback","useRef","useEffect","useState","useMemo","Fragment","jsx","jsxs","SidePanelRendererItem","panel","position","defaultWidth","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","canClose","useEffect","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","handleKeyDown","e","width","widthStyle","FormContainerProvider","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","useState","useEffect","useRef","useCallback","useImperativeHandle","forwardRef","Fragment","jsx","jsxs","Sidebar","forwardRef","position","tabs","drawerWidth","controlledActiveTabId","onActiveTabChange","children","ref","isControlled","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","internalActiveTabId","setInternalActiveTabId","useState","activeTabId","mountedTabIds","setMountedTabIds","initial","tab","useEffect","newEager","t","prev","next","activeTabIdRef","useRef","setActiveTabId","useCallback","id","useImperativeHandle","tabId","handleTabClick","handleClose","changed","tabStrip","isActive","drawer","isCurrent","onOpen"]}
|