react-dockable-desktop 1.3.0 → 2.0.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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 index.ts\n * @description Core entry point for react-dockable-desktop.\n * Exports public window manager components, contexts, hooks, type definitions, sidebar layouts, and overlay renderers.\n */\n\n// Core Components and Layouts\nexport { default as WindowManager } from './components/WindowManager';\nexport { PanelRegistry } from './components/PanelRegistry';\nexport type { PanelRegistryEntry } from './components/PanelRegistry';\n\n// WorkspaceClient — primary configuration and imperative API object\nexport { WorkspaceClient } from './WorkspaceClient';\nexport type { WorkspaceClientConfig, PanelDefinition } from './WorkspaceClient';\n\n// State Actions and Context Providers\nexport {\n WindowManagerProvider,\n useWindowManagerState,\n useWindowManagerActions,\n useFormatMessage,\n formatLabel,\n usePanelContext,\n usePredefinedMessages,\n defaultPredefinedMessages,\n useStyleClasses\n} from './components/WindowManagerContext';\n\n// TypeScript Types and Interfaces\nexport type {\n SplitOrientation,\n LayoutGridNode,\n LayoutLeafNode,\n LayoutNode,\n FloatingWindow,\n PanelInfo,\n WindowState,\n WindowActions,\n ContextMenuPredefinedMessage,\n MessageFormatter,\n PredefinedMessageKey,\n StyleClasses\n} from './components/WindowManagerContext';\n\n// Form Container Context Contract\nexport {\n FormContainerContext,\n FormContainerProvider,\n useFormContainer\n} from './components/FormContainerContext';\n\nexport type {\n CloseOptions,\n FormContainerContract\n} from './components/FormContainerContext';\n\n// Side Panels and Modal Stack Context\nexport {\n PanelProvider,\n usePanelState,\n usePanelActions\n} from './components/PanelProviderContext';\n\nexport type {\n PanelInstanceId,\n PanelTitle,\n SidePanelOptions,\n ModalOptions,\n PanelInstance,\n PanelState,\n PanelActions\n} from './components/PanelProviderContext';\n\n// Overlay Renderers\nexport { default as ModalStackRenderer } from './components/ModalStackRenderer';\nexport {\n default as SidePanelRenderer,\n LeftPanelRenderer,\n RightPanelRenderer\n} from './components/SidePanelRenderer';\nexport type { SidePanelRendererProps } from './components/SidePanelRenderer';\n\n// Reusable Forms\nexport { default as ConfirmationForm } from './forms/ConfirmationForm';\nexport type { ConfirmationFormProps } from './forms/ConfirmationForm';\n\n// Sidebar\nexport { Sidebar } from './components/Sidebar';\nexport type { SidebarTab, SidebarProps, SidebarHandle } from './components/Sidebar';\n\n","/**\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":["index_exports","__export","ConfirmationForm_default","FormContainerContext","FormContainerProvider","LeftPanelRenderer","ModalStackRenderer_default","PanelProvider","PanelRegistry","RightPanelRenderer","SidePanelRenderer_default","Sidebar","WindowManager_default","WindowManagerProvider","WorkspaceClient","defaultPredefinedMessages","formatLabel","useFormContainer","useFormatMessage","usePanelActions","usePanelContext","usePanelState","usePredefinedMessages","useStyleClasses","useWindowManagerActions","useWindowManagerState","__toCommonJS","import_react","import_react_dom","import_react","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","import_jsx_runtime","WindowStateContext","WindowActionsContext","WindowI18nContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","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","effectiveFormatMessage","effectivePredefinedMessages","effectiveDir","state","setState","stateRef","closeGuardsRef","mergedMessages","eventBusRef","maxZRef","subscribe","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","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","firstActive","e","setActivePanel","setDirection","dir","actions","defaultFormatMessage","msg","text","key","value","styleClasses","useWindowManagerState","ctx","useWindowManagerActions","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","isElementRtl","el","closestDirEl","import_replace_react_contexify","import_styles","import_react","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","import_react","import_jsx_runtime","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","import_react","import_jsx_runtime","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","import_jsx_runtime","domCache","hiddenContainerId","DefaultGridIcon","getOrCreateDomCacheElement","id","el","renderPanelContent","componentKey","registry","registryEntry","Component","activePanelDimensions","panelLifecycleRegistry","getOrCreateLifecycleRegistry","panelId","entry","PreservedDOMWrapper","hostRef","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","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","targetEl","WindowManager_default","WorkspaceClient","config","PanelRegistryClass","id","def","actions","json","args","dir","event","data","callback","import_react","import_jsx_runtime","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","optionsRef","baseTitle","formatLabel","handleClose","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","sizeClass","showCloseButton","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","import_react","import_jsx_runtime","SidePanelRendererItem","panel","position","defaultWidth","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","optionsRef","baseTitle","formatLabel","handleClose","ConfirmationForm_default","canClose","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","handleKeyDown","e","width","widthStyle","FormContainerProvider","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","import_react","import_jsx_runtime","Sidebar","position","tabs","drawerWidth","controlledActiveTabId","onActiveTabChange","children","ref","isControlled","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","internalActiveTabId","setInternalActiveTabId","activeTabId","mountedTabIds","setMountedTabIds","initial","tab","newEager","t","prev","next","activeTabIdRef","setActiveTabId","id","tabId","handleTabClick","handleClose","changed","tabStrip","isActive","drawer","isCurrent","onOpen"]}
1
+ {"version":3,"sources":["../src/index.ts","../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 index.ts\n * @description Core entry point for react-dockable-desktop.\n * Exports public window manager components, contexts, hooks, type definitions, sidebar layouts, and overlay renderers.\n */\n\n// Core Components and Layouts\nexport { default as WindowManager } from './components/WindowManager';\nexport { PanelRegistry, PanelRegistryClass } from './components/PanelRegistry';\nexport type { PanelRegistryEntry } from './components/PanelRegistry';\n\n// WorkspaceClient — primary configuration and imperative API object\nexport { WorkspaceClient } from './WorkspaceClient';\nexport type { WorkspaceClientConfig, PanelDefinition } from './WorkspaceClient';\n\n// State Actions and Context Providers\nexport {\n WindowManagerProvider,\n useWindowManagerState,\n useWindowManagerActions,\n useRegistry,\n useFormatMessage,\n formatLabel,\n usePanelContext,\n usePredefinedMessages,\n defaultPredefinedMessages,\n useStyleClasses\n} from './components/WindowManagerContext';\n\n// TypeScript Types and Interfaces\nexport type {\n SplitOrientation,\n LayoutGridNode,\n LayoutLeafNode,\n LayoutNode,\n FloatingWindow,\n PanelInfo,\n WindowState,\n WindowActions,\n ContextMenuPredefinedMessage,\n MessageFormatter,\n PredefinedMessageKey,\n StyleClasses\n} from './components/WindowManagerContext';\n\n// Form Container Context Contract\nexport {\n FormContainerContext,\n FormContainerProvider,\n useFormContainer\n} from './components/FormContainerContext';\n\nexport type {\n CloseOptions,\n FormContainerContract\n} from './components/FormContainerContext';\n\n// Side Panels and Modal Stack Context\nexport {\n PanelProvider,\n usePanelState,\n usePanelActions\n} from './components/PanelProviderContext';\n\nexport type {\n PanelInstanceId,\n PanelTitle,\n SidePanelOptions,\n ModalOptions,\n PanelInstance,\n PanelState,\n PanelActions\n} from './components/PanelProviderContext';\n\n// Overlay Renderers\nexport { default as ModalStackRenderer } from './components/ModalStackRenderer';\nexport {\n default as SidePanelRenderer,\n LeftPanelRenderer,\n RightPanelRenderer\n} from './components/SidePanelRenderer';\nexport type { SidePanelRendererProps } from './components/SidePanelRenderer';\n\n// Reusable Forms\nexport { default as ConfirmationForm } from './forms/ConfirmationForm';\nexport type { ConfirmationFormProps } from './forms/ConfirmationForm';\n\n// Sidebar\nexport { Sidebar } from './components/Sidebar';\nexport type { SidebarTab, SidebarProps, SidebarHandle } from './components/Sidebar';\n\n","/**\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, useWindowManagerActionsInternal, 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 console.warn(\n `[react-dockable-desktop] Panel \"${id}\" references component key \"${componentKey}\" ` +\n `which is not registered. Add it to the WorkspaceClient panels config:\\n` +\n ` new WorkspaceClient({ panels: { \"${componentKey}\": { component: YourComponent } } })`\n );\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 } = useWindowManagerActionsInternal();\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, focusPanel, floatPanel, setDraggedPanelId, dockPanelToGroup, movePanelOrder, dockPanelToWorkspaceEdge, setActivePanel, setDirection } = useWindowManagerActionsInternal();\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<ReturnType<typeof setTimeout>>(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 focusPanel(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 }, [focusPanel, 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 focusPanel(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 focusPanel(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 focusPanel(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 * All layout mutation methods, event bus handles, and serialization methods\n * exposed by the `WindowManagerProvider`.\n *\n * Obtain this object via {@link useWindowManagerActions} inside a component,\n * or via {@link WorkspaceClient} methods from outside the React tree.\n *\n * @group Hooks\n * @example\n * ```tsx\n * function MyToolbar() {\n * const actions = useWindowManagerActions();\n * return <button onClick={() => actions.openPanel('map-1', 'map')}>Open Map</button>;\n * }\n * ```\n */\nexport interface WindowActions {\n /**\n * Opens a registered panel into the workspace.\n * If the panel ID is already open, the panel is focused instead of duplicated.\n * @param id - Unique instance identifier for this panel.\n * @param component - Component key registered in the panel catalog.\n * @param options - Optional display and placement overrides.\n * @example\n * ```ts\n * actions.openPanel('map-1', 'map', { title: 'Satellite View', initialTarget: 'floating' });\n * ```\n */\n openPanel: (id: string, component: string, options?: { title?: string | ContextMenuPredefinedMessage; initialTarget?: 'floating' | 'docked' | 'tabbed'; stickyRight?: boolean; stickyBottom?: boolean }) => void;\n /**\n * Closes a panel immediately, bypassing dirty-state close guards.\n * For guarded close, use {@link requestClosePanel}.\n * @param id - Panel instance ID.\n */\n closePanel: (id: string) => void;\n /**\n * Minimizes a panel to the bottom taskbar dock, preserving its layout position.\n * @param id - Panel instance ID.\n */\n minimizePanel: (id: string) => void;\n /**\n * Restores a minimized panel back to its last docked or floating position.\n * @param id - Panel instance ID.\n */\n restorePanel: (id: string) => void;\n /**\n * Detaches a docked panel, converting it to a resizable floating window.\n * @param id - Panel instance ID.\n * @param rect - Optional initial position and size for the floating window.\n */\n floatPanel: (id: string, rect?: { x: number; y: number; width: number; height: number }) => void;\n /**\n * Returns a floating window to a docked grid tab group.\n * @param id - Panel instance ID.\n * @param targetLeafId - Target leaf group ID. Defaults to the panel's last leaf.\n */\n dockPanel: (id: string, targetLeafId?: string) => void;\n /**\n * Maximizes a floating window to cover the entire workspace viewport.\n * @param id - Panel instance ID.\n */\n maximizePanel: (id: string) => void;\n /**\n * Resizes the flex split proportions of a branch node's children.\n * @param path - Index path from root to the branch node.\n * @param sizes - New proportional sizes (must sum to 1.0).\n */\n updateSplitSizes: (path: number[], sizes: number[]) => void;\n /**\n * Updates the position or size of a floating window.\n * @param id - Panel instance ID.\n * @param updates - Partial update to `x`, `y`, `width`, `height`, `stickyRight`, or `stickyBottom`.\n */\n updateFloatingPosition: (id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'stickyRight' | 'stickyBottom'>>) => void;\n /**\n * Activates the given panel regardless of its current state.\n * - Floating panel: raises z-index so the window appears on top of others.\n * - Docked panel: selects the tab within its leaf group.\n * @param id - Panel instance ID.\n * @example\n * ```ts\n * // Ensure a panel is visible before updating its content:\n * if (actions.isOpen('map-1')) actions.focusPanel('map-1');\n * ```\n */\n focusPanel: (id: string) => void;\n /**\n * Returns `true` if a panel with the given ID is currently open (docked, floating, or minimized).\n * Uses a synchronous `stateRef` read — safe to call outside of render.\n * @param id - Panel instance ID.\n * @returns `true` if the panel is open.\n * @example\n * ```ts\n * if (!actions.isOpen('map-1')) {\n * actions.openPanel('map-1', 'map');\n * } else {\n * actions.focusPanel('map-1');\n * }\n * ```\n */\n isOpen: (id: string) => boolean;\n /**\n * Returns the IDs of all currently open panels (docked, floating, and minimized).\n * Uses a synchronous `stateRef` read — safe to call outside of render.\n * @returns Array of panel instance IDs.\n */\n getOpenPanelIds: () => string[];\n /**\n * Serializes the entire workspace state to a JSON string.\n * Includes grid layout, floating window positions, minimized panels, and panel metadata.\n * @returns JSON string suitable for storage and later restoration via {@link loadLayout}.\n * @example\n * ```ts\n * localStorage.setItem('layout', actions.saveLayout());\n * ```\n */\n saveLayout: () => string;\n /**\n * Restores a previously serialized workspace from a JSON string.\n * Replaces the entire current layout — all panels not in the snapshot are closed.\n * @param layoutJson - JSON string produced by {@link saveLayout}.\n */\n loadLayout: (layoutJson: string) => void;\n /**\n * Publishes an event to the inter-panel pub/sub event bus.\n * @param event - Event name string.\n * @param data - Arbitrary payload passed to all subscribers.\n */\n publish: (event: string, data: any) => void;\n /**\n * Subscribes a callback to the inter-panel pub/sub event bus.\n * @param event - Event name string.\n * @param callback - Function called with the event payload.\n * @returns Unsubscribe function — call it to remove the listener.\n * @example\n * ```ts\n * useEffect(() => actions.subscribe('map:zoom', ({ level }) => setZoom(level)), []);\n * ```\n */\n subscribe: (event: string, callback: (data: any) => void) => () => void;\n /** @internal Stores reference to the active tab ID being dragged. */\n setDraggedPanelId: (id: string | null) => void;\n /**\n * Splits an existing leaf group and docks a panel to the given side.\n * @param id - Panel instance ID to dock.\n * @param targetLeafId - Leaf group ID to split.\n * @param position - Which side of the target to split and dock into.\n */\n dockPanelToGroup: (id: string, targetLeafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center') => void;\n /**\n * Reorders a panel's tab index within a docked leaf group.\n * @param panelId - Panel instance ID to move.\n * @param targetLeafId - Destination leaf group ID.\n * @param targetIndex - New tab index within the target group.\n */\n movePanelOrder: (panelId: string, targetLeafId: string, targetIndex: number) => void;\n /**\n * Closes an empty leaf group (removes it from the grid tree).\n * @param leafId - Leaf node ID to remove.\n */\n closeLeafGroup: (leafId: string) => void;\n /**\n * Registers a close guard that can intercept and cancel panel close requests.\n * @param id - Panel instance ID to guard.\n * @param guard - Function returning `true` (allow close) or `false` / `Promise<false>` (block).\n */\n registerCloseGuard: (id: string, guard: () => boolean | Promise<boolean>) => void;\n /**\n * Removes a previously registered close guard.\n * @param id - Panel instance ID.\n */\n unregisterCloseGuard: (id: string) => void;\n /**\n * Marks a panel as dirty (has unsaved changes). Dirty panels show a visual indicator\n * and the built-in close guard prompts the user before closing.\n * @param id - Panel instance ID.\n * @param dirty - `true` to mark dirty, `false` to clear.\n * @param options - Custom confirmation dialog options.\n */\n setPanelDirty: (id: string, dirty: boolean, options?: DirtyStateOptions) => void;\n /**\n * Updates the display title of an open panel.\n * @param id - Panel instance ID.\n * @param title - New title string or localizable message descriptor.\n */\n updatePanelTitle: (id: string, title: string | ContextMenuPredefinedMessage) => void;\n /**\n * Closes a panel, first running any registered close guards.\n * If the panel is dirty, shows the built-in unsaved-changes confirmation dialog.\n * @param id - Panel instance ID.\n * @param options - `force: true` bypasses guards; `onConfirm` provides a custom dialog.\n */\n requestClosePanel: (id: string, options?: { force?: boolean; onConfirm?: (opts?: DirtyStateOptions) => Promise<boolean> }) => Promise<void>;\n /**\n * Docks a floating panel to a workspace edge, creating a full-width or full-height column/row.\n * @param id - Panel instance ID.\n * @param position - Edge to dock to.\n */\n dockPanelToWorkspaceEdge: (id: string, position: 'left' | 'right' | 'top' | 'bottom') => void;\n /**\n * Overrides the workspace layout direction.\n * @param dir - `'ltr'` or `'rtl'`.\n */\n setDirection: (dir: 'ltr' | 'rtl') => void;\n}\n\n/**\n * Extension of {@link WindowActions} used internally by WindowManager components.\n * `setActivePanel` is not part of the public API — it is a low-level tab-focus\n * primitive used exclusively within this library's rendering layer.\n * @internal\n */\nexport interface InternalWindowActions extends WindowActions {\n /** @internal */\n setActivePanel: (id: string | null) => void;\n}\n\nconst WindowStateContext = createContext<WindowState | null>(null);\nconst WindowActionsContext = createContext<InternalWindowActions | 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/**\n * React hook to read the scoped {@link PanelRegistryClass} for the current provider.\n * When the provider was created with a {@link WorkspaceClient}, this returns the client's\n * private registry. Otherwise it returns the global `PanelRegistry` singleton.\n *\n * @group Hooks\n * @returns The panel registry instance in scope.\n * @example\n * ```tsx\n * function MyComponent() {\n * const registry = useRegistry();\n * const entry = registry.get('map');\n * return entry ? <entry.Component panelId=\"preview\" /> : null;\n * }\n * ```\n */\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 focusPanel = 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 focusPanel(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, focusPanel]);\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 const isOpen = useCallback((id: string) => id in stateRef.current.panels, []);\n\n const getOpenPanelIds = useCallback(() => Object.keys(stateRef.current.panels), []);\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<InternalWindowActions>(() => ({\n openPanel,\n closePanel,\n minimizePanel,\n restorePanel,\n floatPanel,\n dockPanel,\n maximizePanel,\n updateSplitSizes,\n updateFloatingPosition,\n focusPanel,\n isOpen,\n getOpenPanelIds,\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 focusPanel,\n isOpen,\n getOpenPanelIds,\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 (process.env.NODE_ENV !== 'development') return;\n let found = false;\n try {\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n const rules = Array.from(sheet.cssRules || []);\n if (rules.some((r: CSSRule) => r.cssText?.includes('react-contexify'))) {\n found = true;\n break;\n }\n } catch { /* CORS-restricted stylesheet — skip */ }\n }\n } catch { /* document.styleSheets unavailable (SSR) */ }\n if (!found) {\n console.warn(\n '[react-dockable-desktop] replace-react-contexify CSS not detected. ' +\n 'Context menus may not render correctly.\\n' +\n 'Add: import \"replace-react-contexify/dist/ReactContexify.css\"'\n );\n }\n }, []);\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 subscribe to the live {@link WindowState} inside a component.\n * The component re-renders whenever the state changes.\n *\n * For imperative reads without a subscription, use {@link WorkspaceClient} methods\n * like `isOpen()` and `getOpenPanelIds()` instead.\n *\n * @group Hooks\n * @returns The current workspace state tree.\n * @throws Error if used outside of a {@link WindowManagerProvider}.\n * @example\n * ```tsx\n * function PanelList() {\n * const { panels } = useWindowManagerState();\n * return <ul>{Object.keys(panels).map(id => <li key={id}>{id}</li>)}</ul>;\n * }\n * ```\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 all layout mutation actions.\n * Returns the public {@link WindowActions} interface.\n *\n * @group Hooks\n * @returns The full set of workspace mutation methods.\n * @throws Error if used outside of a {@link WindowManagerProvider}.\n * @example\n * ```tsx\n * function Toolbar() {\n * const actions = useWindowManagerActions();\n * return (\n * <button onClick={() => actions.openPanel('map-1', 'map')}>Open Map</button>\n * );\n * }\n * ```\n */\nexport const useWindowManagerActions = (): WindowActions => {\n const ctx = useContext(WindowActionsContext);\n if (!ctx) throw new Error('useWindowManagerActions must be used within WindowManagerProvider');\n return ctx;\n};\n\n/**\n * @internal — used by WindowManager.tsx rendering components only.\n * Returns the full {@link InternalWindowActions} including `setActivePanel`.\n */\nexport const useWindowManagerActionsInternal = (): InternalWindowActions => {\n const ctx = useContext(WindowActionsContext);\n if (!ctx) throw new Error('useWindowManagerActionsInternal 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 * @remarks\n * Calls made before the provider mounts are queued and replayed automatically\n * in order once `_connect()` fires. If the client is never connected to a\n * provider (e.g. `client={workspace}` was forgotten), a console warning is\n * emitted in development after 1 second.\n *\n * `subscribe()` and `saveLayout()` return values immediately and cannot be\n * queued — they return safe defaults (`() => {}` and `''`) when disconnected.\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-1', 'map');\n * workspace.focusPanel('map-1');\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 /** Calls queued before _connect() fires — replayed in order on first connect. */\n private _pendingCalls: Array<(actions: WindowActions) => void> = [];\n\n /** DEV-only timer that warns if _connect() is never called within 1 second. */\n private _disconnectedWarnTimer: ReturnType<typeof setTimeout> | 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 lifecycle ────────────────────────────────────────────────────\n\n /** @internal Called by WindowManagerProvider after mount. */\n _connect(actions: WindowActions): void {\n this._actions = actions;\n if (this._disconnectedWarnTimer !== null) {\n clearTimeout(this._disconnectedWarnTimer);\n this._disconnectedWarnTimer = null;\n }\n const pending = this._pendingCalls.splice(0); // drain atomically\n for (const fn of pending) fn(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 // ── Internal dispatch helper ──────────────────────────────────────────────\n\n /**\n * Dispatches a void action immediately if connected, or queues it for replay.\n * In development, warns if the client is still not connected after 1 second.\n */\n private _dispatch(fn: (actions: WindowActions) => void): void {\n if (this._actions) {\n fn(this._actions);\n } else {\n this._pendingCalls.push(fn);\n if (process.env.NODE_ENV !== 'production' && this._disconnectedWarnTimer === null) {\n this._disconnectedWarnTimer = setTimeout(() => {\n if (!this.isConnected && this._pendingCalls.length > 0) {\n console.warn(\n '[react-dockable-desktop] WorkspaceClient has queued calls but was never ' +\n 'connected to a provider. Did you forget client={workspace} on ' +\n '<WindowManagerProvider client={workspace}>?'\n );\n }\n }, 1000);\n }\n }\n }\n\n // ── Forwarding methods — mirrors the WindowActions public interface ────────\n\n openPanel(...args: Parameters<WindowActions['openPanel']>): void {\n this._dispatch(a => a.openPanel(...args));\n }\n\n closePanel(id: string): void { this._dispatch(a => a.closePanel(id)); }\n\n minimizePanel(id: string): void { this._dispatch(a => a.minimizePanel(id)); }\n\n restorePanel(id: string): void { this._dispatch(a => a.restorePanel(id)); }\n\n floatPanel(...args: Parameters<WindowActions['floatPanel']>): void {\n this._dispatch(a => a.floatPanel(...args));\n }\n\n dockPanel(...args: Parameters<WindowActions['dockPanel']>): void {\n this._dispatch(a => a.dockPanel(...args));\n }\n\n maximizePanel(id: string): void { this._dispatch(a => a.maximizePanel(id)); }\n\n /**\n * Activates the given panel regardless of its current state.\n * For floating panels: raises z-index so the window appears on top.\n * For docked panels: selects the tab within its leaf group.\n */\n focusPanel(id: string): void { this._dispatch(a => a.focusPanel(id)); }\n\n /** Returns `true` if a panel with this ID is currently open. */\n isOpen(id: string): boolean { return this._actions?.isOpen(id) ?? false; }\n\n /** Returns the IDs of all currently open panels. */\n getOpenPanelIds(): string[] { return this._actions?.getOpenPanelIds() ?? []; }\n\n saveLayout(): string { return this._actions?.saveLayout() ?? ''; }\n\n loadLayout(json: string): void { this._dispatch(a => a.loadLayout(json)); }\n\n setDirection(dir: 'ltr' | 'rtl'): void { this._dispatch(a => a.setDirection(dir)); }\n\n publish(event: string, data: unknown): void { this._dispatch(a => a.publish(event, data)); }\n\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":["index_exports","__export","ConfirmationForm_default","FormContainerContext","FormContainerProvider","LeftPanelRenderer","ModalStackRenderer_default","PanelProvider","PanelRegistry","PanelRegistryClass","RightPanelRenderer","SidePanelRenderer_default","Sidebar","WindowManager_default","WindowManagerProvider","WorkspaceClient","defaultPredefinedMessages","formatLabel","useFormContainer","useFormatMessage","usePanelActions","usePanelContext","usePanelState","usePredefinedMessages","useRegistry","useStyleClasses","useWindowManagerActions","useWindowManagerState","__toCommonJS","import_react","import_react_dom","import_react","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","import_jsx_runtime","WindowStateContext","WindowActionsContext","WindowI18nContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","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","effectiveFormatMessage","effectivePredefinedMessages","effectiveDir","state","setState","stateRef","closeGuardsRef","mergedMessages","eventBusRef","maxZRef","subscribe","publish","getCascadedPosition","fav","currentFloating","x","y","width","height","isOverlapping","pos","w","wx","wy","attempts","viewW","viewH","focusPanel","id","z","prev","panel","selectActiveInTree","node","removePanelFromTree","idx","panels","p","activePanelId","updatedLeaf","sizes","sum","a","b","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","maximizePanel","updateSplitSizes","path","updateInTree","depth","i","updateFloatingPosition","updates","saveLayout","loadLayout","layoutJson","firstActive","e","setActivePanel","setDirection","dir","isOpen","getOpenPanelIds","actions","defaultFormatMessage","msg","text","key","value","styleClasses","found","sheet","r","useWindowManagerState","ctx","useWindowManagerActions","useWindowManagerActionsInternal","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","isElementRtl","el","closestDirEl","import_replace_react_contexify","import_styles","import_react","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","import_react","import_jsx_runtime","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","import_react","import_jsx_runtime","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","import_jsx_runtime","domCache","hiddenContainerId","DefaultGridIcon","getOrCreateDomCacheElement","id","el","renderPanelContent","componentKey","registry","registryEntry","Component","activePanelDimensions","panelLifecycleRegistry","getOrCreateLifecycleRegistry","panelId","entry","PreservedDOMWrapper","hostRef","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","useWindowManagerActionsInternal","messages","usePredefinedMessages","windowClass","windowBodyClass","useStyleClasses","selectTab","isSelected","isGloballyActive","isHovered","isLast","isHoveredEmpty","sideClass","rect","side","WindowManager","skin","restorePanel","minimizePanel","maximizePanel","updateFloatingPosition","focusPanel","floatPanel","setDraggedPanelId","dockPanelToGroup","movePanelOrder","dockPanelToWorkspaceEdge","setDirection","openModal","usePanelActions","handleRequestClose","customOpts","resolve","opts","baseTitle","ConfirmationForm_default","taskbarRef","contextMenuRef","hoveredMinimized","setHoveredMinimized","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","targetEl","WindowManager_default","WorkspaceClient","config","PanelRegistryClass","id","def","actions","pending","fn","args","json","dir","event","data","a","callback","import_react","import_jsx_runtime","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","optionsRef","baseTitle","formatLabel","handleClose","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","sizeClass","showCloseButton","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","import_react","import_jsx_runtime","SidePanelRendererItem","panel","position","defaultWidth","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","optionsRef","baseTitle","formatLabel","handleClose","ConfirmationForm_default","canClose","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","handleKeyDown","e","width","widthStyle","FormContainerProvider","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","import_react","import_jsx_runtime","Sidebar","position","tabs","drawerWidth","controlledActiveTabId","onActiveTabChange","children","ref","isControlled","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","internalActiveTabId","setInternalActiveTabId","activeTabId","mountedTabIds","setMountedTabIds","initial","tab","newEager","t","prev","next","activeTabIdRef","setActiveTabId","id","tabId","handleTabClick","handleClose","changed","tabStrip","isActive","drawer","isCurrent","onOpen"]}