react-dockable-desktop 6.1.0 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -6
- package/dist/index.d.ts +15 -6
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/WindowManager.tsx","../src/components/WindowManagerContext.tsx","../src/components/FormContainerContext.ts","../src/components/PanelRegistry.ts","../src/components/predefinedMessages.ts","../src/components/serializable.ts","../src/components/ContextMenu.tsx","../src/components/PanelProviderContext.tsx","../src/forms/ConfirmationForm.tsx","../src/components/anchorGeometry.ts","../src/components/dragResize.ts","../src/hooks/useColorScheme.ts","../src/WorkspaceClient.ts","../src/components/DockableDesktopProvider.tsx","../src/components/ToolbarContext.tsx","../src/components/PanelContributionContext.tsx","../src/components/ModalStackRenderer.tsx","../src/components/SidePanelRenderer.tsx","../src/hooks/useContainerRect.ts","../src/components/Sidebar.tsx","../src/components/Toolbar.tsx","../src/components/Toast.tsx","../src/components/PanelOverlay.tsx"],"sourcesContent":["/**\n * @file WindowManager.tsx\n * @description Core component for react-dockable-desktop layout engine.\n * Renders the workspace desktop containing docked splits, tabbed panels, floated windows,\n * resize handles, context menus, and taskbar docks. Exposes lifecycle event listeners.\n */\n\nimport React, { useState, useRef, useEffect, useCallback, useContext } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useWindowManagerState, useWindowManagerActions, useWindowManagerActionsInternal, useFormatMessage, formatLabel, usePredefinedMessages, useStyleClasses, useRegistry, WindowStateContext } from './WindowManagerContext';\nimport type { LayoutNode, LayoutLeafNode, SplitDirection, DropPosition, FloatAnchor, PanelInfo } from './WindowManagerContext';\nimport type { PanelRegistryClass } from './PanelRegistry';\nimport { DefaultContextMenuAdapter, ContextMenuContext } from './ContextMenu';\nimport type { ContextMenuHandle, ContextMenuAdapter } from './ContextMenu';\nimport { FormContainerProvider } from './FormContainerContext';\nimport type { FormContainerContract, ContainerType } from './FormContainerContext';\nimport { usePanelActions } from './PanelProviderContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\nimport { flipZoneHorizontal } from './anchorGeometry';\nimport { startPointerDrag, computeResizedRect } from './dragResize';\nimport type { ResizeDir } from './dragResize';\nimport { useColorScheme } from '../hooks/useColorScheme';\n\nconst findLeaf = (node: LayoutNode | null, leafId: string): LayoutLeafNode | null => {\n if (!node) return null;\n if (node.type === 'leaf') return node.id === leafId ? node : null;\n for (const child of node.children) {\n const found = findLeaf(child, leafId);\n if (found) return found;\n }\n return null;\n};\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 ContextMenuIcons = {\n // Two offset equal rects — Windows \"restore-down / new window\" language\n float: (\n <span className=\"rdd-menu-icon\">\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=\"2\" y=\"8\" width=\"14\" height=\"14\" rx=\"1\"/>\n <rect x=\"8\" y=\"2\" width=\"14\" height=\"14\" rx=\"1\"/>\n </svg>\n </span>\n ),\n // Single horizontal dash — Windows minimize language\n minimize: (\n <span className=\"rdd-menu-icon\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" style={{ display: 'block' }}>\n <line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/>\n </svg>\n </span>\n ),\n // Single inset rect — restore to normal windowed state\n restore: (\n <span className=\"rdd-menu-icon\">\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=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1\"/>\n </svg>\n </span>\n ),\n // Near-full rect — maximize / fill workspace\n maximize: (\n <span className=\"rdd-menu-icon\">\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=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"1\"/>\n </svg>\n </span>\n ),\n // × — close\n close: (\n <span className=\"rdd-menu-icon\">\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 <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n ),\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, panel: PanelInfo, registry: PanelRegistryClass) => {\n const componentKey = panel.component;\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=\"rdd-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(--rdd-text-secondary, #94a3b8)' }}>Key: {componentKey}</span>\n </div>\n );\n }\n const Component = registryEntry.Component;\n // Props spread first, panelId second — a caller-supplied prop of the same name can never\n // shadow the injected id. Matches ModalStackRenderer/SidePanelRenderer's spread order exactly.\n return <Component {...(panel.props ?? {})} panelId={id} />;\n};\n\nconst activePanelDimensions = new Map<string, { width: number; height: number }>();\n\ninterface PanelLifecycleRegistry {\n onClose: Set<() => void>;\n onMinimize: Set<() => void>;\n onRestore: Set<() => void>;\n onResize: Set<(w: number, h: number) => void>;\n onActivate: Set<() => void>;\n onDeactivate: Set<() => void>;\n onContainerTypeChange: Set<(type: ContainerType) => void>;\n}\n\nconst panelLifecycleRegistry = new Map<string, PanelLifecycleRegistry>();\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 onActivate: new Set(),\n onDeactivate: new Set(),\n onContainerTypeChange: 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=\"rdd-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(--rdd-taskbar-item-border, rgba(255, 255, 255, 0.15))'\n }}\n >\n <div\n style={{\n fontSize: '2rem',\n fontWeight: 600,\n color: 'var(--rdd-panel-title-color, var(--rdd-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=\"rdd-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=\"rdd-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 ['--rdd-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, registerStateProvider, unregisterStateProvider, updatePanelTitle, minimizePanel } = useWindowManagerActions();\n\n // ── minimize / restore ──────────────────────────────────────────────────\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 // ── activate / deactivate ───────────────────────────────────────────────\n const isActive = state.activePanelId === panelId;\n const prevActiveRef = useRef(isActive);\n\n useEffect(() => {\n const wasActive = prevActiveRef.current;\n prevActiveRef.current = isActive; // always sync the ref, even if no handler is registered yet\n const entry = panelLifecycleRegistry.get(panelId);\n if (!entry) return;\n\n if (isActive && !wasActive) {\n entry.onActivate.forEach(h => h());\n } else if (!isActive && wasActive) {\n entry.onDeactivate.forEach(h => h());\n }\n }, [isActive, panelId]);\n\n // ── container-type change ───────────────────────────────────────────────\n const rawPanelState = state.panels[panelId]?.state;\n const derivedContainerType: ContainerType =\n rawPanelState === 'floating' ? 'floating-window' : 'dockable-panel';\n const prevContainerTypeRef = useRef(derivedContainerType);\n\n useEffect(() => {\n if (rawPanelState === 'minimized') return; // minimize/restore is onMinimize's domain; intentionally skip ref update\n const prevType = prevContainerTypeRef.current;\n prevContainerTypeRef.current = derivedContainerType; // always sync, even if no handler registered yet\n const entry = panelLifecycleRegistry.get(panelId);\n if (!entry) return;\n\n if (derivedContainerType !== prevType) {\n entry.onContainerTypeChange.forEach(h => h(derivedContainerType));\n }\n }, [derivedContainerType, rawPanelState, panelId]);\n\n // ── cleanup: fire onDeactivate (if active) then onClose ─────────────────\n useEffect(() => {\n return () => {\n const entry = panelLifecycleRegistry.get(panelId);\n if (entry) {\n if (prevActiveRef.current) entry.onDeactivate.forEach(h => h());\n entry.onClose.forEach(h => h());\n panelLifecycleRegistry.delete(panelId);\n }\n };\n }, [panelId]);\n\n // Capture the container type at mount so the static `containerType` field is\n // correct ('dockable-panel' or 'floating-window') rather than the default 'standalone'.\n const initialContainerTypeRef = useRef<ContainerType>(derivedContainerType);\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 registerStateProvider: (getState) => {\n registerStateProvider(panelId, getState);\n return () => unregisterStateProvider(panelId);\n },\n setTitle: (title) => updatePanelTitle(panelId, title),\n instanceId: panelId,\n containerType: initialContainerTypeRef.current,\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 requestMinimize: () => minimizePanel(panelId),\n getDimensions: () => activePanelDimensions.get(panelId) ?? null,\n onActivate: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onActivate.add(handler);\n return () => reg.onActivate.delete(handler);\n },\n onDeactivate: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onDeactivate.add(handler);\n return () => reg.onDeactivate.delete(handler);\n },\n onContainerTypeChange: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onContainerTypeChange.add(handler);\n return () => reg.onContainerTypeChange.delete(handler);\n },\n }), [panelId, requestClosePanel, setPanelDirty, registerCloseGuard, unregisterCloseGuard, registerStateProvider, unregisterStateProvider, updatePanelTitle, minimizePanel]);\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: DropPosition } | null;\n onHoverDropZone: (leafId: string, position: DropPosition | null) => void;\n onTabDragStart: (id: string, e: React.PointerEvent) => 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 handleResizerPointerDown = (idx: number, e: React.PointerEvent) => {\n e.preventDefault();\n const resizerEl = e.currentTarget as HTMLDivElement;\n const parentEl = resizerEl.parentElement;\n const parentSize = parentEl\n ? (isRow ? parentEl.clientWidth : parentEl.clientHeight)\n : (isRow ? 1000 : 800);\n\n startPointerDrag({\n element: resizerEl,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => [...node.sizes],\n activeClasses: [\n { el: resizerEl, classes: ['rdd-active'] },\n { el: document.body, classes: ['rdd-resizing-active', isRow ? 'rdd-resizing-col-active' : 'rdd-resizing-row-active'] },\n ],\n onMove: (dx, dy, startSizes) => {\n const deltaPercentage = (isRow ? dx : dy) / parentSize;\n const newSizes = [...startSizes];\n newSizes[idx] += deltaPercentage;\n newSizes[idx + 1] -= deltaPercentage;\n if (newSizes[idx] > 0.1 && newSizes[idx + 1] > 0.1) {\n updateSplitSizes(path, newSizes);\n }\n },\n });\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', minWidth: 0, minHeight: 0 }}>\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 onPointerDown={(e) => handleResizerPointerDown(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=\"rdd-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: DropPosition } | null;\n onHoverDropZone: (leafId: string, position: DropPosition | null) => void;\n onTabDragStart: (id: string, e: React.PointerEvent) => 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 tabContainerRef = useRef<HTMLDivElement>(null);\n const [tabScroll, setTabScroll] = useState({ left: false, right: false });\n\n const updateTabScroll = useCallback(() => {\n const el = tabContainerRef.current;\n if (!el) return;\n setTabScroll({\n left: el.scrollLeft > 0,\n right: el.scrollLeft < el.scrollWidth - el.clientWidth - 1,\n });\n }, []);\n\n useEffect(() => {\n const el = tabContainerRef.current;\n if (!el) return;\n el.addEventListener('scroll', updateTabScroll, { passive: true });\n const ro = new ResizeObserver(updateTabScroll);\n ro.observe(el);\n updateTabScroll();\n return () => { el.removeEventListener('scroll', updateTabScroll); ro.disconnect(); };\n }, [updateTabScroll]);\n\n const scrollTabs = (dir: 'left' | 'right') => {\n tabContainerRef.current?.scrollBy({ left: dir === 'left' ? -120 : 120, behavior: 'smooth' });\n };\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={`rdd-workspace-panel ${windowClass ?? ''}`}\n style={{ overflow: 'hidden', position: 'relative' }}\n >\n {/* Tab Headers */}\n <div className=\"rdd-workspace-tab-bar\" style={{ minHeight: '38px' }}>\n {tabScroll.left && (\n <button\n className=\"rdd-tab-scroll-btn rdd-tab-scroll-btn-left\"\n onPointerDown={(e) => e.stopPropagation()}\n onClick={() => scrollTabs('left')}\n tabIndex={-1}\n aria-label=\"Scroll tabs left\"\n >‹</button>\n )}\n <div\n ref={tabContainerRef}\n className=\"rdd-tab-headers-container\"\n style={{ scrollbarWidth: 'none' }}\n onPointerMove={(e) => {\n if (state.draggedPanelId && e.target === e.currentTarget) {\n onTabHover(leaf.id, 'EMPTY', leaf.panels.length, 'right');\n }\n }}\n onPointerLeave={(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' ? 'rdd-drag-hover-left' : 'rdd-drag-hover-right')\n : (isHoveredEmpty ? 'rdd-drag-hover-right' : '');\n\n const tabFocusClass = isSelected\n ? (isGloballyActive ? 'rdd-active rdd-workspace-tab-active-focused' : 'rdd-active rdd-workspace-tab-active-unfocused')\n : 'rdd-workspace-tab-inactive';\n\n return (\n <div\n key={id}\n data-tab-id={id}\n data-leaf-id={leaf.id}\n data-tab-index={String(idx)}\n onClick={() => selectTab(id)}\n onPointerDown={(e) => {\n if (options?.canDrag !== false) {\n onTabDragStart(id, e);\n }\n }}\n onContextMenu={(e) => onTabRightClick(id, e)}\n onPointerMove={(e) => {\n if (state.draggedPanelId && e.pointerType !== 'touch') {\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 onPointerLeave={() => {\n if (state.draggedPanelId) {\n onTabHover(leaf.id, '', -1, null);\n }\n }}\n className={`rdd-workspace-tab ${tabFocusClass} ${sideClass}`}\n style={{ cursor: options?.canDrag === false ? 'default' : 'pointer' }}\n >\n <span className=\"rdd-text-truncate\" style={{ maxWidth: '120px', display: 'flex', alignItems: 'center' }}>\n <span className=\"rdd-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=\"rdd-tab-header-actions\"\n onClick={(e) => e.stopPropagation()}\n onPointerDown={(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=\"rdd-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 {tabScroll.right && (\n <button\n className=\"rdd-tab-scroll-btn rdd-tab-scroll-btn-right\"\n onPointerDown={(e) => e.stopPropagation()}\n onClick={() => scrollTabs('right')}\n tabIndex={-1}\n aria-label=\"Scroll tabs right\"\n >›</button>\n )}\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=\"rdd-close-tab-x rdd-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={`rdd-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=\"rdd-empty-leaf-placeholder\">\n <span>Empty Workspace Section</span>\n </div>\n )}\n\n {/* Drag overlay targets cross */}\n {state.draggedPanelId !== null && (() => {\n // State-driven, not :hover-driven — :hover never fires reliably in Safari\n // during an active drag, and doesn't exist at all on touch. activeDropZone\n // already tracks this for mouse, pen, and touch alike (see updateHoverFromPoint).\n const isActive = (pos: DropPosition) => activeDropZone?.leafId === leaf.id && activeDropZone.position === pos;\n return (\n <div className=\"rdd-dock-drop-zone-overlay\">\n <div className=\"rdd-dock-target-cross\">\n {/* Top target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"top\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'top')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-top${isActive('top') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▲\n </div>\n {/* Bottom target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"bottom\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'bottom')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-bottom${isActive('bottom') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▼\n </div>\n {/* Left target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"left\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'left')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-left${isActive('left') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ◀\n </div>\n {/* Right target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"right\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'right')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-right${isActive('right') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▶\n </div>\n {/* Center target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"center\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'center')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-center${isActive('center') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▣\n </div>\n </div>\n </div>\n );\n })()}\n\n {/* Visual preview highlight overlay */}\n {state.draggedPanelId !== null && activeDropZone !== null && activeDropZone.leafId === leaf.id && (\n <div\n className=\"rdd-dock-preview-highlight\"\n style={(() => {\n const pos = activeDropZone.position;\n const pct = `${state.splitRatio * 100}%`;\n const rem = `${(1 - state.splitRatio) * 100}%`;\n return {\n left: pos === 'right' ? rem : '0',\n top: pos === 'bottom' ? rem : '0',\n width: (pos === 'left' || pos === 'right') ? pct : '100%',\n height: (pos === 'top' || pos === 'bottom') ? pct : '100%',\n };\n })()}\n />\n )}\n </div>\n </div>\n );\n};\n\n\n// ==========================================\n// 5. WindowManager (Main Render Component)\n// ==========================================\n\n/** Controls when the minimized-panel taskbar is visible. */\nexport type TaskbarVisibility = 'always' | 'compact' | 'autohide';\n\n/** Props for `<WindowManager>`. */\nexport interface WindowManagerProps {\n /** Built-in skin name or a custom skin key registered via CSS. @default 'vscode' */\n skin?: string;\n /** Fallback icon shown in panel tabs when no panel-specific icon is provided. */\n defaultPanelIcon?: React.ReactNode;\n /**\n * Controls taskbar visibility.\n * - `'always'` — permanent bar at the bottom (default)\n * - `'compact'` — only visible when minimized panels exist\n * - `'autohide'` — overlay bar with 8 px peek strip\n * @default 'always'\n */\n taskbarVisibility?: TaskbarVisibility;\n /** Custom context menu renderer. Defaults to the built-in `DefaultContextMenuAdapter`. */\n contextMenuAdapter?: ContextMenuAdapter;\n /** Enables the library's own transitions/animations (tab hover, dock preview, etc.). Never affects the consumer's own page. @default true */\n animations?: boolean;\n}\n\nexport const WindowManager: React.FC<WindowManagerProps> = ({ skin = 'vscode', defaultPanelIcon, taskbarVisibility = 'always', contextMenuAdapter = DefaultContextMenuAdapter, animations = true }) => {\n const state = useWindowManagerState();\n const registry = useRegistry();\n const { restorePanel, minimizePanel, requestClosePanel, maximizePanel, updateFloatingPosition, focusPanel, floatPanel, setDraggedPanelId, dockPanelToGroup, movePanelOrder, dockPanelToWorkspaceEdge, setActivePanel, getPanelContextMenuItems, showContextMenu, registerContextMenuFn } = 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 ctxMenu = useContext(ContextMenuContext);\n const contextMenuRef = useRef<ContextMenuHandle>(null);\n\n useEffect(() => {\n if (ctxMenu !== null) {\n return registerContextMenuFn((opts) => ctxMenu.show(opts));\n } else {\n return registerContextMenuFn((opts) => contextMenuRef.current?.show(opts));\n }\n }, [ctxMenu, registerContextMenuFn]);\n\n const taskbarRef = useRef<HTMLDivElement | null>(null);\n const [taskbarExpanded, setTaskbarExpanded] = useState(false);\n const taskbarCollapseTimerRef = useRef<ReturnType<typeof setTimeout>>(null);\n const prevMinimizedLengthRef = useRef(state.minimized.length);\n\n const [hoveredMinimized, setHoveredMinimized] = useState<{ id: string; rect: DOMRect; title: string | any; component: string; fromTouch?: boolean } | null>(null);\n const minimizedTooltipTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);\n const lastTaskbarPointerTypeRef = useRef<string>('mouse');\n const [internalContextMenuOpen, setInternalContextMenuOpen] = useState(false);\n const isContextMenuOpen = ctxMenu !== null ? ctxMenu.isOpen : internalContextMenuOpen;\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 useEffect(() => {\n if (!hoveredMinimized?.fromTouch) return;\n const handler = (e: PointerEvent) => {\n if (e.pointerType !== 'touch') return;\n const tooltip = document.querySelector('.rdd-taskbar-item-tooltip');\n if (tooltip?.contains(e.target as Node)) return;\n setHoveredMinimized(null);\n };\n document.addEventListener('pointerdown', handler, { capture: true });\n return () => document.removeEventListener('pointerdown', handler, { capture: true });\n }, [hoveredMinimized?.fromTouch]);\n\n const [activeDropZone, setActiveDropZone] = useState<{ leafId: string; position: DropPosition } | null>(null);\n const activeDropZoneRef = useRef<{ leafId: string; position: DropPosition } | null>(null);\n const [dragPos, setDragPos] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n\n const [activeEdgeDrop, setActiveEdgeDropState] = useState<SplitDirection | null>(null);\n const activeEdgeDropRef = useRef<SplitDirection | null>(null);\n const setActiveEdgeDrop = (val: SplitDirection | null) => {\n setActiveEdgeDropState(val);\n activeEdgeDropRef.current = val;\n };\n\n const [activeCornerAnchor, setActiveCornerAnchorState] = useState<FloatAnchor | null>(null);\n const activeCornerAnchorRef = useRef<FloatAnchor | null>(null);\n const setActiveCornerAnchor = (val: FloatAnchor | null) => {\n setActiveCornerAnchorState(val);\n activeCornerAnchorRef.current = val;\n };\n\n const isRtl = useContext(WindowStateContext)?.isRtl ?? false;\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: DropPosition | null) => {\n const val = position ? { leafId, position } : null;\n setActiveDropZone(val);\n activeDropZoneRef.current = val;\n // A leaf's cross commonly overlaps the workspace edge/corner zones underneath it —\n // the more specific per-leaf target wins, matching the corner zone's own handler,\n // which already clears the edge the same way.\n if (val) {\n setActiveEdgeDrop(null);\n setActiveCornerAnchor(null);\n }\n };\n\n // Used during touch drag (pointer capture suppresses hover events on other elements)\n const updateHoverFromPoint = (x: number, y: number) => {\n const elements = document.elementsFromPoint(x, y);\n let foundDropZone = false;\n let foundEdge = false;\n let foundTab = false;\n\n for (const el of elements) {\n if (!(el instanceof HTMLElement)) continue;\n\n if (!foundDropZone && el.dataset.dropZone) {\n const leafId = el.dataset.leafId;\n if (leafId) {\n const pos = el.dataset.dropZone as DropPosition;\n setActiveDropZone({ leafId, position: pos });\n activeDropZoneRef.current = { leafId, position: pos };\n foundDropZone = true;\n }\n }\n\n // Tabs checked before edge triggers — precise tab intent beats the coarse edge zone\n if (!foundTab && el.dataset.tabId) {\n const leafId = el.dataset.leafId;\n const tabIdx = parseInt(el.dataset.tabIndex || '0', 10);\n if (leafId) {\n const rect = el.getBoundingClientRect();\n const side = (x - rect.left) < rect.width / 2 ? 'left' : 'right';\n setHoveredTab({ leafId, panelId: el.dataset.tabId, index: tabIdx, side });\n hoveredTabRef.current = { leafId, panelId: el.dataset.tabId, index: tabIdx, side };\n foundTab = true;\n }\n }\n\n if (!foundEdge && el.dataset.edgeTrigger) {\n setActiveEdgeDrop(el.dataset.edgeTrigger as SplitDirection);\n foundEdge = true;\n }\n\n if (foundDropZone && foundEdge && foundTab) break;\n }\n\n if (!foundDropZone) { setActiveDropZone(null); activeDropZoneRef.current = null; }\n if (!foundEdge) setActiveEdgeDrop(null);\n if (!foundTab) { setHoveredTab(null); hoveredTabRef.current = null; }\n };\n\n const LONG_PRESS_MS = 300;\n const CANCEL_MOVE_PX = 8;\n\n const clearDragState = () => {\n setDraggedPanelId(null);\n setActiveDropZone(null);\n activeDropZoneRef.current = null;\n setHoveredTab(null);\n hoveredTabRef.current = null;\n setActiveEdgeDrop(null);\n };\n\n const flipRtl = (pos: DropPosition): DropPosition => {\n if (!state.isRtl) return pos;\n if (pos === 'left') return 'right';\n if (pos === 'right') return 'left';\n return pos;\n };\n\n const executeDrop = (id: string, me: PointerEvent) => {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n const cornerAnchor = activeCornerAnchorRef.current;\n\n if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, flipRtl(edgeDrop) as SplitDirection);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') targetIndex += 1;\n // DOM tab indices are pre-removal. movePanelOrder removes the panel before\n // inserting, shifting subsequent positions down by 1 in the same leaf.\n // Compensate when the dragged panel currently sits before the drop target.\n const targetLeaf = findLeaf(state.gridRoot, targetTab.leafId);\n if (targetLeaf) {\n const currentIdx = targetLeaf.panels.indexOf(id);\n if (currentIdx !== -1 && currentIdx < targetIndex) targetIndex -= 1;\n }\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, flipRtl(dropZone.position));\n } else if (cornerAnchor) {\n floatPanel(id, undefined, isRtl ? flipZoneHorizontal(cornerAnchor) : cornerAnchor);\n } else {\n floatPanel(id, { x: me.clientX - 150, y: me.clientY - 15, width: 450, height: 350 });\n }\n setActiveCornerAnchor(null);\n clearDragState();\n };\n\n const handleTabDragStart = (id: string, e: React.PointerEvent) => {\n if (e.pointerType === 'mouse' && e.button !== 0) return;\n e.preventDefault();\n\n const el = e.currentTarget as HTMLElement;\n const startX = e.clientX;\n const startY = e.clientY;\n\n if (e.pointerType === 'touch') {\n const pointerId = e.pointerId;\n let cancelled = false;\n\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n };\n\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n\n try { el.setPointerCapture(pointerId); } catch { return; }\n el.classList.add('rdd-long-press-active');\n document.body.classList.add('rdd-dragging-active');\n if (navigator.vibrate) navigator.vibrate(10);\n\n // Long-press captured: move → drag, release → context menu\n let dragStarted = false;\n\n const onMove = (me: PointerEvent) => {\n if (!dragStarted) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n setDragPos({ x: me.clientX, y: me.clientY });\n updateHoverFromPoint(me.clientX, me.clientY);\n };\n\n const onEnd = (me: PointerEvent) => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n\n if (dragStarted) {\n executeDrop(id, me);\n } else {\n // Release without drag → context menu\n handleTabRightClick(id, me as unknown as React.MouseEvent);\n }\n };\n\n const onCancel = () => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n if (dragStarted) clearDragState();\n };\n\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onCancel);\n }, LONG_PRESS_MS);\n\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', cancel);\n el.addEventListener('pointercancel', cancel);\n } else {\n // Mouse / pen: window-level listeners WITHOUT setPointerCapture so that\n // onPointerEnter/Leave on drop zones and edge triggers still fire normally.\n let dragStarted = false;\n\n const onMove = (me: PointerEvent) => {\n const dx = me.clientX - startX;\n const dy = me.clientY - startY;\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n if (dragStarted) setDragPos({ x: me.clientX, y: me.clientY });\n };\n\n const onEnd = (me: PointerEvent) => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) executeDrop(id, me);\n };\n\n const onCancel = () => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) clearDragState();\n };\n\n document.body.classList.add('rdd-dragging-active');\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onEnd);\n window.addEventListener('pointercancel', onCancel);\n }\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 icon: ContextMenuIcons.float,\n action: () => floatPanel(id)\n });\n }\n if (options?.canMinimize !== false) {\n items.push({\n label: formatLabel(messages.minimizePanel, formatMessage),\n icon: ContextMenuIcons.minimize,\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 icon: ContextMenuIcons.close,\n action: () => handleRequestClose(id)\n });\n }\n\n if (items.length === 0) return;\n\n const custom = getPanelContextMenuItems(id);\n const finalItems = custom.length > 0 ? [...items, { separator: true as const }, ...custom] : items;\n\n showContextMenu({\n event: e,\n items: finalItems\n });\n };\n\n const handleMinimizedRightClick = (id: string, e: React.MouseEvent) => {\n e.preventDefault();\n setHoveredMinimized(null);\n showContextMenu({\n event: e,\n items: [\n {\n label: formatLabel(messages.restorePanel, formatMessage),\n icon: ContextMenuIcons.restore,\n action: () => restorePanel(id)\n },\n {\n label: formatLabel(messages.maximizePanel, formatMessage),\n icon: ContextMenuIcons.maximize,\n action: () => maximizePanel(id)\n },\n { separator: true },\n {\n label: formatLabel(messages.closePanel, formatMessage),\n icon: ContextMenuIcons.close,\n action: () => handleRequestClose(id)\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 let heightWarnShown = false;\n\n const observer = new ResizeObserver((entries) => {\n if (!entries || entries.length === 0) return;\n const rect = entries[0].contentRect;\n\n if (process.env.NODE_ENV === 'development' && rect.height < 10 && !heightWarnShown) {\n heightWarnShown = true;\n\n // Walk up the ancestor chain to find the highest zero-height element\n let culprit: Element = el;\n let cursor = el.parentElement;\n while (cursor && cursor !== document.documentElement) {\n if (cursor.getBoundingClientRect().height < 10) {\n culprit = cursor;\n } else {\n break;\n }\n cursor = cursor.parentElement;\n }\n\n const tag = culprit.tagName.toLowerCase();\n const id = culprit.id ? ` id=\"${culprit.id}\"` : '';\n const cls = culprit.className ? ` class=\"${culprit.className}\"` : '';\n const who = culprit === el\n ? 'the WindowManager container itself'\n : `a wrapper element: <${tag}${id}${cls}>`;\n\n console.warn(\n `[react-dockable-desktop] Workspace height is 0px — the workspace will be invisible.\\n\\n` +\n `Zero height found at: ${who}\\n\\n` +\n `Root cause: in CSS, \"height: 100%\" only works when the parent has an explicit height.\\n` +\n `If any ancestor has height: auto (the default for <div>), the chain breaks and\\n` +\n `everything inside collapses to 0px.\\n\\n` +\n `Fix options:\\n` +\n ` 1. Use height: 100vh directly on the workspace wrapper:\\n` +\n ` <div style={{ height: '100vh', overflow: 'hidden' }}>\\n` +\n ` <WindowManager />\\n` +\n ` </div>\\n\\n` +\n ` 2. Use CSS Grid/Flex and let the workspace fill remaining space:\\n` +\n ` .layout { display: flex; flex-direction: column; height: 100vh; }\\n` +\n ` .workspace { flex: 1; min-height: 0; }\\n\\n` +\n ` 3. Verify styles.css is imported — it anchors html, body, #root to 100% height.`\n );\n }\n\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 // 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 (applies whether anchored or free-floating)\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 // Anchored windows are positioned entirely by `anchor` + `dir` at render time (see the\n // floating-window style callback below), so x/y don't affect their visual position —\n // only free-floating windows need off-screen bounds clamping here.\n if (!w.anchor) {\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 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/touch anywhere inside a window or grid panel focuses it)\n useEffect(() => {\n const handlePointerDownGlobal = (e: PointerEvent) => {\n // Only handle primary button (left-click or first touch point)\n if (e.button !== 0) return;\n\n const target = e.target as HTMLElement | null;\n if (!target || typeof target.closest !== 'function') return;\n\n // 1. Check if click is inside a floating window\n const windowEl = target.closest('.rdd-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('.rdd-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('pointerdown', handlePointerDownGlobal);\n return () => {\n document.removeEventListener('pointerdown', handlePointerDownGlobal);\n };\n }, [focusPanel, setActivePanel]);\n\n // Floating Window dragging handler\n const startDrag = (id: string, e: React.PointerEvent) => {\n e.preventDefault();\n const floatingWin = state.floating.find(w => w.id === id);\n if (!floatingWin || floatingWin.maximized) return;\n focusPanel(id);\n\n const el = e.currentTarget as HTMLDivElement;\n const windowEl = el.closest('.rdd-floating-window') as HTMLDivElement | null;\n const startX = e.clientX;\n const startY = e.clientY;\n const startPosX = windowEl ? windowEl.offsetLeft : 0;\n const startPosY = windowEl ? windowEl.offsetTop : 0;\n\n const executeFWDrop = () => {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n const cornerAnchor = activeCornerAnchorRef.current;\n if (cornerAnchor) {\n updateFloatingPosition(id, { anchor: isRtl ? flipZoneHorizontal(cornerAnchor) : cornerAnchor });\n } else if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, flipRtl(edgeDrop) as SplitDirection);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') targetIndex += 1;\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, flipRtl(dropZone.position));\n }\n setActiveCornerAnchor(null);\n clearDragState();\n };\n\n if (e.pointerType === 'touch') {\n const pointerId = e.pointerId;\n let cancelled = false;\n\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n };\n\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n\n try { el.setPointerCapture(pointerId); } catch { return; }\n el.classList.add('rdd-long-press-active');\n document.body.classList.add('rdd-dragging-active');\n setDraggedPanelId(id);\n\n const onMove = (me: PointerEvent) => {\n const dx = me.clientX - startX;\n const dy = me.clientY - startY;\n updateFloatingPosition(id, { x: startPosX + dx, y: startPosY + dy, anchor: null });\n updateHoverFromPoint(me.clientX, me.clientY);\n };\n\n const onEnd = () => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n executeFWDrop();\n };\n\n const onCancel = () => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n clearDragState();\n };\n\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onCancel);\n }, LONG_PRESS_MS);\n\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', cancel);\n el.addEventListener('pointercancel', cancel);\n } else {\n // Mouse / pen: window-level listeners WITHOUT setPointerCapture so that\n // onPointerEnter/Leave on drop zones and edge triggers still fire normally.\n let dragStarted = false;\n\n const onMove = (me: PointerEvent) => {\n const dx = me.clientX - startX;\n const dy = me.clientY - startY;\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n if (dragStarted) {\n updateFloatingPosition(id, { x: startPosX + dx, y: startPosY + dy, anchor: null });\n }\n };\n\n const onEnd = () => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) executeFWDrop();\n };\n\n const onCancel = () => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) clearDragState();\n };\n\n document.body.classList.add('rdd-dragging-active');\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onEnd);\n window.addEventListener('pointercancel', onCancel);\n }\n };\n\n // Floating Window resizing handler — supports 8 directions\n const startResize = (id: string, dir: ResizeDir, e: React.PointerEvent) => {\n e.preventDefault();\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 el = e.currentTarget as HTMLDivElement;\n const windowEl = el.closest('.rdd-floating-window') as HTMLDivElement | null;\n const startRect = {\n x: windowEl ? windowEl.offsetLeft : 0,\n y: windowEl ? windowEl.offsetTop : 0,\n w: windowEl ? windowEl.offsetWidth : 400,\n h: windowEl ? windowEl.offsetHeight : 300,\n };\n\n const viewW = workspaceSize.width;\n const viewH = workspaceSize.height;\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 const isRightSnapped = dir === 'se' && Math.abs(parsedX + parsedW - viewW) < 4;\n const isBottomSnapped = dir === 'se' && Math.abs(parsedY + parsedH - viewH) < 4;\n\n startPointerDrag({\n element: el,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => startRect,\n activeClasses: [{ el: document.body, classes: ['rdd-resizing-active'] }],\n // No maxW/maxH/minX/minY: this window is intentionally allowed to grow\n // unbounded and be dragged fully off-screen, same as before this refactor.\n onMove: (dx, dy, start) => {\n const resized = computeResizedRect(dir, dx, dy, start, { minW: 200, minH: 150 });\n let { x: newX, y: newY, w: newW, h: newH } = resized;\n\n // Snap adjustments for SE corner when previously snapped to workspace edges\n if (isRightSnapped) {\n newX = viewW - newW;\n if (newX < 0) { newX = 0; newW = viewW; }\n }\n if (isBottomSnapped) {\n newY = viewH - newH;\n if (newY < 0) { newY = 0; newH = viewH; }\n }\n\n updateFloatingPosition(id, { x: newX, y: newY, width: newW, height: newH });\n },\n });\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 const expandTaskbar = useCallback(() => {\n if (taskbarCollapseTimerRef.current) clearTimeout(taskbarCollapseTimerRef.current);\n setTaskbarExpanded(true);\n }, []);\n\n const scheduleCollapseTaskbar = useCallback(() => {\n taskbarCollapseTimerRef.current = setTimeout(() => setTaskbarExpanded(false), 400);\n }, []);\n\n useEffect(() => {\n if (taskbarVisibility === 'autohide' && state.minimized.length > prevMinimizedLengthRef.current) {\n if (taskbarCollapseTimerRef.current) clearTimeout(taskbarCollapseTimerRef.current);\n setTaskbarExpanded(true);\n taskbarCollapseTimerRef.current = setTimeout(() => setTaskbarExpanded(false), 2000);\n }\n prevMinimizedLengthRef.current = state.minimized.length;\n }, [state.minimized.length, taskbarVisibility]);\n\n // Fetch the active color-scheme from documentElement to make sure nested variables resolve correctly\n const currentColorScheme = useColorScheme();\n\n // Mirror skin onto documentElement so components rendered outside the WindowManager div\n // (Toolbar, Sidebar) also inherit per-skin CSS variable overrides — same pattern as data-color-scheme.\n useEffect(() => {\n if (skin) {\n document.documentElement.setAttribute('data-workspace-skin', skin);\n } else {\n document.documentElement.removeAttribute('data-workspace-skin');\n }\n return () => { document.documentElement.removeAttribute('data-workspace-skin'); };\n }, [skin]);\n\n // Mirror color-scheme onto documentElement too — Toolbar/Sidebar are siblings (or,\n // for Sidebar, an ancestor) of this div, not descendants, so without this they never\n // actually receive the [data-color-scheme]-scoped tokens (e.g. --sidebar-*) despite\n // the comment above claiming parity with the skin mirroring. Only mirror 'light' —\n // 'dark' is the unscoped :root default, so leaving the attribute absent for it avoids\n // writing back the exact value useColorScheme() just read from this same attribute,\n // which would otherwise re-trigger its own MutationObserver on every mount.\n useEffect(() => {\n if (currentColorScheme === 'light') {\n document.documentElement.setAttribute('data-color-scheme', 'light');\n } else {\n document.documentElement.removeAttribute('data-color-scheme');\n }\n return () => { document.documentElement.removeAttribute('data-color-scheme'); };\n }, [currentColorScheme]);\n\n // Mirror the animations opt-out the same way — covers portaled chrome (ContextMenu,\n // Toast, Toolbar's flyout) that renders outside this div via createPortal.\n useEffect(() => {\n if (!animations) {\n document.documentElement.classList.add('rdd-no-animations');\n } else {\n document.documentElement.classList.remove('rdd-no-animations');\n }\n return () => { document.documentElement.classList.remove('rdd-no-animations'); };\n }, [animations]);\n\n return (\n <div\n className={`rdd-workspace${animations ? '' : ' rdd-no-animations'}`}\n data-workspace-skin={skin}\n data-color-scheme={currentColorScheme}\n style={{ display: 'flex', flexDirection: 'column', position: 'relative', 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 ? 'rdd-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 data-edge-trigger=\"left\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-left\"\n onPointerEnter={() => setActiveEdgeDrop('left')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n data-edge-trigger=\"right\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-right\"\n onPointerEnter={() => setActiveEdgeDrop('right')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n data-edge-trigger=\"top\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-top\"\n onPointerEnter={() => setActiveEdgeDrop('top')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n data-edge-trigger=\"bottom\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-bottom\"\n onPointerEnter={() => setActiveEdgeDrop('bottom')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n </>\n )}\n\n {/* Corner anchor drop zones — appear during floating window drag */}\n {state.draggedPanelId !== null && (['top-left', 'top-right', 'bottom-left', 'bottom-right'] as FloatAnchor[]).map(corner => (\n <div\n key={corner}\n className={`rdd-corner-zone rdd-corner-zone--${corner}${activeCornerAnchor === corner ? ' rdd-corner-zone--hovered' : ''}`}\n onPointerEnter={() => { setActiveCornerAnchor(corner); setActiveEdgeDrop(null); }}\n onPointerLeave={() => setActiveCornerAnchor(null)}\n aria-hidden=\"true\"\n />\n ))}\n\n {/* Edge drop visual preview overlay */}\n {state.draggedPanelId !== null && activeEdgeDrop !== null && (\n <div\n className=\"rdd-workspace-edge-preview\"\n style={(() => {\n const pct = `${state.edgeSplitRatio * 100}%`;\n switch (activeEdgeDrop) {\n case 'left': return { left: 0, top: 0, bottom: 0, width: pct };\n case 'right': return { right: 0, top: 0, bottom: 0, width: pct };\n case 'top': return { top: 0, left: 0, right: 0, height: pct };\n case 'bottom': return { bottom: 0, left: 0, right: 0, height: pct };\n }\n })()}\n />\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=\"rdd-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 onPointerDownCapture={() => {\n setActivePanel(w.id);\n focusPanel(w.id);\n }}\n className={`rdd-floating-window ${isMaximized ? 'rdd-maximized' : ''} ${isFocused ? 'rdd-window-focused' : ''} ${windowClass ?? ''}`}\n style={(() => {\n const CORNER_INSET = 8;\n const CORNER_GAP = 8;\n const w_ = typeof w.width === 'number' ? `${w.width}px` : w.width;\n const h_ = typeof w.height === 'number' ? `${w.height}px` : w.height;\n if (isMaximized) {\n return { position: 'absolute' as const, left: 0, top: 0, width: '100%', height: '100%', zIndex: w.z, pointerEvents: isDragged ? 'none' as const : 'auto' as const };\n }\n if (w.anchor) {\n const stack = state.floating.filter(fw => fw.anchor === w.anchor && !fw.maximized);\n const idx = stack.findIndex(fw => fw.id === w.id);\n let stackOffset = CORNER_INSET;\n for (let i = 0; i < idx; i++) {\n const sh = typeof stack[i].height === 'number' ? stack[i].height as number : parseFloat(stack[i].height as string);\n stackOffset += sh + CORNER_GAP;\n }\n const isTop = w.anchor.startsWith('top');\n const isRight = w.anchor.endsWith('-right');\n return {\n position: 'absolute' as const,\n [isRight ? 'insetInlineEnd' : 'insetInlineStart']: CORNER_INSET,\n [isTop ? 'top' : 'bottom']: stackOffset,\n width: w_,\n height: h_,\n zIndex: w.z,\n transition: isDragged ? 'none' : 'top 0.2s ease, bottom 0.2s ease',\n pointerEvents: isDragged ? 'none' as const : 'auto' as const,\n };\n }\n return {\n position: 'absolute' as const,\n left: typeof w.x === 'number' ? `${w.x}px` : w.x,\n top: typeof w.y === 'number' ? `${w.y}px` : w.y,\n width: w_,\n height: h_,\n zIndex: w.z,\n pointerEvents: isDragged ? 'none' as const : 'auto' as const,\n };\n })()}\n >\n {/* Title Bar */}\n <div\n onDoubleClick={() => maximizePanel(w.id)}\n onPointerDown={(e) => {\n if (options?.canDrag !== false) {\n startDrag(w.id, e);\n }\n }}\n className=\"rdd-floating-window-titlebar rdd-cursor-move\"\n style={{ cursor: isMaximized || options?.canDrag === false ? 'default' : 'move' }}\n >\n <span className=\"rdd-floating-window-title\">\n <span className=\"rdd-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=\"rdd-titlebar-actions\" style={{ gap: 'var(--rdd-header-button-gap, 4px)' }} onPointerDown={(e) => e.stopPropagation()}>\n {options?.renderHeaderActions && (\n <div className=\"rdd-window-header-actions\">\n {options.renderHeaderActions(w.id)}\n </div>\n )}\n {getPanelContextMenuItems(w.id).length > 0 && (\n <button\n type=\"button\"\n className=\"rdd-custom-tab-btn rdd-btn-more-actions\"\n title=\"More actions\"\n onClick={(e) => {\n e.stopPropagation();\n const customItems = getPanelContextMenuItems(w.id);\n if (customItems.length === 0) return;\n showContextMenu({\n event: e,\n items: customItems\n });\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style={{ display: 'block' }}>\n <circle cx=\"12\" cy=\"5\" r=\"2\"/>\n <circle cx=\"12\" cy=\"12\" r=\"2\"/>\n <circle cx=\"12\" cy=\"19\" r=\"2\"/>\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=\"rdd-custom-tab-btn rdd-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=\"rdd-custom-tab-btn rdd-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=\"rdd-custom-tab-btn rdd-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 {/* 8-direction resize handles */}\n {!isMaximized && (\n <>\n <div onPointerDown={(e) => startResize(w.id, 'n', e)} className=\"rdd-resize-handle rdd-resize-n\" />\n <div onPointerDown={(e) => startResize(w.id, 'ne', e)} className=\"rdd-resize-handle rdd-resize-ne\" />\n <div onPointerDown={(e) => startResize(w.id, 'e', e)} className=\"rdd-resize-handle rdd-resize-e\" />\n <div onPointerDown={(e) => startResize(w.id, 'se', e)} className=\"rdd-resize-handle rdd-resize-se\" />\n <div onPointerDown={(e) => startResize(w.id, 's', e)} className=\"rdd-resize-handle rdd-resize-s\" />\n <div onPointerDown={(e) => startResize(w.id, 'sw', e)} className=\"rdd-resize-handle rdd-resize-sw\" />\n <div onPointerDown={(e) => startResize(w.id, 'w', e)} className=\"rdd-resize-handle rdd-resize-w\" />\n <div onPointerDown={(e) => startResize(w.id, 'nw', e)} className=\"rdd-resize-handle rdd-resize-nw\" />\n </>\n )}\n </div>\n );\n });\n })()}\n </div>\n\n {/* 2. macOS / Windows 11-style Taskbar Sibling Footer (Flex-shrinked at bottom) */}\n {(taskbarVisibility === 'always' || state.minimized.length > 0) && (\n <div\n className={[\n 'rdd-taskbar-footer-container',\n `rdd-taskbar-mode-${taskbarVisibility}`,\n taskbarVisibility === 'autohide' && taskbarExpanded ? 'rdd-taskbar-expanded' : '',\n ].filter(Boolean).join(' ')}\n style={{ height: '48px', zIndex: 100 }}\n onPointerEnter={taskbarVisibility === 'autohide' ? expandTaskbar : undefined}\n onPointerLeave={taskbarVisibility === 'autohide' ? scheduleCollapseTaskbar : undefined}\n >\n {taskbarVisibility === 'autohide' && <div className=\"rdd-taskbar-peek-handle\" />}\n <button\n type=\"button\"\n onClick={() => scrollTaskbar('left')}\n className=\"rdd-taskbar-nav-btn\"\n style={{ display: state.minimized.length > 4 ? 'block' : 'none' }}\n >\n ◀\n </button>\n\n <div\n ref={taskbarRef}\n className=\"rdd-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 if (lastTaskbarPointerTypeRef.current === 'touch') return;\n setHoveredMinimized(null);\n restorePanel(m.id);\n }}\n onContextMenu={(e) => handleMinimizedRightClick(m.id, e)}\n onPointerDown={(e) => {\n lastTaskbarPointerTypeRef.current = e.pointerType;\n if (e.pointerType !== 'touch') return;\n const el = e.currentTarget as HTMLElement;\n const startX = e.clientX;\n const startY = e.clientY;\n const pointerId = e.pointerId;\n let cancelled = false;\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', onShortTap);\n el.removeEventListener('pointercancel', cancel);\n };\n const onShortTap = () => {\n cancel();\n const rect = el.getBoundingClientRect();\n if (hoveredMinimized?.id === m.id) {\n restorePanel(m.id);\n setHoveredMinimized(null);\n } else {\n setHoveredMinimized({ id: m.id, rect, title: m.title, component: m.component, fromTouch: true });\n }\n };\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', onShortTap);\n el.removeEventListener('pointercancel', cancel);\n try { el.setPointerCapture(pointerId); } catch { return; }\n if (navigator.vibrate) navigator.vibrate(10);\n const onEnd = (me: PointerEvent) => {\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onEnd);\n handleMinimizedRightClick(m.id, me as unknown as React.MouseEvent);\n };\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onEnd);\n }, LONG_PRESS_MS);\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', onShortTap);\n el.addEventListener('pointercancel', cancel);\n }}\n onPointerEnter={(e) => {\n if (e.pointerType === 'touch') return;\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 onPointerLeave={(e) => {\n if (e.pointerType === 'touch') return;\n minimizedTooltipTimeoutRef.current = setTimeout(() => {\n setHoveredMinimized(null);\n }, 150);\n }}\n className=\"rdd-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=\"rdd-taskbar-item-icon\">\n {icon}\n </span>\n </div>\n );\n })}\n </div>\n\n {hoveredMinimized && createPortal(\n <div\n className=\"rdd-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 onPointerEnter={() => {\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n }}\n onPointerLeave={(e) => {\n if (e.pointerType === 'touch') return;\n setHoveredMinimized(null);\n }}\n onClick={() => {\n restorePanel(hoveredMinimized.id);\n setHoveredMinimized(null);\n }}\n onContextMenu={(e) => handleMinimizedRightClick(hoveredMinimized.id, e)}\n onPointerDown={(e) => {\n if (e.pointerType !== 'touch') return;\n const tooltipId = hoveredMinimized.id;\n const el = e.currentTarget as HTMLElement;\n const startX = e.clientX;\n const startY = e.clientY;\n const pointerId = e.pointerId;\n let cancelled = false;\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n };\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n try { el.setPointerCapture(pointerId); } catch { return; }\n if (navigator.vibrate) navigator.vibrate(10);\n const onEnd = (me: PointerEvent) => {\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onEnd);\n handleMinimizedRightClick(tooltipId, me as unknown as React.MouseEvent);\n };\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onEnd);\n }, LONG_PRESS_MS);\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', cancel);\n el.addEventListener('pointercancel', cancel);\n }}\n >\n <div className=\"rdd-tooltip-header-row\">\n <span className=\"rdd-tooltip-title-text rdd-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=\"rdd-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=\"rdd-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%' }} dir={state.dir}>\n {renderPanelContent(id, panel, registry)}\n </div>\n </FormContainerProviderWrapper>,\n targetEl,\n id\n );\n })}\n\n {/* 4. Context Menu — only rendered when no parent ContextMenuProvider is in the tree */}\n {ctxMenu === null && (\n <contextMenuAdapter.Component\n ref={contextMenuRef}\n theme=\"dark\"\n formatMessageProvider={formatMessage}\n onShow={() => setInternalContextMenuOpen(true)}\n onHide={() => setInternalContextMenuOpen(false)}\n />\n )}\n\n {/* 5. Dragging Tab Ghost Representation */}\n {state.draggedPanelId !== null && !state.floating.some(w => w.id === state.draggedPanelId) && (\n <div\n className=\"rdd-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, useSyncExternalStore } from 'react';\nimport { useFormContainer } from './FormContainerContext';\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 };\nimport type { ContextMenuItem, ShowContextMenuOptions } from './ContextMenu';\nimport { isSerializable } from './serializable';\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/** The four cardinal directions a panel can be docked relative to another. */\nexport type SplitDirection = 'left' | 'right' | 'top' | 'bottom';\n\n/** All possible drop positions — cardinal directions plus center (same group). */\nexport type DropPosition = SplitDirection | 'center';\n\n/** The target leaf and position for a drag-and-drop dock operation. */\nexport interface DropTarget {\n leafId: string;\n position: DropPosition;\n}\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 * Corner of the workspace a floating window can be pinned to.\n *\n * When `anchor` is set on a `FloatingWindow`, the window is positioned\n * relative to that corner using CSS `right`/`left` + `top`/`bottom` and\n * stacks with other windows sharing the same anchor (8 px gap, uncapped).\n * Dragging a window away from its corner clears the anchor and returns it\n * to free-float mode. The value is RTL-aware — `'top-left'` always means the\n * logical start corner regardless of document direction.\n */\nexport type FloatAnchor = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\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 /** Corner of the workspace this window is pinned to, or null when free-floating. */\n anchor?: FloatAnchor | null;\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; anchor?: FloatAnchor | null };\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 /** Custom per-instance data passed via `openPanel(id, component, { props })`. Unconstrained —\n * any value is accepted, but only a value that passes {@link isSerializable} is actually\n * included in {@link WindowActions.saveLayout}'s output. See {@link PanelInfo.serializable}. */\n props?: Record<string, unknown>;\n /** Whether this panel's current `props` can round-trip through `saveLayout()`/`loadLayout()`.\n * Computed automatically — `true` when no `props` were passed, or when they were and passed\n * {@link isSerializable}. A panel with `serializable: false` still renders and works normally;\n * it's simply excluded from the next `saveLayout()` call (and pruned from `gridRoot`/\n * `floating`/`minimized` in that saved snapshot) rather than corrupting or throwing. */\n serializable: boolean;\n /** Optional dedup key. If another open panel of the same `component` already has this exact\n * key, `openPanel` focuses that existing panel instead of creating a new one — see\n * {@link WindowActions.openPanel}'s `dedupeKey` option and {@link WindowActions.findPanelId}. */\n dedupeKey?: string;\n}\n\n/**\n * Options accepted by {@link WindowActions.openPanel}.\n */\nexport interface OpenPanelOptions<P extends object = Record<string, unknown>> {\n /** Override the panel tab/window title. Accepts a plain string or an i18n message descriptor. */\n title?: string | ContextMenuPredefinedMessage;\n /** Initial placement: `'floating'`, `'docked'` (default when a grid exists), or `'tabbed'`. */\n initialTarget?: 'floating' | 'docked' | 'tabbed';\n /** Pin the new floating window to a workspace corner on creation. Has no effect when\n * `initialTarget` is `'docked'` or `'tabbed'`. */\n anchor?: FloatAnchor | null;\n /** Set `state.activePanelId` to this panel. @default true */\n focus?: boolean;\n /**\n * Custom per-instance data spread onto the panel component alongside `panelId`, matching\n * `openModal`/`openLeftPanel`/`openRightPanel`'s already-unconstrained `props` argument — no\n * type restriction here either. Whether a specific value round-trips through `saveLayout()` is\n * a runtime fact, not a type-level guarantee: see {@link PanelInfo.serializable} and the\n * `'layout:panels-excluded'` event.\n */\n props?: P;\n /**\n * If set, and another currently-open panel of the same `component` already has this exact\n * `dedupeKey`, that existing panel is focused instead of opening a new one — the `id`/`props`\n * passed to *this* call are ignored in that case, the same way re-opening an already-open exact\n * `id` already focuses it instead of duplicating it. Use this when multiple call sites might\n * not agree on the same literal `id` for what is semantically the same entity (e.g. \"the panel\n * for the document at this path\"). See also {@link WindowActions.findPanelId}.\n */\n dedupeKey?: string;\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 /**\n * The ID of the active/focused panel — the one contributions are read from\n * (see `useActivePanelContribution`) and the one drawn with focused chrome.\n *\n * Always a panel the user can actually see: the selected tab of its leaf, or a floating\n * window. Never a minimized panel, except when an app explicitly calls `focusPanel()` on\n * one. Restored layouts resolve it from the saved snapshot's own `activePanelId`, falling\n * back to the first leaf's selected tab — never to an arbitrary entry in `panels`.\n */\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 /** Split ratio for panel cross-target drops (0.1–0.9). Default 0.5. */\n splitRatio: number;\n /** Split ratio for workspace outer-edge drops (0.1–0.9). Default 0.2. */\n edgeSplitRatio: number;\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 * Becomes `state.activePanelId` by default — pass `options.focus: false` to open\n * without stealing focus from whatever is currently active.\n * @param id - Unique instance identifier for this panel.\n * @param component - Component key registered in the panel catalog.\n * @param options.title - Override the panel tab/window title. Accepts a plain string or an i18n message descriptor.\n * @param options.initialTarget - Initial placement: `'floating'`, `'docked'` (default when a grid exists), or `'tabbed'`.\n * @param options.anchor - Pin the new floating window to a workspace corner on creation. Has no effect when `initialTarget` is `'docked'` or `'tabbed'`.\n * @param options.focus - Set `state.activePanelId` to this panel. @default true\n * @param options.props - Custom per-instance data spread onto the component alongside `panelId`. Unconstrained, like `openModal`/`openLeftPanel`/`openRightPanel`'s `props` — see {@link PanelInfo.serializable} for what determines whether it survives `saveLayout()`.\n * @param options.dedupeKey - If another open panel of the same `component` already has this key, that panel is focused instead of opening a new one.\n * @example\n * ```ts\n * // Open floating and pin to the top-right corner:\n * actions.openPanel('layers', 'layertree', { initialTarget: 'floating', anchor: 'top-right' });\n *\n * // Open in the background without stealing focus:\n * actions.openPanel('prefetch', 'report', { focus: false });\n *\n * // Open with per-instance data, deduped by document path:\n * actions.openPanel(crypto.randomUUID(), 'document', {\n * props: { path: '/notes/todo.md' },\n * dedupeKey: '/notes/todo.md',\n * });\n * ```\n */\n openPanel: <P extends object = Record<string, unknown>>(id: string, component: string, options?: OpenPanelOptions<P>) => 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. Omit to use the last known position or a cascaded default.\n * @param anchor - Optional corner to pin the new floating window to. Omit (or pass `null`) for free-float.\n */\n floatPanel: (id: string, rect?: { x: number; y: number; width: number; height: number }, anchor?: FloatAnchor | null) => 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`, or `anchor`.\n */\n updateFloatingPosition: (id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'anchor'>>) => 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 * Finds the ID of an already-open panel of the given `component` with a matching `dedupeKey`\n * (set via `openPanel`'s `dedupeKey` option). Uses a synchronous `stateRef` read — safe to\n * call outside of render.\n * @param component - Component key registered in the panel catalog.\n * @param dedupeKey - The dedup key to search for.\n * @returns The matching panel's ID, or `null` if none is open.\n */\n findPanelId: (component: string, dedupeKey: string) => string | null;\n /**\n * Serializes the entire workspace state to a JSON string.\n * Includes grid layout, floating window positions, minimized panels, panel metadata, and the\n * globally active panel (see {@link SerializedLayout.activePanelId}).\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 *\n * `state.activePanelId` is resolved from the snapshot's own `activePanelId` when that panel is\n * still visible in it, and otherwise from the first leaf's selected tab (which is also the path\n * layouts saved before that field existed take). It is never seeded from an arbitrary entry in\n * `panels`.\n *\n * @param layoutJson - JSON string produced by {@link saveLayout}.\n * @returns `true` if the layout was successfully parsed and applied, `false` otherwise.\n */\n loadLayout: (layoutJson: string) => boolean;\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: DropPosition) => 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 * Registers a callback reporting a docked/floating panel's *current* restorable state, pulled\n * fresh every `saveLayout()` call — for panels whose props alone can't capture state they\n * accumulate after opening (scroll position, an in-progress edit, a view-mode toggle). A panel\n * that registers nothing keeps its static open-time `props` (or none). The returned value goes\n * through the same {@link isSerializable} check as static props, re-evaluated on every save —\n * a provider-backed panel's serializability can flip over its lifetime.\n * @param id - Panel instance ID.\n * @param provider - Called synchronously at each `saveLayout()`; return the current state (or\n * `undefined` to fall back to the static `props` this panel was opened with).\n */\n registerStateProvider: (id: string, provider: () => unknown) => void;\n /**\n * Removes a previously registered state provider.\n * @param id - Panel instance ID.\n */\n unregisterStateProvider: (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: SplitDirection) => void;\n /**\n * Overrides the workspace layout direction.\n * @param dir - `'ltr'` or `'rtl'`.\n */\n setDirection: (dir: 'ltr' | 'rtl') => void;\n /**\n * Imperatively shows the workspace context menu at the given position.\n * Delegates to the active {@link ContextMenuProvider}, so custom adapters\n * and externally-placed providers are respected automatically.\n */\n showContextMenu: (options: ShowContextMenuOptions) => 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 /** @internal */\n registerPanelContextMenu: (panelId: string, getItems: () => ContextMenuItem[]) => () => void;\n /** @internal */\n getPanelContextMenuItems: (panelId: string) => ContextMenuItem[];\n /** @internal */\n registerContextMenuFn: (fn: (options: ShowContextMenuOptions) => void) => () => void;\n}\n\nexport const WindowStateContext: React.Context<WindowState | null> = createContext<WindowState | null>(null);\nconst WindowActionsContext = createContext<InternalWindowActions | null>(null);\nconst WindowI18nContext = createContext<MessageFormatter | null>(null);\n\ninterface WindowStoreSyncContextValue {\n getSnapshot: () => WindowState;\n subscribeToState: (callback: () => void) => () => void;\n}\nconst WindowStoreSyncContext = createContext<WindowStoreSyncContextValue | 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 = (): StyleClasses => 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 = (): PanelRegistryClass => 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\n/** The on-disk shape produced by `saveLayout()` and accepted by `loadLayout()`/`initialState`. */\nexport interface SerializedLayout {\n /** Schema version — absent on layouts saved before this field was introduced (treated as 0). */\n version?: number;\n /**\n * The globally active panel at save time — the one the user was actually looking at.\n *\n * Omitted when nothing was active, and when the active panel didn't survive this snapshot's\n * serializability pruning (see {@link WindowActions.saveLayout}) — so it never names a panel\n * absent from this payload's own `panels`. Absent on every layout saved before this field\n * existed, in which case the restore derives it from `gridRoot`'s own per-leaf selection\n * instead; a present-but-no-longer-valid value falls back to the same derivation. `version`\n * is deliberately not bumped for this: the field is optional and its absence is a supported,\n * fully-handled case rather than a schema a migration has to branch on.\n */\n activePanelId?: string | null;\n gridRoot: LayoutNode;\n floating: FloatingWindow[];\n minimized: { id: string; title: string | ContextMenuPredefinedMessage; component: string }[];\n panels: Record<string, PanelInfo>;\n}\n\ntype ParsedLayoutPayload = Pick<SerializedLayout, 'gridRoot' | 'floating' | 'minimized' | 'panels'> & {\n /** Resolved by `parseLayoutPayload` — the persisted value when still valid, else derived. */\n activePanelId: string | null;\n};\n\n/** The subset of a layout needed to reason about which panel is visibly active. */\ntype ActiveTargetScope = Pick<SerializedLayout, 'gridRoot' | 'floating' | 'panels'>;\n\n/**\n * Whether `id` names a panel the user can actually see, and which may therefore be the globally\n * active one: the selected tab of some leaf, or a floating window. A minimized panel never\n * qualifies — it stays mounted (see the persistence port in `WindowManager.tsx`), so leaving it\n * active would keep routing `useActivePanelContribution()` to a panel that isn't on screen.\n *\n * Used both to validate a persisted `activePanelId` on load and to guard the one written by\n * `saveLayout`, so the two directions can't disagree about what \"active\" is allowed to mean.\n */\nfunction isVisibleActiveTarget(id: string, scope: ActiveTargetScope): boolean {\n const info = scope.panels[id];\n if (!info || info.state === 'minimized') return false;\n if (scope.floating.some(w => w.id === id)) return true;\n const isLeafSelection = (node: LayoutNode): boolean =>\n node.type === 'leaf'\n ? node.activePanelId === id\n : node.children.some(isLeafSelection);\n return scope.gridRoot ? isLeafSelection(scope.gridRoot) : false;\n}\n\n/**\n * Derives the globally active panel for a restored layout.\n *\n * Replaces the original `Object.keys(panels)[0]` seed, which picked the first key of a flat,\n * insertion-ordered record that knows nothing about tab order or docked/floating/minimized — so\n * unless the user happened to have the first-opened panel selected when they saved, the workspace\n * came back with one panel visible and a *different*, invisible one marked active. Every\n * `LayoutLeafNode` already persists its own `activePanelId`, so the answer was on disk all along.\n *\n * Order:\n * 1. The first leaf in document order whose own selected tab is a valid target.\n * 2. Otherwise the frontmost (highest `z`) floating window — matching `focusPanel`'s own\n * \"highest z is on top\" rule, and keeping float-only layouts from restoring with nothing\n * active at all.\n * 3. Otherwise `null`.\n *\n * Depth-first, not breadth-first: for a grid whose first child is itself a split, a level-by-level\n * walk reaches the *second* child's leaf before the first child's leaves and picks the wrong tab.\n * Mirrors `findFirstLeafId`'s traversal shape for exactly that reason.\n */\nfunction deriveActivePanelId(scope: ActiveTargetScope): string | null {\n const isCandidate = (id: string | null): boolean =>\n id !== null && !!scope.panels[id] && scope.panels[id].state !== 'minimized';\n\n const fromLeaves = (node: LayoutNode): string | null => {\n if (node.type === 'leaf') {\n return isCandidate(node.activePanelId) ? node.activePanelId : null;\n }\n for (const child of node.children) {\n const found = fromLeaves(child);\n if (found) return found;\n }\n return null;\n };\n\n const selected = scope.gridRoot ? fromLeaves(scope.gridRoot) : null;\n if (selected) return selected;\n\n let frontmost: FloatingWindow | null = null;\n for (const w of scope.floating) {\n if (!isCandidate(w.id)) continue;\n if (!frontmost || w.z > frontmost.z) frontmost = w;\n }\n return frontmost?.id ?? null;\n}\n\n/**\n * Shared shape-check + migration for a parsed (but not yet validated) layout payload,\n * used by both `parseInitialState` (the `initialState`/`WorkspaceClient.initialState`\n * entry point) and `loadLayout` — previously these duplicated the check independently\n * and only one of them ran the stickyRight/stickyBottom migration, so a layout fed\n * through `initialState` silently skipped it. `version` is read but not yet branched on\n * — it's read here so a future migration has a version to gate on without needing\n * another ad hoc field-presence sniff like this one.\n *\n * Also resolves `activePanelId`, for the same reason the shape-check lives here: both entry\n * points need it and previously seeded it themselves, identically wrongly, in two places.\n */\nfunction parseLayoutPayload(parsed: any): ParsedLayoutPayload | null {\n if (!parsed || !parsed.gridRoot || !Array.isArray(parsed.floating) || !Array.isArray(parsed.minimized) || !parsed.panels) {\n return null;\n }\n // const version = typeof parsed.version === 'number' ? parsed.version : 0; // reserved for future migrations\n const floating = (parsed.floating as any[]).map((fw: any) => {\n if ('stickyRight' in fw || 'stickyBottom' in fw) {\n const anchor: FloatAnchor | null = fw.stickyRight && fw.stickyBottom ? 'bottom-right'\n : fw.stickyRight ? 'top-right'\n : fw.stickyBottom ? 'bottom-left'\n : null;\n const { stickyRight: _sr, stickyBottom: _sb, ...rest } = fw;\n return { ...rest, anchor };\n }\n return fw;\n });\n const scope: ActiveTargetScope = { gridRoot: parsed.gridRoot, floating, panels: parsed.panels };\n\n // A persisted value wins when it still names a visible panel; anything stale (the panel was\n // closed, minimized, or pruned from this snapshot) falls back to deriving from the grid, which\n // is also the path every pre-`activePanelId` layout takes.\n const persisted = typeof parsed.activePanelId === 'string' ? parsed.activePanelId : null;\n let activePanelId: string | null = null;\n if (persisted !== null) {\n if (isVisibleActiveTarget(persisted, scope)) {\n activePanelId = persisted;\n } else if (process.env.NODE_ENV === 'development') {\n console.warn(\n `[react-dockable-desktop] Ignoring the saved layout's activePanelId (\"${persisted}\") — ` +\n `it doesn't name a currently visible panel (it may have been closed, minimized, or ` +\n `excluded from the snapshot as non-serializable). Falling back to the selected tab of ` +\n `the first leaf in the grid.`\n );\n }\n }\n if (activePanelId === null) activePanelId = deriveActivePanelId(scope);\n\n return { gridRoot: parsed.gridRoot, floating, minimized: parsed.minimized, panels: parsed.panels, activePanelId };\n}\n\nfunction parseInitialState(json: string | null): Pick<WindowState, 'gridRoot' | 'floating' | 'minimized' | 'panels' | 'activePanelId'> {\n if (json) {\n try {\n const payload = parseLayoutPayload(JSON.parse(json));\n if (payload) return payload;\n } catch {\n // fall through to empty canvas\n }\n }\n return { gridRoot: EMPTY_LEAF, floating: [], minimized: [], panels: {}, activePanelId: null };\n}\n\n/**\n * Props for `<DockableDesktopProvider>` and `<WindowManagerProvider>`.\n * Also exported as `DockableDesktopProviderProps` for consumers who use\n * the composite provider.\n * @see DockableDesktopProviderProps\n */\nexport interface WindowManagerProviderProps {\n children: React.ReactNode;\n /** `WorkspaceClient` instance created outside the React tree. When provided, its panel\n * registry and config take precedence over the individual props below. */\n client?: WorkspaceClient;\n /** Custom i18n formatter. Receives a `{ id, defaultMessage }` descriptor and returns\n * the translated string. When omitted, `defaultMessage` is used as-is. */\n formatMessage?: MessageFormatter;\n /** Override the built-in predefined UI strings (confirm button labels, close tooltips, etc.).\n * Merge with or replace `defaultPredefinedMessages` to localise system strings. */\n predefinedMessages?: Record<string, ContextMenuPredefinedMessage>;\n /** Layout direction. `'rtl'` mirrors all controls, tab order, and drop zones.\n * Can also be changed at runtime via `WorkspaceClient.setDirection()`. @default 'ltr' */\n dir?: 'ltr' | 'rtl';\n /** CSS class applied to the outer wrapper element of every modal overlay. */\n modalClass?: string;\n /** CSS class applied to the inner content area of every modal overlay. */\n modalBodyClass?: string;\n /** CSS class applied to the outer wrapper of left/right side-panel drawers. */\n sidePanelClass?: string;\n /** CSS class applied to the inner content area of side-panel drawers. */\n sidePanelBodyClass?: string;\n /** CSS class applied to the outer wrapper of floating panel windows. */\n windowClass?: string;\n /** CSS class applied to the inner content area of floating panel windows. */\n windowBodyClass?: string;\n /**\n * Starting z-index for floating windows and the library's own chrome overlays\n * (context menu, toolbar flyout, modal stack, toast, workspace edge zones),\n * all of which shift together via `--rdd-z-base`. Set this above/below a host\n * app's own modal z-index range to control stacking against it. @default 1000\n */\n zIndexBase?: number;\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 zIndexBase: zIndexBaseProp\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 const effectiveZIndexBase = client?.config.zIndexBase ?? zIndexBaseProp ?? 1000;\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 splitRatio: Math.min(0.9, Math.max(0.1, client?.config.defaultSplitRatio ?? 0.5)),\n edgeSplitRatio: Math.min(0.9, Math.max(0.1, client?.config.defaultEdgeSplitRatio ?? 0.2)),\n };\n });\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const stateSubscribersRef = useRef<Set<() => void>>(new Set());\n\n useEffect(() => {\n stateSubscribersRef.current.forEach(cb => cb());\n }, [state]);\n\n const getSnapshot = useCallback((): WindowState => stateRef.current, []);\n const subscribeToState = useCallback((cb: () => void): (() => void) => {\n stateSubscribersRef.current.add(cb);\n return () => stateSubscribersRef.current.delete(cb);\n }, []);\n\n const closeGuardsRef = useRef<Record<string, () => boolean | Promise<boolean>>>({});\n const stateProvidersRef = useRef<Record<string, () => unknown>>({});\n\n const mergedMessages = useMemo(() => ({\n ...defaultPredefinedMessages,\n ...effectivePredefinedMessages\n }), [effectivePredefinedMessages]);\n\n const eventBusRef = useRef(new PanelEventBus());\n const maxZRef = useRef(effectiveZIndexBase);\n\n // Mirror the z-index base onto document.documentElement as a CSS variable so the\n // library's portaled chrome (ContextMenu, Toast, Toolbar's flyout, ModalStackRenderer),\n // which renders outside this provider's own DOM subtree, shifts in lockstep with\n // maxZRef — same rationale as the data-workspace-skin mirroring in WindowManager.tsx.\n useEffect(() => {\n document.documentElement.style.setProperty('--rdd-z-base', String(effectiveZIndexBase));\n return () => { document.documentElement.style.removeProperty('--rdd-z-base'); };\n }, [effectiveZIndexBase]);\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 setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n if (panel.state === 'floating') {\n const win = prev.floating.find(w => w.id === id);\n if (!win) return prev;\n const alreadyTop = !prev.floating.some(w => w.z > win.z);\n if (alreadyTop && prev.activePanelId === id) return prev; // no-op — StrictMode safe\n if (!alreadyTop) maxZRef.current += 1;\n return {\n ...prev,\n floating: prev.floating.map(w =>\n w.id === id ? { ...w, z: alreadyTop ? win.z : maxZRef.current } : w\n ),\n activePanelId: id\n };\n } else if (panel.state === 'docked') {\n if (prev.activePanelId === id) return prev; // no-op\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 if (prev.activePanelId === id) return prev; // no-op for minimized\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(<P extends object = Record<string, unknown>>(id: string, component: string, options?: OpenPanelOptions<P>) => {\n // Dedup redirect: resolve to an already-open panel of the same component/dedupeKey, if any,\n // before anything else runs — the caller's own `id`/`props` are ignored for this call in\n // that case, the same way re-opening an already-open exact `id` already focuses it instead\n // of duplicating it.\n let resolvedId = id;\n if (options?.dedupeKey !== undefined) {\n const match = Object.values(stateRef.current.panels).find(\n p => p.component === component && p.dedupeKey === options.dedupeKey\n );\n if (match) resolvedId = match.id;\n }\n const isNew = !(resolvedId in stateRef.current.panels);\n const isRedirect = resolvedId !== id;\n const shouldFocus = options?.focus !== false;\n const propsProvided = options?.props !== undefined;\n const serializable = propsProvided ? isSerializable(options.props) : true;\n setState(prev => {\n const exists = prev.panels[resolvedId];\n const entry = registry.get(component);\n const title = options?.title || options?.title || entry?.defaultOptions?.title || resolvedId;\n const target = options?.initialTarget || entry?.defaultOptions?.initialTarget || 'docked';\n const favPos = entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n const activePanelId = shouldFocus ? resolvedId : prev.activePanelId;\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 !== resolvedId);\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: resolvedId, z: maxZRef.current }],\n panels: { ...prev.panels, [resolvedId]: { ...exists, state: 'floating' } },\n activePanelId\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-default';\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, resolvedId),\n panels: { ...prev.panels, [resolvedId]: { ...exists, state: 'docked' } },\n activePanelId\n };\n }\n } else if (exists.state === 'floating') {\n if (shouldFocus) focusPanel(resolvedId);\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(resolvedId)) {\n return { ...node, activePanelId: resolvedId };\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\n };\n }\n }\n\n // Case 2: New panel\n const targetState = target === 'tabbed' ? 'docked' : target;\n const newPanelInfo: PanelInfo = {\n id: resolvedId,\n title,\n component,\n state: targetState,\n props: options?.props as Record<string, unknown> | undefined,\n serializable,\n dedupeKey: options?.dedupeKey,\n };\n const nextPanels = { ...prev.panels, [resolvedId]: newPanelInfo };\n\n if (target === 'floating') {\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n\n const anchor = options?.anchor ?? entry?.defaultOptions?.defaultAnchor ?? null;\n\n return {\n ...prev,\n floating: [...prev.floating, { ...cascaded, id: resolvedId, z: maxZRef.current, anchor }],\n panels: nextPanels,\n activePanelId\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-default';\n return {\n ...prev,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, resolvedId),\n panels: nextPanels,\n activePanelId\n };\n }\n });\n if (isNew) eventBusRef.current.publish('panel:opened', { id: resolvedId, component });\n if (isNew || isRedirect) eventBusRef.current.publish('layout:changed', {});\n }, [getCascadedPosition, focusPanel]);\n\n const closePanel = useCallback((id: string) => {\n const exists = id in stateRef.current.panels;\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 delete stateProvidersRef.current[id];\n\n const nextPanels = { ...prev.panels };\n delete nextPanels[id];\n\n const nextRoot = removePanelFromTree(prev.gridRoot, id)\n || { type: 'leaf' as const, id: 'group-default', panels: [], activePanelId: null };\n const nextFloating = prev.floating.filter(w => w.id !== id);\n\n // Closing the active panel used to leave `activePanelId` pointing at the panel just deleted.\n // `removePanelFromTree` has already promoted the next tab in its leaf, so re-deriving picks\n // whatever the user can now actually see.\n const nextActivePanelId = prev.activePanelId === id\n ? deriveActivePanelId({ gridRoot: nextRoot, floating: nextFloating, panels: nextPanels })\n : prev.activePanelId;\n\n return {\n ...prev,\n gridRoot: nextRoot,\n floating: nextFloating,\n minimized: prev.minimized.filter(m => m.id !== id),\n panels: nextPanels,\n activePanelId: nextActivePanelId\n };\n });\n if (exists) {\n eventBusRef.current.publish('panel:closed', { id });\n eventBusRef.current.publish('layout:changed', {});\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 registerStateProvider = useCallback((id: string, provider: () => unknown) => {\n stateProvidersRef.current[id] = provider;\n }, []);\n\n const unregisterStateProvider = useCallback((id: string) => {\n delete stateProvidersRef.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 const wasActive = stateRef.current.panels[id]?.state !== 'minimized' && id in stateRef.current.panels;\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: PanelInfo['lastFloatingRect'] = undefined;\n let lastLeafId: string | undefined = undefined;\n\n if (panel.state === 'floating') {\n const win = prev.floating.find(w => w.id === id);\n if (win) {\n lastFloatingRect = {\n x: Number(win.x),\n y: Number(win.y),\n width: Number(win.width),\n height: Number(win.height),\n anchor: win.anchor ?? null\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) ?? undefined;\n }\n\n const nextRoot = removePanelFromTree(prev.gridRoot, id)\n || { type: 'leaf' as const, id: 'group-default', panels: [], activePanelId: null };\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const nextPanels: Record<string, PanelInfo> = {\n ...prev.panels,\n [id]: {\n ...panel,\n state: 'minimized',\n previousState: panel.state,\n lastFloatingRect,\n lastLeafId\n }\n };\n\n // A minimized panel is off screen but still mounted (see the persistence port in\n // WindowManager.tsx), so leaving it active kept `useActivePanelContribution()` — and every\n // contributed control — wired to a panel the user can't see. `deriveActivePanelId` skips\n // minimized panels, so this lands on whatever became visible in its place.\n const nextActivePanelId = prev.activePanelId === id\n ? deriveActivePanelId({ gridRoot: nextRoot, floating: nextFloating, panels: nextPanels })\n : prev.activePanelId;\n\n return {\n ...prev,\n gridRoot: nextRoot,\n floating: nextFloating,\n minimized: [...prev.minimized, { id, title: panel.title, component: panel.component }],\n panels: nextPanels,\n activePanelId: nextActivePanelId\n };\n });\n if (wasActive) {\n eventBusRef.current.publish('panel:minimized', { id });\n eventBusRef.current.publish('layout:changed', {});\n }\n }, []);\n\n const restorePanel = useCallback((id: string) => {\n const wasMinimized = stateRef.current.panels[id]?.state === 'minimized';\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 anchor: panel.lastFloatingRect?.anchor ?? null\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 anchor: panel.lastFloatingRect?.anchor ?? null\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 if (wasMinimized) {\n eventBusRef.current.publish('panel:restored', { id });\n eventBusRef.current.publish('layout:changed', {});\n }\n }, [getCascadedPosition]);\n\n const floatPanel = useCallback((id: string, rect?: { x: number; y: number; width: number; height: number }, anchor?: FloatAnchor | null) => {\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, anchor: anchor ?? null }],\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: SplitDirection,\n splitRatio: number\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 const sizes = (position === 'left' || position === 'top')\n ? [splitRatio, 1 - splitRatio]\n : [1 - splitRatio, splitRatio];\n return {\n type: 'branch',\n orientation,\n sizes,\n children\n };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(c => splitLeafInTree(c, leafId, panelId, position, splitRatio))\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: DropPosition) => {\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, prev.splitRatio);\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: SplitDirection) => {\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 r = prev.edgeSplitRatio;\n const newRoot: LayoutNode = {\n type: 'branch',\n orientation,\n sizes: (position === 'left' || position === 'top') ? [r, 1 - r] : [1 - r, r],\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' | 'anchor'>>) => {\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 const currentPanels = stateRef.current.panels;\n const excludedIds: string[] = [];\n const includedPanels: Record<string, PanelInfo> = {};\n\n // A registered state provider (see registerStateProvider) is pulled fresh on every save —\n // a panel's serializability can flip over its lifetime, so this is never cached from open\n // time for provider-backed panels. Panels with no provider keep their static open-time\n // props/serializable classification unchanged.\n for (const [id, info] of Object.entries(currentPanels)) {\n const provider = stateProvidersRef.current[id];\n const dynamicValue = provider?.();\n const hasDynamicValue = provider !== undefined && dynamicValue !== undefined;\n const effectiveProps = hasDynamicValue ? (dynamicValue as Record<string, unknown>) : info.props;\n const effectiveSerializable = hasDynamicValue ? isSerializable(dynamicValue) : info.serializable;\n\n if (effectiveSerializable) {\n includedPanels[id] = hasDynamicValue ? { ...info, props: effectiveProps, serializable: effectiveSerializable } : info;\n } else {\n excludedIds.push(id);\n }\n }\n\n // Non-serializable panels are excluded from this saved snapshot — pruned from gridRoot/\n // floating/minimized too, so a restore never references a panel with no data to recreate it\n // meaningfully. This computes a derived copy for the JSON string only; none of this touches\n // stateRef/setState, so the live, on-screen workspace is completely unaffected — an excluded\n // panel keeps existing and working normally on screen, it simply won't be there after the\n // *next* loadLayout().\n let gridRoot = stateRef.current.gridRoot;\n let floating = stateRef.current.floating;\n let minimized = stateRef.current.minimized;\n for (const id of excludedIds) {\n gridRoot = removePanelFromTree(gridRoot, id) || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null };\n floating = floating.filter(w => w.id !== id);\n minimized = minimized.filter(m => m.id !== id);\n }\n\n if (excludedIds.length > 0) {\n eventBusRef.current.publish('layout:panels-excluded', {\n panels: excludedIds.map(id => ({ id, component: currentPanels[id].component }))\n });\n }\n\n // Validated against the *pruned* snapshot, not the live state: if the active panel was itself\n // excluded above, or is minimized, the field is omitted entirely rather than persisted as an id\n // this payload's own `panels` doesn't contain. A restore then derives it — see\n // `deriveActivePanelId`.\n const liveActive = stateRef.current.activePanelId;\n const activePanelId = liveActive !== null && isVisibleActiveTarget(liveActive, { gridRoot, floating, panels: includedPanels })\n ? liveActive\n : null;\n\n const payload: SerializedLayout = {\n version: 2, // v2: panels may carry `props`/`dedupeKey`; the payload may omit panels the\n // live workspace still has open (see the exclusion pass above).\n ...(activePanelId !== null ? { activePanelId } : {}),\n gridRoot,\n floating,\n minimized,\n panels: includedPanels\n };\n return JSON.stringify(payload);\n }, []);\n\n const loadLayout = useCallback((layoutJson: string): boolean => {\n try {\n const payload = parseLayoutPayload(JSON.parse(layoutJson));\n if (!payload) return false;\n setState(prev => ({\n ...prev,\n gridRoot: payload.gridRoot,\n floating: payload.floating,\n minimized: payload.minimized,\n panels: payload.panels,\n draggedPanelId: null,\n activePanelId: payload.activePanelId\n }));\n return true;\n } catch (e) {\n console.error('Failed to parse layout configuration:', e);\n return false;\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 const findPanelId = useCallback((component: string, dedupeKey: string): string | null => {\n const match = Object.values(stateRef.current.panels).find(\n p => p.component === component && p.dedupeKey === dedupeKey\n );\n return match?.id ?? null;\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 customMenuGettersRef = useRef<Map<string, () => ContextMenuItem[]>>(new Map());\n\n const showContextMenuFnRef = useRef<((options: ShowContextMenuOptions) => void) | null>(null);\n const registerContextMenuFn = useCallback(\n (fn: (options: ShowContextMenuOptions) => void) => {\n showContextMenuFnRef.current = fn;\n return () => { showContextMenuFnRef.current = null; };\n }, []\n );\n const showContextMenu = useCallback((options: ShowContextMenuOptions) => {\n showContextMenuFnRef.current?.(options);\n }, []);\n\n const registerPanelContextMenu = useCallback(\n (panelId: string, getItems: () => ContextMenuItem[]) => {\n customMenuGettersRef.current.set(panelId, getItems);\n return () => { customMenuGettersRef.current.delete(panelId); };\n }, []\n );\n\n const getPanelContextMenuItems = useCallback(\n (panelId: string): ContextMenuItem[] =>\n customMenuGettersRef.current.get(panelId)?.() ?? [],\n []\n );\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 findPanelId,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n registerStateProvider,\n unregisterStateProvider,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection,\n registerPanelContextMenu,\n getPanelContextMenuItems,\n showContextMenu,\n registerContextMenuFn,\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 findPanelId,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n registerStateProvider,\n unregisterStateProvider,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection,\n registerPanelContextMenu,\n getPanelContextMenuItems,\n showContextMenu,\n registerContextMenuFn,\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\n // Check 1: styles.css sentinel — catches the \"forgot to import\" case precisely\n try {\n const sentinel = getComputedStyle(document.documentElement)\n .getPropertyValue('--rdd-styles-loaded').trim();\n if (sentinel !== '1') {\n console.error(\n \"[react-dockable-desktop] styles.css is not imported.\\n\" +\n \"Add this to your entry file (main.tsx / index.tsx):\\n\" +\n \" import 'react-dockable-desktop/styles.css'\\n\" +\n \"Without it the workspace renders as a black screen with no console errors.\"\n );\n }\n } catch { /* getComputedStyle unavailable (SSR) */ }\n\n }, []);\n\n useEffect(() => {\n if (client) {\n client._connect(actions);\n return () => { client._disconnect(); };\n }\n }, [client, actions]);\n\n const syncContextValue = useMemo<WindowStoreSyncContextValue>(\n () => ({ getSnapshot, subscribeToState }),\n [getSnapshot, subscribeToState]\n );\n\n return (\n <StyleClassContext.Provider value={styleClasses}>\n <RegistryContext.Provider value={registry}>\n <WindowStoreSyncContext.Provider value={syncContextValue}>\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 </WindowStoreSyncContext.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 */\nconst noopSubscribe = (_cb: () => void): (() => void) => () => {};\n\nexport function useWindowManagerState(): WindowState;\nexport function useWindowManagerState<T>(selector: (state: WindowState) => T): T;\nexport function useWindowManagerState<T>(selector?: (state: WindowState) => T): WindowState | T {\n const stateCtx = useContext(WindowStateContext);\n const syncCtx = useContext(WindowStoreSyncContext);\n const selectorRef = useRef<((state: WindowState) => T) | undefined>(selector);\n selectorRef.current = selector;\n\n const syncResult = useSyncExternalStore(\n selector ? (syncCtx?.subscribeToState ?? noopSubscribe) : noopSubscribe,\n (): T => {\n const snap = syncCtx?.getSnapshot() ?? stateCtx!;\n return (selectorRef.current ? selectorRef.current(snap) : snap) as T;\n },\n (): T => {\n const snap = syncCtx?.getSnapshot() ?? stateCtx!;\n return (selectorRef.current ? selectorRef.current(snap) : snap) as T;\n }\n );\n\n if (!stateCtx) throw new Error('useWindowManagerState must be used within WindowManagerProvider');\n if (!selector) return stateCtx;\n return syncResult;\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 = (): MessageFormatter => {\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 = (): Pick<WindowActions, 'publish' | 'subscribe'> => {\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 = (): Record<PredefinedMessageKey, ContextMenuPredefinedMessage> => {\n return useContext(WindowPredefinedMessagesContext);\n};\n\n/**\n * React hook to retrieve the panel instance ID for the component currently rendered inside\n * the dockable desktop. Works for docked, floating, modal, and side-panel containers.\n * Opt-in — components that don't need the ID require no changes.\n *\n * @group Hooks\n * @returns The unique panel instance ID string.\n * @example\n * ```tsx\n * function MyPanel() {\n * const panelId = usePanelId();\n * const { closePanel } = useWindowManagerActions();\n * return <button onClick={() => closePanel(panelId)}>Close</button>;\n * }\n * ```\n */\nexport const usePanelId = (): string => useFormContainer().instanceId;\n\n/**\n * React hook for injecting custom context menu items into a panel's context menu from inside the panel component.\n * Items are dynamic — the array is re-read each time the menu opens, so state-driven changes (enable/disable, add/remove) work automatically.\n * The hook reads the panel ID internally via {@link usePanelId} — no prop needed.\n *\n * @param items - Array of `ContextMenuItem` entries (simple items, separators, submenus).\n * @example\n * ```tsx\n * import { usePanelContextMenu } from 'dockable-windows';\n *\n * function MyPanel() {\n * const [dirty, setDirty] = useState(false);\n * usePanelContextMenu([\n * { label: 'Save', action: () => save() },\n * { label: 'Revert', action: () => revert() },\n * ]);\n * return <Editor onChange={() => setDirty(true)} />;\n * }\n * ```\n */\nexport function usePanelContextMenu(items: ContextMenuItem[]): void {\n const ctx = useContext(WindowActionsContext);\n const panelId = usePanelId();\n const itemsRef = useRef(items);\n itemsRef.current = items;\n\n useEffect(() => {\n if (!ctx?.registerPanelContextMenu || !panelId) return;\n return ctx.registerPanelContextMenu(panelId, () => itemsRef.current);\n }, [panelId, ctx?.registerPanelContextMenu]);\n}\n","import { createContext, useContext, useSyncExternalStore, type Context, type Provider } 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 =\n | 'left-panel'\n | 'right-panel'\n | 'modal'\n | 'dockable-panel' // panel currently docked in the grid\n | 'floating-window' // panel currently in a detached floating window\n | '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 /**\n * Registers a callback reporting this panel's *current* restorable state, pulled fresh by\n * `WorkspaceClient.saveLayout()` every time it's called — for panels whose static open-time\n * props can't capture state accumulated after opening (scroll position, an in-progress edit, a\n * view-mode toggle). Only meaningful for docked/floating panels — left/right side panels and\n * modals already have a complete answer to this via `openLeftPanel`/`openRightPanel`/\n * `openModal`'s own `props` argument plus `updateInstance`, so this is `undefined` there.\n * The returned value must be synchronous — `saveLayout()` itself never returns a `Promise`.\n * Return `undefined` to fall back to the static `props` this panel was opened with.\n */\n registerStateProvider?: (getState: () => unknown) => (() => 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. Reflects the state at mount time; subscribe to {@link onContainerTypeChange} for live updates. */\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. Returns an unsubscribe function. */\n onResize?: (handler: (width: number, height: number) => void) => () => void;\n /** Request the container to minimize itself to the taskbar. No-op if the container type does not support minimize. */\n requestMinimize?: () => void;\n /** Returns the current rendered dimensions of this panel, or `null` if the panel has not been laid out yet. */\n getDimensions?: () => { width: number; height: number } | null;\n /**\n * Subscribe to this panel becoming the globally active panel.\n * Fires when `activePanelId` transitions to this panel's id.\n * Returns an unsubscribe function.\n */\n onActivate?: (handler: () => void) => () => void;\n /**\n * Subscribe to this panel losing active status.\n * Fires when `activePanelId` transitions away from this panel's id,\n * and also fires if the panel is destroyed while it is active.\n * Returns an unsubscribe function.\n */\n onDeactivate?: (handler: () => void) => () => void;\n /**\n * Subscribe to changes in the panel's container type (e.g. docked ↔ floating).\n * Does not fire for minimize/restore cycles — use {@link onMinimize} / {@link onRestore} for those.\n * Returns an unsubscribe function.\n */\n onContainerTypeChange?: (handler: (type: ContainerType) => 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 registerStateProvider: () => () => {},\n setTitle: () => {},\n setIcon: () => {},\n containerType: 'standalone',\n instanceId: 'standalone',\n onClose: () => () => {},\n onMinimize: () => () => {},\n onRestore: () => () => {},\n onResize: () => () => {},\n requestMinimize: () => {},\n getDimensions: () => null,\n onActivate: () => () => {},\n onDeactivate: () => () => {},\n onContainerTypeChange: () => () => {},\n};\n\n/**\n * Context that supplies the {@link FormContainerContract} to panels inside the Window Manager.\n */\nexport const FormContainerContext: Context<FormContainerContract> = createContext<FormContainerContract>(defaultContract);\nexport const FormContainerProvider: Provider<FormContainerContract> = FormContainerContext.Provider;\n\n/**\n * React hook to retrieve the current {@link FormContainerContract} from context.\n * Enables sub-forms to trigger close/minimize requests, mark themselves dirty,\n * rename their tabs, query dimensions, or subscribe to lifecycle events\n * (resize, close, minimize, restore, activate, deactivate, container-type changes).\n */\nexport const useFormContainer = (): FormContainerContract => {\n return useContext(FormContainerContext);\n};\n\n/**\n * Reactive alternative to calling {@link FormContainerContract.getDimensions} yourself.\n * Returns the panel's current `{ width, height }`, or `null` before it has been laid\n * out, and re-renders whenever the panel's rendered box changes — including resizes\n * caused by the workspace itself (a grid split being dragged, docking, floating, or\n * tab activation), not just resizes of an element the panel created.\n */\nexport const usePanelSize = (): { width: number; height: number } | null => {\n const { onResize, getDimensions } = useFormContainer();\n return useSyncExternalStore(\n (onStoreChange) => (onResize ? onResize(() => onStoreChange()) : () => {}),\n () => (getDimensions ? getDimensions() : null)\n );\n};\n","import type { ComponentType } from 'react';\nimport type { FloatAnchor } from './WindowManagerContext';\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 /** Corner of the workspace to anchor newly-opened floating windows to. */\n defaultAnchor?: FloatAnchor;\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: PanelRegistryClass = 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 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","import { isValidElement } from 'react';\n\n/**\n * Recursively checks whether a value can round-trip through `JSON.stringify`/`JSON.parse`\n * without silently losing information.\n *\n * Deliberately **not** a `JSON.stringify` try/catch — that call doesn't throw for the actual\n * failure case this guards against: a function-valued property is simply dropped by\n * `JSON.stringify`, not rejected. This walks the value tree instead, returning `false` as soon as\n * it finds a function, symbol, `undefined`, React element, or any non-plain object (a class\n * instance, `Map`, `Set`, `RegExp`, etc.).\n *\n * `Date` is treated as an explicit exception — serializable-enough, matching `JSON.stringify`'s\n * own behavior — even though it doesn't round-trip back to a `Date` instance on parse. That's a\n * smaller, more tolerable gotcha than a silently-vanishing function, so it's documented rather\n * than treated as a disqualifying case.\n *\n * Used to decide whether a docked/floating panel's `props` can be included in\n * `WorkspaceClient.saveLayout()`'s output — see {@link PanelInfo.serializable}.\n */\nexport function isSerializable(value: unknown): boolean {\n if (value === null) return true;\n if (value === undefined) return false;\n\n const type = typeof value;\n if (type === 'string' || type === 'number' || type === 'boolean') return true;\n if (type === 'function' || type === 'symbol' || type === 'bigint') return false;\n\n // type === 'object' from here on.\n if (value instanceof Date) return true;\n if (isValidElement(value)) return false;\n if (Array.isArray(value)) return value.every(isSerializable);\n\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return false; // class instance, Map, Set, RegExp, Error, etc.\n\n return Object.values(value as Record<string, unknown>).every(isSerializable);\n}\n","import React, {\n forwardRef,\n useImperativeHandle,\n useState,\n useRef,\n useEffect,\n useLayoutEffect,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport type { ContextMenuLabel, MessageFormatter, MenuItemAction } from './contextMenuTypes';\n\n// ─── Re-export shared primitives so callers don't need contextMenuTypes.ts ───\nexport type { ContextMenuLabel, MessageFormatter, MenuItemAction };\n\n// ─── Item type shapes (identical surface to former replace-react-contexify) ───\n\nexport interface ContextMenuCheckbox {\n /** Whether the checkbox column renders at all (default: true). */\n active?: boolean;\n /** Whether the item is interactive (default: true). Prefer top-level `disabled` on the item instead. */\n enabled?: boolean;\n /** Current checked state. */\n value: boolean;\n}\n\nexport interface ContextMenuSimpleItem {\n label: ContextMenuLabel;\n icon?: React.ReactNode;\n title?: ContextMenuLabel;\n checkbox?: ContextMenuCheckbox;\n action?: MenuItemAction;\n cyAction?: string;\n disabled?: boolean;\n}\n\nexport interface ContextMenuSeparator {\n separator: true;\n}\n\nexport interface ContextMenuSubMenu {\n label: ContextMenuLabel;\n title?: ContextMenuLabel;\n items?: ContextMenuItem[];\n}\n\nexport type ContextMenuItem = ContextMenuSimpleItem | ContextMenuSeparator | ContextMenuSubMenu;\n\n// ─── Imperative API ───────────────────────────────────────────────────────────\n\nexport interface ShowContextMenuOptions {\n event?: React.MouseEvent | React.TouchEvent | MouseEvent | TouchEvent;\n x?: number;\n y?: number;\n items: ContextMenuItem[];\n}\n\nexport interface ContextMenuHandle {\n show(options: ShowContextMenuOptions): void;\n}\n\n// ─── Component props ──────────────────────────────────────────────────────────\n\nexport interface ContextMenuProps {\n theme?: string;\n animation?: string;\n formatMessageProvider?: MessageFormatter;\n onShow?: () => void;\n onHide?: () => void;\n onOpenChange?: (open: boolean) => void;\n className?: string;\n style?: React.CSSProperties;\n}\n\n// ─── Adapter interface (strategy pattern) ────────────────────────────────────\n\nexport interface ContextMenuAdapter {\n Component: React.ForwardRefExoticComponent<\n ContextMenuProps & React.RefAttributes<ContextMenuHandle>\n >;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nfunction getCoords(\n event: ShowContextMenuOptions['event'],\n): { x: number; y: number } {\n if (!event) return { x: 0, y: 0 };\n if ('touches' in event && event.touches.length > 0) {\n return { x: event.touches[0].clientX, y: event.touches[0].clientY };\n }\n return { x: (event as MouseEvent).clientX, y: (event as MouseEvent).clientY };\n}\n\nfunction resolveLabel(label: ContextMenuLabel, fmt?: MessageFormatter): string {\n if (typeof label === 'string') return label;\n if (fmt) return fmt(label);\n return label.defaultMessage ?? label.id;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is ContextMenuSeparator {\n return 'separator' in item;\n}\n\nfunction isSubMenu(item: ContextMenuItem): item is ContextMenuSubMenu {\n return !isSeparator(item) && 'items' in item;\n}\n\n// ─── Sub-menu panel (one-level deep) ─────────────────────────────────────────\n\ninterface SubMenuPanelProps {\n items: ContextMenuItem[];\n x: number;\n y: number;\n theme: string;\n fmt?: MessageFormatter;\n onClose: () => void;\n onMouseEnter: () => void;\n onMouseLeave: () => void;\n}\n\nconst SubMenuPanel = forwardRef<HTMLDivElement, SubMenuPanelProps>(\n ({ items, x, y, theme, fmt, onClose, onMouseEnter, onMouseLeave }, ref) => {\n useLayoutEffect(() => {\n const el = (ref as React.RefObject<HTMLDivElement>)?.current;\n if (!el) return;\n const r = el.getBoundingClientRect();\n const PAD = 8;\n if (r.right > window.innerWidth - PAD) {\n el.style.left = `${Math.max(PAD, window.innerWidth - r.width - PAD)}px`;\n el.style.right = 'auto';\n }\n if (r.bottom > window.innerHeight - PAD) {\n el.style.top = `${Math.max(PAD, window.innerHeight - r.height - PAD)}px`;\n }\n if (r.left < PAD) { el.style.left = `${PAD}px`; el.style.right = 'auto'; }\n if (r.top < PAD) el.style.top = `${PAD}px`;\n });\n\n return createPortal(\n <div\n ref={ref}\n className={`rdd-context-menu rdd-context-menu--${theme} rdd-context-menu--submenu`}\n // z-index from .rdd-context-menu--submenu (+8501) — see the main menu's note below.\n style={{ position: 'fixed', left: x, top: y }}\n role=\"menu\"\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n >\n {items.map((item, i) => {\n if (isSeparator(item)) {\n return <hr key={i} className=\"rdd-context-menu__separator\" role=\"separator\" />;\n }\n const simple = item as ContextMenuSimpleItem;\n const showChk = simple.checkbox && simple.checkbox.active !== false;\n const isChecked = showChk && simple.checkbox!.value;\n const isDisabled = simple.disabled === true || (showChk ? simple.checkbox!.enabled === false : false);\n return (\n <button\n key={i}\n type=\"button\"\n className={`rdd-context-menu__item${isDisabled ? ' rdd-context-menu__item--disabled' : ''}`}\n title={simple.title ? resolveLabel(simple.title, fmt) : undefined}\n disabled={isDisabled}\n data-cy-action={simple.cyAction}\n onClick={() => { if (!isDisabled) { simple.action?.(); onClose(); } }}\n role=\"menuitem\"\n aria-checked={showChk ? isChecked : undefined}\n >\n {simple.icon\n ? <span className=\"rdd-context-menu__icon\">{simple.icon}</span>\n : <span className=\"rdd-context-menu__icon\" aria-hidden=\"true\" />}\n <span className=\"rdd-context-menu__label\">{resolveLabel(simple.label, fmt)}</span>\n {showChk && (\n <span className={`rdd-context-menu__checkbox${isChecked ? ' rdd-context-menu__checkbox--checked' : ''}`} aria-hidden=\"true\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"0.75\" y=\"0.75\" width=\"10.5\" height=\"10.5\" rx=\"2\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n {isChecked && (\n <path d=\"M2.5 6 L4.5 8.5 L9.5 3.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n )}\n </svg>\n </span>\n )}\n </button>\n );\n })}\n </div>,\n document.body,\n );\n },\n);\n\nSubMenuPanel.displayName = 'ContextMenuSubMenuPanel';\n\n// ─── Main component ───────────────────────────────────────────────────────────\n\ninterface MenuState {\n visible: boolean;\n x: number;\n y: number;\n items: ContextMenuItem[];\n}\n\nconst CLOSED: MenuState = { visible: false, x: 0, y: 0, items: [] };\n\nexport const ContextMenu: React.ForwardRefExoticComponent<ContextMenuProps & React.RefAttributes<ContextMenuHandle>> = forwardRef<ContextMenuHandle, ContextMenuProps>(\n ({ theme = 'dark', formatMessageProvider, onShow, onHide, onOpenChange, className, style }, ref) => {\n const [menuState, setMenuState] = useState<MenuState>(CLOSED);\n const [submenuIndex, setSubmenuIndex] = useState<number | null>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const submenuPanelRef = useRef<HTMLDivElement>(null);\n const itemRefs = useRef<Map<number, HTMLButtonElement | null>>(new Map());\n const timers = useRef<{\n open: ReturnType<typeof setTimeout> | null;\n close: ReturnType<typeof setTimeout> | null;\n }>({ open: null, close: null });\n\n const close = React.useCallback(() => {\n setMenuState(CLOSED);\n setSubmenuIndex(null);\n timers.current.open && clearTimeout(timers.current.open);\n timers.current.close && clearTimeout(timers.current.close);\n timers.current.open = null;\n timers.current.close = null;\n onHide?.();\n onOpenChange?.(false);\n }, [onHide, onOpenChange]);\n\n useImperativeHandle(ref, () => ({\n show({ event, x, y, items }) {\n const coords = event ? getCoords(event) : { x: x ?? 0, y: y ?? 0 };\n itemRefs.current.clear();\n setMenuState({ visible: true, x: coords.x, y: coords.y, items });\n setSubmenuIndex(null);\n onShow?.();\n onOpenChange?.(true);\n },\n }), [onShow, onOpenChange]);\n\n // Click-outside dismiss\n // Two listeners for full coverage:\n // pointerdown (capture) — fires before any canvas gesture handler; catches touch/stylus\n // click (bubble, window) — synthetic click survives stopPropagation on mousedown/pointerdown;\n // this is the reliable fallback for WebGL canvases (LuciadRIA, MapLibre, Three.js, etc.)\n useEffect(() => {\n if (!menuState.visible) return;\n const dismiss = (e: Event) => {\n if (menuRef.current?.contains(e.target as Node)) return;\n if (submenuPanelRef.current?.contains(e.target as Node)) return;\n close();\n };\n document.addEventListener('pointerdown', dismiss, { capture: true });\n window.addEventListener('click', dismiss);\n return () => {\n document.removeEventListener('pointerdown', dismiss, { capture: true });\n window.removeEventListener('click', dismiss);\n };\n }, [menuState.visible, close]);\n\n // Escape dismiss\n useEffect(() => {\n if (!menuState.visible) return;\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') close(); };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [menuState.visible, close]);\n\n // Viewport clamping for main menu\n useLayoutEffect(() => {\n if (!menuState.visible || !menuRef.current) return;\n const el = menuRef.current;\n const r = el.getBoundingClientRect();\n const PAD = 8;\n if (r.right > window.innerWidth - PAD) {\n el.style.left = `${Math.max(PAD, window.innerWidth - r.width - PAD)}px`;\n }\n if (r.bottom > window.innerHeight - PAD) {\n el.style.top = `${Math.max(PAD, window.innerHeight - r.height - PAD)}px`;\n }\n if (r.left < PAD) el.style.left = `${PAD}px`;\n if (r.top < PAD) el.style.top = `${PAD}px`;\n }, [menuState.visible]);\n\n if (!menuState.visible) return null;\n\n const fmt = formatMessageProvider;\n\n // Compute sub-menu anchor position\n let submenuX = 0;\n let submenuY = 0;\n if (submenuIndex !== null) {\n const itemEl = itemRefs.current.get(submenuIndex);\n if (itemEl) {\n const ir = itemEl.getBoundingClientRect();\n const rtl = document.documentElement.dir === 'rtl';\n submenuX = rtl ? window.innerWidth - ir.left + 2 : ir.right + 2;\n submenuY = ir.top;\n }\n }\n\n function cancelOpenTimer() {\n if (timers.current.open) {\n clearTimeout(timers.current.open);\n timers.current.open = null;\n }\n }\n function cancelCloseTimer() {\n if (timers.current.close) {\n clearTimeout(timers.current.close);\n timers.current.close = null;\n }\n }\n\n function handleItemMouseEnter(index: number, item: ContextMenuItem) {\n cancelCloseTimer();\n // Switching away from a different open sub-menu\n if (submenuIndex !== null && submenuIndex !== index) {\n cancelOpenTimer();\n setSubmenuIndex(null);\n }\n if (isSubMenu(item) && item.items?.length) {\n cancelOpenTimer();\n timers.current.open = setTimeout(() => {\n setSubmenuIndex(index);\n }, 150);\n } else if (!isSubMenu(item)) {\n // Non-sub-menu item: close any open sub-menu after grace period\n cancelOpenTimer();\n if (submenuIndex !== null) {\n timers.current.close = setTimeout(() => setSubmenuIndex(null), 200);\n }\n }\n }\n\n function handleItemMouseLeave(item: ContextMenuItem) {\n cancelOpenTimer();\n if (isSubMenu(item) && item.items?.length) {\n timers.current.close = setTimeout(() => setSubmenuIndex(null), 200);\n }\n }\n\n return createPortal(\n <>\n <div\n ref={menuRef}\n className={`rdd-context-menu rdd-context-menu--${theme}${className ? ` ${className}` : ''}`}\n // No inline z-index: .rdd-context-menu's own `calc(var(--rdd-z-base, 1000) + 8500)`\n // owns it, so a WindowManagerProvider's zIndexBase actually shifts this menu (an\n // inline value here silently overrode it). Resolves to the same 9500 by default.\n style={{ position: 'fixed', left: menuState.x, top: menuState.y, ...style }}\n role=\"menu\"\n aria-orientation=\"vertical\"\n >\n {menuState.items.map((item, i) => {\n if (isSeparator(item)) {\n return <hr key={i} className=\"rdd-context-menu__separator\" role=\"separator\" />;\n }\n\n if (isSubMenu(item)) {\n return (\n <button\n key={i}\n ref={el => { itemRefs.current.set(i, el); }}\n type=\"button\"\n className={`rdd-context-menu__item rdd-context-menu__item--has-submenu${submenuIndex === i ? ' rdd-context-menu__item--submenu-open' : ''}`}\n title={item.title ? resolveLabel(item.title, fmt) : undefined}\n onMouseEnter={() => handleItemMouseEnter(i, item)}\n onMouseLeave={() => handleItemMouseLeave(item)}\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={submenuIndex === i}\n >\n <span className=\"rdd-context-menu__icon\" aria-hidden=\"true\" />\n <span className=\"rdd-context-menu__label\">{resolveLabel(item.label, fmt)}</span>\n <span className=\"rdd-context-menu__chevron\" aria-hidden=\"true\">›</span>\n </button>\n );\n }\n\n const simple = item as ContextMenuSimpleItem;\n const showChk = simple.checkbox && simple.checkbox.active !== false;\n const isChecked = showChk && simple.checkbox!.value;\n const isDisabled = simple.disabled === true || (showChk ? simple.checkbox!.enabled === false : false);\n\n return (\n <button\n key={i}\n ref={el => { itemRefs.current.set(i, el); }}\n type=\"button\"\n className={`rdd-context-menu__item${isDisabled ? ' rdd-context-menu__item--disabled' : ''}`}\n title={simple.title ? resolveLabel(simple.title, fmt) : undefined}\n disabled={isDisabled}\n data-cy-action={simple.cyAction}\n onClick={() => { if (!isDisabled) { simple.action?.(); close(); } }}\n onMouseEnter={() => handleItemMouseEnter(i, item)}\n onMouseLeave={() => handleItemMouseLeave(item)}\n role=\"menuitem\"\n aria-checked={showChk ? isChecked : undefined}\n >\n {simple.icon\n ? <span className=\"rdd-context-menu__icon\">{simple.icon}</span>\n : <span className=\"rdd-context-menu__icon\" aria-hidden=\"true\" />}\n <span className=\"rdd-context-menu__label\">{resolveLabel(simple.label, fmt)}</span>\n {showChk && (\n <span className={`rdd-context-menu__checkbox${isChecked ? ' rdd-context-menu__checkbox--checked' : ''}`} aria-hidden=\"true\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"0.75\" y=\"0.75\" width=\"10.5\" height=\"10.5\" rx=\"2\"\n fill={isChecked ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n {isChecked && (\n <path d=\"M2.5 6 L4.5 8.5 L9.5 3.5\" stroke=\"white\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n )}\n </svg>\n </span>\n )}\n </button>\n );\n })}\n </div>\n\n {submenuIndex !== null && (() => {\n const sub = menuState.items[submenuIndex] as ContextMenuSubMenu;\n return (\n <SubMenuPanel\n ref={submenuPanelRef}\n items={sub.items ?? []}\n x={submenuX}\n y={submenuY}\n theme={theme}\n fmt={fmt}\n onClose={close}\n onMouseEnter={() => cancelCloseTimer()}\n onMouseLeave={() => {\n timers.current.close = setTimeout(() => setSubmenuIndex(null), 200);\n }}\n />\n );\n })()}\n </>,\n document.body,\n );\n },\n);\n\nContextMenu.displayName = 'ContextMenu';\n\n// ─── Default adapter ──────────────────────────────────────────────────────────\n\nexport const DefaultContextMenuAdapter: ContextMenuAdapter = {\n Component: ContextMenu,\n};\n\n// ─── ContextMenuContext ────────────────────────────────────────────────────────\n// Decouples menu placement from WindowManager. Any component that renders\n// <ContextMenuProvider> makes showContextMenu available to all descendants,\n// regardless of where it sits relative to WindowManager in the tree.\n\ninterface ContextMenuContextValue {\n show: (options: ShowContextMenuOptions) => void;\n isOpen: boolean;\n}\n\nconst ContextMenuContext: React.Context<ContextMenuContextValue | null> = React.createContext<ContextMenuContextValue | null>(null);\n\nexport const ContextMenuProvider: React.FC<{\n adapter?: ContextMenuAdapter;\n children: React.ReactNode;\n} & ContextMenuProps> = ({ adapter = DefaultContextMenuAdapter, children, ...componentProps }) => {\n const menuRef = useRef<ContextMenuHandle>(null);\n const [isOpen, setIsOpen] = React.useState(false);\n const show = React.useCallback((opts: ShowContextMenuOptions) => {\n menuRef.current?.show(opts);\n }, []);\n return (\n <ContextMenuContext.Provider value={{ show, isOpen }}>\n {children}\n <adapter.Component\n ref={menuRef}\n {...componentProps}\n onShow={() => { setIsOpen(true); componentProps.onShow?.(); }}\n onHide={() => { setIsOpen(false); componentProps.onHide?.(); }}\n />\n </ContextMenuContext.Provider>\n );\n};\n\nexport function useShowContextMenu(): (options: ShowContextMenuOptions) => void {\n const ctx = React.useContext(ContextMenuContext);\n if (!ctx) throw new Error('useShowContextMenu must be used within a ContextMenuProvider');\n return ctx.show;\n}\n\n// Exported for the WindowManager.tsx bridge only — not re-exported from src/index.ts\nexport { ContextMenuContext };\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 * CSS padding for the panel body content — a number (px) or any CSS value/shorthand\n * (e.g. `'10px 16px'`). Default: `0` (edge-to-edge) — pass `10` to restore the pre-v6.0.0\n * default, or any value your content needs.\n */\n bodyPadding?: 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 * CSS padding for the modal body content — a number (px) or any CSS value/shorthand\n * (e.g. `'10px 16px'`). Default: `0` (edge-to-edge) — pass `10` to restore the pre-v6.0.0\n * default, or any value your content needs.\n */\n bodyPadding?: number | string;\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({ preventScroll: true });\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=\"rdd-confirmation-form-body\">\n {alert && (\n <div className={`rdd-confirmation-alert rdd-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=\"rdd-confirmation-actions\">\n <button\n type=\"button\"\n className=\"rdd-btn rdd-btn-sm rdd-btn-outline\"\n onClick={handleCancel}\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n className=\"rdd-btn rdd-btn-sm rdd-btn-primary\"\n ref={confirmButtonRef}\n >\n {confirmLabel}\n </button>\n </div>\n </form>\n );\n};\n\nexport default ConfirmationForm;\n","import type { FloatAnchor } from './WindowManagerContext';\n\n/**\n * Mirrors a physical workspace corner to its horizontal opposite.\n *\n * Used only to translate a physically-hovered corner (raw pointer/screen\n * position, which CSS cannot reason about) into the logical `FloatAnchor`\n * value stored on a `FloatingWindow` under RTL. Render-time positioning\n * should use CSS logical properties (`insetInlineStart`/`insetInlineEnd`)\n * driven by the element's `dir` attribute instead of calling this.\n */\nexport function flipZoneHorizontal(zone: FloatAnchor): FloatAnchor {\n if (zone === 'top-left') return 'top-right';\n if (zone === 'top-right') return 'top-left';\n if (zone === 'bottom-left') return 'bottom-right';\n return 'bottom-left';\n}\n","/**\n * Shared pointer-drag-resize primitives.\n *\n * Extracted from four previously-independent implementations (the workspace grid\n * split resizer, the sidebar drawer resizer, and two floating-window resize-handle\n * implementations) that had quietly drifted apart in exactly the kind of detail\n * (an inline-style property present in one and missing in the other) that once\n * caused a real, user-visible bug. This file is the single place that mechanic now\n * lives, so it can't drift again.\n */\n\n// ── Pointer-capture drag mechanics ──────────────────────────────────────────\n\nexport interface PointerDragConfig<TStart> {\n /** The element to capture the pointer on — normally the handle the user grabbed. */\n element: HTMLElement;\n pointerId: number;\n /** The pointerdown event's clientX/clientY, used as the delta origin. */\n startClientX: number;\n startClientY: number;\n /** Snapshot whatever state the caller needs at drag start (sizes, positions, ...). */\n captureStart: () => TStart;\n /** Called on every pointermove with the delta from the drag's start position. */\n onMove: (dx: number, dy: number, start: TStart) => void;\n /** Called once when the drag ends (pointerup or pointercancel). */\n onEnd?: (start: TStart) => void;\n /** Classes toggled on the given elements for the duration of the drag. */\n activeClasses?: Array<{ el: HTMLElement; classes: string[] }>;\n}\n\n/**\n * Starts a pointer-capture-based drag: captures the pointer on `element`, tracks\n * movement via listeners scoped to that element's own lifetime (not `window`), and\n * cleans up automatically on release or cancel.\n */\nexport function startPointerDrag<TStart>(config: PointerDragConfig<TStart>): void {\n const { element, pointerId, startClientX, startClientY, captureStart, onMove, onEnd, activeClasses } = config;\n\n element.setPointerCapture(pointerId);\n activeClasses?.forEach(({ el, classes }) => el.classList.add(...classes));\n const start = captureStart();\n\n const handleMove = (e: PointerEvent) => {\n onMove(e.clientX - startClientX, e.clientY - startClientY, start);\n };\n\n const handleEnd = () => {\n activeClasses?.forEach(({ el, classes }) => el.classList.remove(...classes));\n element.removeEventListener('pointermove', handleMove);\n element.removeEventListener('pointerup', handleEnd);\n element.removeEventListener('pointercancel', handleEnd);\n onEnd?.(start);\n };\n\n element.addEventListener('pointermove', handleMove);\n element.addEventListener('pointerup', handleEnd);\n element.addEventListener('pointercancel', handleEnd);\n}\n\n// ── 8-directional resize math ────────────────────────────────────────────────\n\nexport type ResizeDir = 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw';\n\nexport interface ResizeRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface ResizeConstraints {\n minW: number;\n minH: number;\n /** Upper bound on width — only applies to eastward growth (dir includes 'e'). */\n maxW?: number;\n /** Upper bound on height — only applies to southward growth (dir includes 's'). */\n maxH?: number;\n /** Lower bound on the resulting x — only applies to westward growth (dir includes 'w'). */\n minX?: number;\n /** Lower bound on the resulting y — only applies to northward growth (dir includes 'n'). */\n minY?: number;\n}\n\n/**\n * Pure function computing the new rect for an 8-directional resize handle drag.\n *\n * `maxW`/`maxH` and `minX`/`minY` are independent, direction-scoped constraints\n * rather than one \"container bound\" — a resize toward the fixed edge (e/s) is\n * naturally bounded by a maximum dimension, while a resize toward the moving edge\n * (w/n) is naturally bounded by a minimum position, and the two calling sites this\n * was extracted from need different subsets of these (see WindowManager.tsx's\n * `startResize`, which omits all four and lets a window grow unbounded and be\n * dragged fully off-screen, vs. PanelOverlay.tsx's `handleResizePointerDown`, which\n * supplies all four to keep windows within their container).\n */\nexport function computeResizedRect(dir: ResizeDir, dx: number, dy: number, start: ResizeRect, constraints: ResizeConstraints): ResizeRect {\n const { minW, minH, maxW, maxH, minX, minY } = constraints;\n let { x, y, w, h } = start;\n\n if (dir.includes('e')) {\n w = Math.max(minW, Math.min(start.w + dx, maxW ?? Infinity));\n }\n if (dir.includes('w')) {\n const maxDx = start.w - minW; // largest rightward (shrinking) delta before hitting minW\n const minDx = minX != null ? -(start.x - minX) : -Infinity; // most negative (growing) delta before x hits minX\n const clampedDx = Math.max(minDx, Math.min(dx, maxDx));\n w = start.w - clampedDx;\n x = start.x + clampedDx;\n }\n if (dir.includes('s')) {\n h = Math.max(minH, Math.min(start.h + dy, maxH ?? Infinity));\n }\n if (dir.includes('n')) {\n const maxDy = start.h - minH;\n const minDy = minY != null ? -(start.y - minY) : -Infinity;\n const clampedDy = Math.max(minDy, Math.min(dy, maxDy));\n h = start.h - clampedDy;\n y = start.y + clampedDy;\n }\n\n return { x, y, w, h };\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * Reactively reads the workspace's current `data-color-scheme` attribute\n * (set on `document.documentElement` by `<WindowManager />`), returning\n * `'dark'` or `'light'` and re-rendering whenever it changes.\n *\n * Useful for panel content that needs to react to the same scheme the\n * workspace itself is using — e.g. swapping a map's tile layer or an\n * embedded editor's theme to match.\n */\nexport function useColorScheme(): 'dark' | 'light' {\n const [scheme, setScheme] = useState<'dark' | 'light'>(() =>\n document.documentElement.getAttribute('data-color-scheme') === 'light' ? 'light' : 'dark'\n );\n\n useEffect(() => {\n const updateScheme = () => {\n setScheme(document.documentElement.getAttribute('data-color-scheme') === 'light' ? 'light' : 'dark');\n };\n updateScheme();\n const observer = new MutationObserver(updateScheme);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-color-scheme'] });\n return () => observer.disconnect();\n }, []);\n\n return scheme;\n}\n","import type { ComponentType } from 'react';\nimport { PanelRegistryClass } from './components/PanelRegistry';\nimport type { PanelRegistryEntry } from './components/PanelRegistry';\nimport type {\n WindowActions,\n MessageFormatter,\n ContextMenuPredefinedMessage,\n DropPosition,\n SplitDirection,\n DirtyStateOptions,\n FloatingWindow,\n} from './components/WindowManagerContext';\nimport type { ShowContextMenuOptions } from './components/ContextMenu';\n\n/** Built-in lifecycle events always available on the WorkspaceClient event bus. */\nexport interface BuiltInPanelEvents {\n 'panel:opened': { id: string; component: string };\n 'panel:closed': { id: string };\n 'panel:minimized': { id: string };\n 'panel:restored': { id: string };\n /**\n * Fires whenever something `saveLayout()` would capture changes — open/close/minimize/restore,\n * and an `openPanel` `dedupeKey` redirect. Coalesces those into one signal for autosave-style\n * consumers, so they don't need to subscribe to four separate events. Does **not** cover a\n * `registerStateProvider` callback's return value changing on its own — that's a pull, there's\n * no way to observe it changing without the panel separately notifying — nor resize/split-ratio\n * drag/dock-rearrange, which have no hooks yet.\n */\n 'layout:changed': Record<string, never>;\n /**\n * Fires from inside `saveLayout()` itself, only when that specific call excluded at least one\n * panel (a panel whose current `props` — static or from a `registerStateProvider` — failed\n * {@link isSerializable}). A passive `PanelInfo.serializable` flag alone isn't enough for this:\n * nobody may be polling it at the exact moment a save happens and something silently drops out\n * (e.g. a floating window rendering data from a live class instance). This is deliberately just\n * a signal, not a UI opinion — decide for yourself whether that becomes a toast, a console\n * warning, or nothing.\n */\n 'layout:panels-excluded': { panels: { id: string; component: string }[] };\n}\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 * Parsed synchronously before the first render. The restored `activePanelId` is the one the\n * snapshot recorded, or — for layouts saved before that was persisted — the selected tab of\n * the first leaf in the grid.\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 * Fraction of the target panel the new panel takes when dropped on a panel's\n * top/bottom/left/right cross target. Range 0.1–0.9. Default: 0.5.\n */\n defaultSplitRatio?: number;\n /**\n * Fraction of the workspace the new panel takes when dropped on the workspace\n * outer edge. Range 0.1–0.9. Default: 0.2.\n */\n defaultEdgeSplitRatio?: number;\n /**\n * Starting z-index for floating windows and the library's own chrome overlays\n * (context menu, toolbar flyout, modal stack, toast, workspace edge zones),\n * all of which shift together via `--rdd-z-base`. Set this above/below a host\n * app's own modal z-index range to control stacking against it. Default: 1000.\n */\n zIndexBase?: number;\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. Duplicate `openPanel` calls for the same\n * ID are deduplicated while queued. Subscriptions made before mount are\n * buffered and re-registered on each connect/reconnect.\n *\n * @example\n * const workspace = new WorkspaceClient<MyEvents>({\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<TUserEvents extends Record<string, unknown> = Record<string, unknown>> {\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' | 'defaultSplitRatio' | 'defaultEdgeSplitRatio' | 'zIndexBase'>;\n\n private _actions: WindowActions | null = null;\n private _initialized = false;\n\n /** Calls queued before _connect() fires — replayed in order on first connect. */\n private _pendingCalls: Array<(actions: WindowActions) => void> = [];\n\n /** Tracks openPanel IDs in the pending queue to prevent duplicates before mount. */\n private _pendingOpenPanelIds = new Set<string>();\n\n /** Subscriptions buffered before connect — re-registered on every connect/reconnect. */\n private _pendingSubscriptions: Array<{\n event: string;\n callback: (data: unknown) => void;\n unsub: (() => void) | null;\n }> = [];\n\n /** Timer that emits an error if _connect() is never called with pending work. */\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 defaultSplitRatio: config.defaultSplitRatio,\n defaultEdgeSplitRatio: config.defaultEdgeSplitRatio,\n zIndexBase: config.zIndexBase,\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 if (!this._initialized) {\n this._initialized = true;\n }\n for (const entry of this._pendingSubscriptions) {\n entry.unsub = actions.subscribe(entry.event, entry.callback);\n }\n const pending = this._pendingCalls.splice(0);\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 for (const entry of this._pendingSubscriptions) {\n entry.unsub?.();\n entry.unsub = null;\n }\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 helpers ──────────────────────────────────────────────────────\n\n private _startWarnTimer(): void {\n if (this._disconnectedWarnTimer === null) {\n this._disconnectedWarnTimer = setTimeout(() => {\n if (!this.isConnected && this._pendingCalls.length > 0) {\n console.error(\n '[react-dockable-desktop] WorkspaceClient has ' + this._pendingCalls.length +\n ' queued call(s) but was never connected to a WindowManagerProvider. ' +\n 'Did you forget client={workspace} on <WindowManagerProvider>?'\n );\n }\n }, process.env.NODE_ENV === 'production' ? 5000 : 1000);\n }\n }\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 this._startWarnTimer();\n }\n }\n\n private _subscribeRaw(event: string, cb: (data: unknown) => void): () => void {\n if (this._actions) return this._actions.subscribe(event, cb);\n const entry = { event, callback: cb, unsub: null as (() => void) | null };\n this._pendingSubscriptions.push(entry);\n return () => {\n entry.unsub?.();\n entry.unsub = null;\n const idx = this._pendingSubscriptions.indexOf(entry);\n if (idx !== -1) this._pendingSubscriptions.splice(idx, 1);\n };\n }\n\n // ── Forwarding methods — mirrors the WindowActions public interface ────────\n\n openPanel(...args: Parameters<WindowActions['openPanel']>): void {\n if (this._actions) {\n this._actions.openPanel(...args);\n return;\n }\n const id = args[0];\n if (!this._pendingOpenPanelIds.has(id)) {\n this._pendingOpenPanelIds.add(id);\n this._pendingCalls.push(a => {\n this._pendingOpenPanelIds.delete(id);\n a.openPanel(...args);\n });\n this._startWarnTimer();\n }\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 /** Finds an already-open panel of the given component with a matching `dedupeKey` (set via\n * `openPanel`'s `dedupeKey` option). Returns `null` if none is open. */\n findPanelId(component: string, dedupeKey: string): string | null {\n return this._actions?.findPanelId(component, dedupeKey) ?? null;\n }\n\n saveLayout(): string { return this._actions?.saveLayout() ?? ''; }\n\n loadLayout(json: string): boolean {\n if (this._actions) return this._actions.loadLayout(json);\n this._pendingCalls.push(a => { a.loadLayout(json); });\n return false;\n }\n\n setDirection(dir: 'ltr' | 'rtl'): void { this._dispatch(a => a.setDirection(dir)); }\n\n /** Updates the split-size fractions at the given grid path. */\n updateSplitSizes(path: number[], sizes: number[]): void {\n this._dispatch(a => a.updateSplitSizes(path, sizes));\n }\n\n /** Updates position/size/anchor of a floating panel. */\n updateFloatingPosition(id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'anchor'>>): void {\n this._dispatch(a => a.updateFloatingPosition(id, updates));\n }\n\n /** @internal Drives the drag-in-progress visual state; normally only the library's own drag UI calls this. */\n setDraggedPanelId(id: string | null): void { this._dispatch(a => a.setDraggedPanelId(id)); }\n\n /** Docks a panel into an existing leaf group at the given drop position. */\n dockPanelToGroup(id: string, targetLeafId: string, position: DropPosition): void {\n this._dispatch(a => a.dockPanelToGroup(id, targetLeafId, position));\n }\n\n /** Reorders a panel's tab within its leaf group. */\n movePanelOrder(panelId: string, targetLeafId: string, targetIndex: number): void {\n this._dispatch(a => a.movePanelOrder(panelId, targetLeafId, targetIndex));\n }\n\n /** Closes an entire leaf group (all of its tabs) at once. */\n closeLeafGroup(leafId: string): void { this._dispatch(a => a.closeLeafGroup(leafId)); }\n\n /** Registers a guard that can veto closing the given panel. */\n registerCloseGuard(id: string, guard: () => boolean | Promise<boolean>): void {\n this._dispatch(a => a.registerCloseGuard(id, guard));\n }\n\n /** Removes a previously registered close guard. */\n unregisterCloseGuard(id: string): void { this._dispatch(a => a.unregisterCloseGuard(id)); }\n\n /** Registers a callback reporting a panel's current restorable state, pulled fresh on every\n * `saveLayout()` call — see {@link BuiltInPanelEvents}'s `'layout:panels-excluded'` doc and\n * `FormContainerContract.registerStateProvider`. */\n registerStateProvider(id: string, provider: () => unknown): void {\n this._dispatch(a => a.registerStateProvider(id, provider));\n }\n\n /** Removes a previously registered state provider. */\n unregisterStateProvider(id: string): void { this._dispatch(a => a.unregisterStateProvider(id)); }\n\n /** Sets/clears a panel's dirty (unsaved changes) flag. */\n setPanelDirty(id: string, dirty: boolean, options?: DirtyStateOptions): void {\n this._dispatch(a => a.setPanelDirty(id, dirty, options));\n }\n\n /** Updates a panel's displayed title. */\n updatePanelTitle(id: string, title: string | ContextMenuPredefinedMessage): void {\n this._dispatch(a => a.updatePanelTitle(id, title));\n }\n\n /**\n * Requests that a panel close, honoring its dirty flag and any registered close guard.\n * Resolves once the close (or user cancellation) has been resolved.\n *\n * @remarks If called before the provider mounts, the request is queued and this\n * returns an already-resolved promise immediately — the caller can't observe the\n * eventual outcome of a queued call, only that the request was accepted.\n */\n requestClosePanel(id: string, options?: { force?: boolean; onConfirm?: (opts?: DirtyStateOptions) => Promise<boolean> }): Promise<void> {\n if (this._actions) return this._actions.requestClosePanel(id, options);\n this._pendingCalls.push(a => { a.requestClosePanel(id, options); });\n return Promise.resolve();\n }\n\n /** Docks a panel to one of the workspace's outer edges. */\n dockPanelToWorkspaceEdge(id: string, position: SplitDirection): void {\n this._dispatch(a => a.dockPanelToWorkspaceEdge(id, position));\n }\n\n /** Shows a context menu using the app's configured ContextMenuAdapter. */\n showContextMenu(options: ShowContextMenuOptions): void { this._dispatch(a => a.showContextMenu(options)); }\n\n // ── Typed event bus ───────────────────────────────────────────────────────\n\n publish<K extends keyof (TUserEvents & BuiltInPanelEvents)>(\n event: K,\n data: (TUserEvents & BuiltInPanelEvents)[K]\n ): void {\n this._dispatch(a => a.publish(event as string, data));\n }\n\n subscribe<K extends keyof (TUserEvents & BuiltInPanelEvents)>(\n event: K,\n callback: (data: (TUserEvents & BuiltInPanelEvents)[K]) => void\n ): () => void {\n return this._subscribeRaw(event as string, callback as (data: unknown) => void);\n }\n\n // ── Lifecycle callbacks ───────────────────────────────────────────────────\n\n /** Subscribe to panel open events. Fires only for newly created panels. */\n onPanelOpen(callback: (id: string, component: string) => void): () => void {\n return this._subscribeRaw('panel:opened', data => {\n const d = data as BuiltInPanelEvents['panel:opened'];\n callback(d.id, d.component);\n });\n }\n\n /** Subscribe to panel close events. */\n onPanelClose(callback: (id: string) => void): () => void {\n return this._subscribeRaw('panel:closed', data => {\n callback((data as BuiltInPanelEvents['panel:closed']).id);\n });\n }\n\n /** Subscribe to panel minimize events. */\n onPanelMinimize(callback: (id: string) => void): () => void {\n return this._subscribeRaw('panel:minimized', data => {\n callback((data as BuiltInPanelEvents['panel:minimized']).id);\n });\n }\n\n /** Subscribe to panel restore events. */\n onPanelRestore(callback: (id: string) => void): () => void {\n return this._subscribeRaw('panel:restored', data => {\n callback((data as BuiltInPanelEvents['panel:restored']).id);\n });\n }\n\n /** Subscribe to the coalesced layout-change signal — see {@link BuiltInPanelEvents}'s\n * `'layout:changed'` doc for exactly what it covers (and doesn't). */\n onLayoutChanged(callback: () => void): () => void {\n return this._subscribeRaw('layout:changed', () => callback());\n }\n\n /** Subscribe to notification that a `saveLayout()` call excluded one or more panels because\n * their current props weren't serializable — see {@link BuiltInPanelEvents}'s\n * `'layout:panels-excluded'` doc. */\n onPanelsExcluded(callback: (panels: { id: string; component: string }[]) => void): () => void {\n return this._subscribeRaw('layout:panels-excluded', data => {\n callback((data as BuiltInPanelEvents['layout:panels-excluded']).panels);\n });\n }\n}\n","import React, { useContext } from 'react';\nimport { WindowManagerProvider } from './WindowManagerContext';\nimport type { WindowManagerProviderProps } from './WindowManagerContext';\nimport { PanelProvider } from './PanelProviderContext';\nimport { ToolbarProvider } from './ToolbarContext';\nimport { PanelContributionProvider } from './PanelContributionContext';\nimport { ContextMenuContext, ContextMenuProvider, DefaultContextMenuAdapter } from './ContextMenu';\nimport type { ContextMenuAdapter } from './ContextMenu';\n\n/**\n * Props for `<DockableDesktopProvider>`.\n * Extends `WindowManagerProviderProps` with workspace-level context menu configuration.\n */\nexport interface DockableDesktopProviderProps extends WindowManagerProviderProps {\n /**\n * Context menu adapter for the workspace-level `ContextMenuProvider`.\n * Defaults to `DefaultContextMenuAdapter`. Ignored if a `<ContextMenuProvider>`\n * already exists above `<DockableDesktopProvider>` in the tree.\n */\n contextMenuAdapter?: ContextMenuAdapter;\n}\n\n/**\n * Composite provider that wraps `WindowManagerProvider`, `PanelProvider`, `ToolbarProvider`,\n * and `PanelContributionProvider` in the correct order, and mounts the workspace-level\n * `ContextMenuProvider` so that\n * `showContextMenu()` and `useShowContextMenu()` work from any component in the tree —\n * including siblings of `<WindowManager>` such as `<Sidebar>`, `<SidePanelRenderer>`,\n * and `<ModalStackRenderer>`.\n *\n * Drop-in replacement for manually nesting both providers.\n *\n * `WindowManagerProvider` and `PanelProvider` remain independently exported\n * for cases that require custom nesting or separate configuration.\n *\n * @example\n * ```tsx\n * <DockableDesktopProvider client={workspace}>\n * <Sidebar>\n * <WindowManager />\n * </Sidebar>\n * <SidePanelRenderer />\n * <ModalStackRenderer />\n * </DockableDesktopProvider>\n * ```\n */\nexport const DockableDesktopProvider: React.FC<DockableDesktopProviderProps> = (\n { contextMenuAdapter = DefaultContextMenuAdapter, ...props }\n): React.ReactElement => {\n const existingCtxMenu = useContext(ContextMenuContext);\n\n const inner = (\n <ToolbarProvider>\n <WindowManagerProvider {...props}>\n <PanelContributionProvider>\n <PanelProvider>\n {props.children}\n </PanelProvider>\n </PanelContributionProvider>\n </WindowManagerProvider>\n </ToolbarProvider>\n );\n\n if (existingCtxMenu !== null) return inner;\n\n return (\n <ContextMenuProvider\n adapter={contextMenuAdapter}\n formatMessageProvider={props.formatMessage}\n >\n {inner}\n </ContextMenuProvider>\n );\n};\n\nexport default DockableDesktopProvider;\n","/**\n * @file ToolbarContext.tsx\n * @description Toolbar state context — radio group selection and toggle modifier state.\n * Provided by DockableDesktopProvider; consumed via useToolbar() from anywhere in the tree.\n */\n\nimport React, { createContext, useContext, useMemo, useState } from 'react';\n\nexport interface ToolbarContextValue {\n /** Returns the active item id in a radio group, or null if none. */\n getActiveInGroup: (group: string) => string | null;\n /** Set the active item in a radio group (pass null to deselect all). */\n setActiveInGroup: (group: string, id: string | null) => void;\n /** Returns whether a toggle modifier is currently active. */\n isModifierActive: (id: string) => boolean;\n /** Explicitly set a toggle modifier's active state. */\n setModifierActive: (id: string, active: boolean) => void;\n /** Flip a toggle modifier between active and inactive. */\n toggleModifier: (id: string) => void;\n}\n\nconst ToolbarContext = createContext<ToolbarContextValue | null>(null);\n\nexport const ToolbarProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const [radioGroups, setRadioGroups] = useState<Record<string, string | null>>({});\n const [modifiers, setModifiers] = useState<Record<string, boolean>>({});\n\n const value = useMemo<ToolbarContextValue>(() => ({\n getActiveInGroup: (group) => radioGroups[group] ?? null,\n setActiveInGroup: (group, id) => setRadioGroups(prev => ({ ...prev, [group]: id })),\n isModifierActive: (id) => modifiers[id] ?? false,\n setModifierActive: (id, active) => setModifiers(prev => ({ ...prev, [id]: active })),\n toggleModifier: (id) => setModifiers(prev => ({ ...prev, [id]: !prev[id] })),\n }), [radioGroups, modifiers]);\n\n return <ToolbarContext.Provider value={value}>{children}</ToolbarContext.Provider>;\n};\n\n/**\n * Returns toolbar state and control functions from anywhere inside\n * a `<DockableDesktopProvider>` tree.\n *\n * @throws Error if used outside of a {@link DockableDesktopProvider}.\n */\nexport function useToolbar(): ToolbarContextValue {\n const ctx = useContext(ToolbarContext);\n if (!ctx) throw new Error('useToolbar must be used within DockableDesktopProvider');\n return ctx;\n}\n","/**\n * @file PanelContributionContext.tsx\n * @description Lets any panel publish toolbar items and/or sidebar sections that\n * should only be surfaced while it is the globally active panel (`state.activePanelId`).\n * Optional, additive module — `DockableDesktopProvider` wires it up automatically.\n * Neither `<Toolbar>` nor `<Sidebar>` reads from this automatically; the app shell\n * merges `useActivePanelContribution()`'s result into its own `items`/`tabs` calls.\n */\n\nimport React, { createContext, useCallback, useContext, useLayoutEffect, useMemo, useRef, useSyncExternalStore } from 'react';\nimport type { ToolbarItem } from './Toolbar';\nimport type { SidebarTab } from './Sidebar';\nimport { usePanelId, useWindowManagerState } from './WindowManagerContext';\n\n/** A single named, labeled slot of content a panel contributes to the app's Sidebar while active. */\nexport interface PanelSidebarSection {\n id: string;\n label: string;\n icon?: React.ReactNode;\n content: React.ReactNode;\n}\n\n/**\n * What a panel publishes via `usePanelContribution()`. Both fields are optional and\n * independent — a panel may contribute only toolbar items, only sidebar sections,\n * both, or neither. The app decides what \"toolbar items\" and \"sidebar sections\" mean\n * for its own domain (map controls, document formatting, anything else).\n */\nexport interface PanelContribution {\n toolbarItems?: ToolbarItem[];\n sidebarSections?: PanelSidebarSection[];\n}\n\ntype Listener = () => void;\n\ninterface PanelContributionStore {\n publish(panelId: string, contribution: PanelContribution): () => void;\n get(panelId: string): PanelContribution | null;\n subscribe(listener: Listener): () => void;\n}\n\nfunction createPanelContributionStore(): PanelContributionStore {\n const contributions = new Map<string, PanelContribution>();\n const listeners = new Set<Listener>();\n const notify = () => listeners.forEach(l => l());\n\n return {\n publish(panelId, contribution) {\n contributions.set(panelId, contribution);\n notify();\n return () => {\n // Only clear if nothing else re-published for this id in the meantime.\n if (contributions.get(panelId) === contribution) {\n contributions.delete(panelId);\n notify();\n }\n };\n },\n get(panelId) {\n return contributions.get(panelId) ?? null;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\nconst PanelContributionContext = createContext<PanelContributionStore | null>(null);\n\n/**\n * Provider enabling `usePanelContribution()` / `useActivePanelContribution()`.\n * Mounted automatically by `DockableDesktopProvider` — only needed manually when\n * composing `WindowManagerProvider` directly without it.\n */\nexport const PanelContributionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const store = useMemo(() => createPanelContributionStore(), []);\n return <PanelContributionContext.Provider value={store}>{children}</PanelContributionContext.Provider>;\n};\n\n/**\n * Publish this panel's toolbar items and/or sidebar sections. Call on every render —\n * republishes automatically whenever `contribution` changes, and is cleared when the\n * panel unmounts. Memoize the object (and its array/callback contents, e.g. with\n * `useMemo`/`useCallback`) to avoid republishing on every unrelated re-render.\n *\n * Contributions are only ever surfaced while this panel is `state.activePanelId` —\n * see `useActivePanelContribution()`.\n *\n * @throws Error if used outside of a {@link PanelContributionProvider}.\n * @example\n * function MapPanel() {\n * const [controller, setController] = useState<'pan' | 'draw' | 'measure'>('pan');\n * usePanelContribution({\n * toolbarItems: (['pan', 'draw', 'measure'] as const).map(id => ({\n * type: 'toggle', id, label: id, icon: icons[id],\n * active: controller === id, onToggle: () => setController(id),\n * })),\n * sidebarSections: [{ id: 'layers', label: 'Layers', content: <LayerList /> }],\n * });\n * // ...\n * }\n */\nexport function usePanelContribution(contribution: PanelContribution): void {\n const panelId = usePanelId();\n const store = useContext(PanelContributionContext);\n const cleanupRef = useRef<(() => void) | null>(null);\n\n if (!store) throw new Error('usePanelContribution must be used within PanelContributionProvider');\n\n useLayoutEffect(() => {\n if (!store) return;\n cleanupRef.current?.();\n cleanupRef.current = store.publish(panelId, contribution);\n return () => {\n cleanupRef.current?.();\n cleanupRef.current = null;\n };\n }, [store, panelId, contribution]);\n}\n\n/**\n * Returns whatever the currently active panel (`state.activePanelId`) has published\n * via `usePanelContribution()`, or `null` if no panel is active or the active panel\n * hasn't contributed anything. Intended for the app shell to merge into its own\n * `<Toolbar items={...}>` / `<Sidebar tabs={...}>` calls.\n *\n * @throws Error if used outside of a {@link PanelContributionProvider}.\n */\nexport function useActivePanelContribution(): PanelContribution | null {\n const activePanelId = useWindowManagerState(s => s.activePanelId);\n const store = useContext(PanelContributionContext);\n\n if (!store) throw new Error('useActivePanelContribution must be used within PanelContributionProvider');\n\n const subscribe = useCallback(\n (onChange: Listener) => (store ? store.subscribe(onChange) : () => {}),\n [store]\n );\n const getSnapshot = () => (store && activePanelId ? store.get(activePanelId) : null);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Converts a contributed sidebar section into a `SidebarTab` for `<Sidebar tabs={...}>`.\n * `SidebarTab.icon` is optional but recommended unless the tab is `hidden`; supply\n * `fallbackIcon` for sections that omit one.\n * `eagerMount`/`preserveState` have no contribution-side equivalent — a contribution\n * only exists while its owning panel is mounted and active, so both are left unset.\n */\nexport function sidebarSectionToTab(section: PanelSidebarSection, fallbackIcon: React.ReactNode = null): SidebarTab {\n return {\n id: section.id,\n label: section.label,\n icon: section.icon ?? fallbackIcon,\n renderContent: () => section.content,\n };\n}\n\n/**\n * Convenience wrapper around `useActivePanelContribution()` for the common case:\n * append the active panel's contributed toolbar items (behind a separator) to a\n * static list. Returns `staticItems` unchanged when there's nothing to add.\n * For manual control (a different merge position, no separator, etc.), call\n * `useActivePanelContribution()` directly instead.\n */\nexport function useMergedToolbarItems(staticItems: ToolbarItem[]): ToolbarItem[] {\n const active = useActivePanelContribution();\n return active?.toolbarItems?.length\n ? [...staticItems, { type: 'separator' }, ...active.toolbarItems]\n : staticItems;\n}\n\n/**\n * Convenience wrapper around `useActivePanelContribution()` for the common case:\n * append the active panel's contributed sidebar sections (via `sidebarSectionToTab`)\n * to a static tab list, as dynamic tabs that appear only while their panel is active.\n * Returns `staticTabs` unchanged when there's nothing to add.\n */\nexport function useMergedSidebarTabs(staticTabs: SidebarTab[], fallbackIcon: React.ReactNode = null): SidebarTab[] {\n const active = useActivePanelContribution();\n return active?.sidebarSections?.length\n ? [...staticTabs, ...active.sidebarSections.map(section => sidebarSectionToTab(section, fallbackIcon))]\n : staticTabs;\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 type { DirtyStateOptions } from './dirtyOptions';\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?: DirtyStateOptions) => 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 ? `rdd-modal-size-${modalOptions.size}` : 'rdd-modal-size-auto';\n const showCloseButton = modalOptions.closable !== false;\n\n const bodyPadding = modalOptions.bodyPadding;\n const bodyPaddingStyle = bodyPadding != null\n ? (typeof bodyPadding === 'number' ? `${bodyPadding}px` : bodyPadding)\n : undefined;\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 // Reads the same --rdd-z-base a WindowManagerProvider's zIndexBase config mirrors\n // onto documentElement (falls back to 1000 so this also works standalone, with\n // no WindowManager mounted, matching the :root default in index.css).\n const modalZIndex = `calc(var(--rdd-z-base, 1000) + 9000 + ${index * 10})`;\n\n return (\n <div className=\"rdd-modal-overlay\" style={{ zIndex: modalZIndex }} dir={dir}>\n <div className=\"rdd-modal-curtain\" onClick={showCloseButton ? () => handleClose() : undefined} />\n <div className={`rdd-modal-window ${sizeClass} ${modalClass ?? ''}`}>\n <div className=\"rdd-modal-header\">\n {icon && <div className=\"rdd-modal-icon\">{icon}</div>}\n <h4 className=\"rdd-modal-title\">{displayTitle}</h4>\n {showCloseButton && (\n <button\n className=\"rdd-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\n className={`rdd-modal-body ${modalBodyClass ?? ''}`}\n style={bodyPaddingStyle != null ? { padding: bodyPaddingStyle } : undefined}\n >\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 type { DirtyStateOptions } from './dirtyOptions';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\nimport { useContainerRect, type ContainerRect } from '../hooks/useContainerRect';\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 /** On-screen rect of the app's own container, or null to default to the full viewport. */\n containerRect: ContainerRect | null;\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, containerRect }) => {\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?: DirtyStateOptions) => 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 const bodyPadding = panelOptions.bodyPadding;\n const bodyPaddingStyle = bodyPadding != null\n ? (typeof bodyPadding === 'number' ? `${bodyPadding}px` : bodyPadding)\n : undefined;\n\n return (\n <div\n className={`rdd-side-panel rdd-side-panel-${position} rdd-side-panel-visible ${sidePanelClass ?? ''}`}\n style={{\n width: widthStyle,\n ...(containerRect ? {\n top: containerRect.top,\n height: containerRect.height,\n bottom: 'auto',\n ...(position === 'right' ? { right: containerRect.right } : { left: containerRect.left }),\n } : {}),\n }}\n dir={dir}\n >\n <div className=\"rdd-side-panel-window\">\n <div className=\"rdd-side-panel-header\">\n {icon && <div className=\"rdd-side-panel-icon\">{icon}</div>}\n <h4 className=\"rdd-side-panel-title\">{displayTitle}</h4>\n <button\n className=\"rdd-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\n className={`rdd-side-panel-body ${sidePanelBodyClass ?? ''}`}\n style={bodyPaddingStyle != null ? { padding: bodyPaddingStyle } : undefined}\n >\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 * Renders an always-present, zero-footprint anchor (`display: contents` — no box\n * of its own, no layout/visual effect) so its parent element — the container the\n * consuming app actually placed the workspace into — can be measured via\n * {@link useContainerRect}, independent of whether any panel is currently open.\n */\nconst SidePanelAnchor: React.FC<{ children: (containerRect: ContainerRect | null) => React.ReactNode }> = ({ children }) => {\n const anchorRef = useRef<HTMLDivElement>(null);\n const containerRect = useContainerRect(anchorRef);\n return <div ref={anchorRef} style={{ display: 'contents' }}>{children(containerRect)}</div>;\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 <SidePanelAnchor>\n {(containerRect) => (\n <>\n {leftPanel && <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} containerRect={containerRect} />}\n {rightPanel && <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} containerRect={containerRect} />}\n </>\n )}\n </SidePanelAnchor>\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 return (\n <SidePanelAnchor>\n {(containerRect) => leftPanel ? <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} containerRect={containerRect} /> : null}\n </SidePanelAnchor>\n );\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 return (\n <SidePanelAnchor>\n {(containerRect) => rightPanel ? <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} containerRect={containerRect} /> : null}\n </SidePanelAnchor>\n );\n};\n\nexport default SidePanelRenderer;\n","import { useLayoutEffect, useState, type RefObject } from 'react';\n\n/** On-screen rect of a container, in the coordinate system `position: fixed` uses. */\nexport interface ContainerRect {\n top: number;\n left: number;\n /** Distance from the viewport's right edge — what CSS `right` expects for `position: fixed`. */\n right: number;\n height: number;\n}\n\n/**\n * Tracks the live on-screen rect of `anchorRef.current`'s parent element.\n *\n * Used to keep a `position: fixed` overlay (side panel) visually confined to\n * whatever container the consuming app actually placed the workspace into,\n * instead of defaulting to the full browser viewport. `position: fixed` is\n * required so the overlay never contributes scrollable overflow to any\n * ancestor (see the side-panel autofocus scroll-jump fix), but that means it\n * no longer inherits containment from a `position: relative` ancestor the way\n * `position: absolute` did — this hook restores that containment by measuring\n * it directly. For a full-viewport app the measured rect equals the viewport,\n * so this is a no-op change from the app's perspective.\n */\nexport function useContainerRect(anchorRef: RefObject<HTMLElement | null>): ContainerRect | null {\n const [rect, setRect] = useState<ContainerRect | null>(null);\n\n useLayoutEffect(() => {\n const container = anchorRef.current?.parentElement;\n if (!container) return;\n\n const measure = () => {\n const r = container.getBoundingClientRect();\n setRect({ top: r.top, left: r.left, right: window.innerWidth - r.right, height: r.height });\n };\n measure();\n\n const resizeObserver = new ResizeObserver(measure);\n resizeObserver.observe(container);\n window.addEventListener('resize', measure);\n\n return () => {\n resizeObserver.disconnect();\n window.removeEventListener('resize', measure);\n };\n }, [anchorRef]);\n\n return rect;\n}\n","/**\n * @file Sidebar.tsx\n * @description Sidebar activity bar (strip) and resizable content drawer.\n * The strip and drawer are independently controllable via `visible` and\n * `stripVisible`. Drawer width is pixel-based and user-draggable using the\n * same pointer-capture interaction as the panel grid resizer.\n */\n\nimport React, {\n useState,\n useEffect,\n useRef,\n useCallback,\n useImperativeHandle,\n useContext,\n useMemo,\n createContext,\n forwardRef,\n memo,\n} from 'react';\nimport { startPointerDrag } from './dragResize';\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 /** Required unless `hidden` is true — a hidden tab never renders a rail button, so it has no icon to show. */\n icon?: React.ReactNode;\n /**\n * Omit this tab's rail button entirely — no icon, no click target — while it\n * remains fully openable via `openTab()` / `useSidebar().openTab()` / a controlled\n * `activeTabId`. Use for menu-driven panels with no persistent icon (e.g. a\n * Google-Maps-style hamburger that opens content not otherwise pinned to the rail).\n * Default: false\n */\n hidden?: boolean;\n /**\n * Mount immediately when the Sidebar first renders, not on first user click.\n * Implies `preserveState: true`.\n * Default: false\n */\n eagerMount?: boolean;\n /**\n * Keep the component alive behind `display: none` when closed instead of\n * unmounting it. Use for panels with expensive local state.\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\n */\n renderContent: (tabId: string, onClose: () => void, onOpen: () => void) => React.ReactNode;\n}\n\n/**\n * Simple case for `SidebarProps.headerAction`/`footerAction`: the library renders a\n * default-styled icon button (visually consistent with the regular tab buttons) and forwards\n * the click.\n */\nexport interface SidebarHeaderActionButton {\n /** Only needed when used inside a `SidebarRailEntry[]` array, for the React key. */\n id?: string;\n icon: React.ReactNode;\n /** Tooltip and aria-label — same convention as `SidebarTab.label`. */\n label: string;\n onClick: () => void;\n disabled?: boolean;\n}\n\n/**\n * Full-control case for `SidebarProps.headerAction`/`footerAction`: the consumer supplies their\n * own markup (a Material UI `IconButton`, a Bootstrap `Button`, a Tailwind-styled `<button>`, or\n * anything else) wholesale. The library renders exactly what this returns, unwrapped, so the\n * consumer's own hover/active/focus/ripple behavior and click handling are untouched.\n */\nexport interface SidebarHeaderActionCustom {\n /** Only needed when used inside a `SidebarRailEntry[]` array, for the React key. */\n id?: string;\n render: () => React.ReactNode;\n}\n\n/**\n * A single, non-toggling action button shown above the tab strip (e.g. a hamburger menu).\n * Unlike `SidebarTab`, it never affects `activeTabId` or the drawer — the library only renders\n * it and forwards the click; what happens next (opening a side panel, a modal, anything else)\n * is entirely up to the consumer.\n */\nexport type SidebarHeaderAction = SidebarHeaderActionButton | SidebarHeaderActionCustom;\n\n/**\n * A single entry inside `SidebarProps.headerAction`/`footerAction` when used as an array: either\n * a non-toggling action button/custom render (see `SidebarHeaderAction`), or a real `SidebarTab`\n * that behaves exactly like a main-list tab — it mounts, activates, and closes through the same\n * lifecycle, so e.g. a \"Settings\" entry pinned to the footer can expand like any other tab.\n */\nexport type SidebarRailEntry = SidebarTab | SidebarHeaderActionButton | SidebarHeaderActionCustom;\n\nfunction isRailTab(entry: SidebarRailEntry): entry is SidebarTab {\n return 'renderContent' in entry;\n}\n\nfunction isRailCustom(entry: SidebarRailEntry): entry is SidebarHeaderActionCustom {\n return 'render' in entry;\n}\n\nfunction toRailArray(value: SidebarRailEntry | SidebarRailEntry[] | undefined): SidebarRailEntry[] {\n if (value == null) return [];\n return Array.isArray(value) ? value : [value];\n}\n\nexport interface SidebarProps {\n /** Which side the activity bar and drawer appear on. Default: 'right' */\n position?: 'left' | 'right';\n tabs: SidebarTab[];\n /**\n * One or more non-toggling action buttons and/or real tabs shown above the tabs, in their\n * own `.rdd-sidebar-header-area` — independent of the tabs' own inter-item gap. Pass a single\n * `{ icon, label, onClick }`/`{ render }` object (the common case), or an array mixing action\n * buttons, custom renders, and `SidebarTab` entries — a tab entry here behaves exactly like a\n * main-list tab (mounts, activates, closes through the same lifecycle). Override\n * `--rdd-sidebar-header-area-padding-top`/`--rdd-sidebar-header-area-padding-bottom`\n * (both default `8px`) to control its spacing/effective height.\n */\n headerAction?: SidebarRailEntry | SidebarRailEntry[];\n /**\n * Mirror of `headerAction`, pinned to the bottom of the tab strip via its own\n * `.rdd-sidebar-footer-area` — e.g. a \"Settings\" tab that should always sit at the bottom\n * regardless of tab count. Override `--rdd-sidebar-footer-area-padding-top`/\n * `--rdd-sidebar-footer-area-padding-bottom` (both default `8px`) to control its spacing.\n */\n footerAction?: SidebarRailEntry | SidebarRailEntry[];\n /** Initial drawer width in pixels. Default: 280 */\n defaultWidth?: number;\n /** Minimum drawer width in pixels during drag-resize. Default: 150 */\n minWidth?: number;\n /** Maximum drawer width in pixels during drag-resize. Default: 600 */\n maxWidth?: number;\n /** Called during drag resize and on setWidth() with the new pixel width. */\n onWidthChange?: (px: number) => void;\n /** Controlled active tab id. Omit to use internal state. */\n activeTabId?: string | null;\n /** Called when the active tab changes. */\n onActiveTabChange?: (tabId: string | null) => void;\n /** Collapse the entire sidebar (strip + drawer). Default: true */\n visible?: boolean;\n /** Called when show/hide/toggle is invoked on the imperative handle. */\n onVisibilityChange?: (visible: boolean) => void;\n /** Collapse only the activity bar strip, leaving the drawer unaffected. Default: true */\n stripVisible?: boolean;\n /** Called when showStrip/hideStrip is invoked on the imperative handle. */\n onStripVisibilityChange?: (visible: boolean) => void;\n /**\n * Show an \"X\" close button in the expanded drawer's header, as an additional way to collapse\n * the sidebar (equivalent to clicking the active tab's own icon again). Opt-in. Default: false.\n * Has no effect once the default header is suppressed — via `hideDefaultHeader`, or simply by\n * passing `renderHeader` (either one is sufficient) — since the entire default header, this\n * button included, is skipped for every tab in that case.\n */\n showCloseButton?: boolean;\n /**\n * Suppress the library's own drawer header (title + `showCloseButton`'s close\n * button) for every tab, so `renderHeader` (or each tab's own `renderContent`)\n * can supply a header, border, and styling instead. Applies uniformly across\n * all tabs — there's no per-tab override. Passing `renderHeader` by itself has\n * the same suppressing effect even if this is left unset — the two conditions\n * are combined with OR, precisely so that supplying `renderHeader` alone is\n * never a silent no-op. The close mechanism is unaffected either way: the\n * `onClose` parameter passed to `renderContent`/`renderHeader`, or\n * `useSidebarTab().onClose` from anywhere in a tab's content tree.\n * Default: false\n */\n hideDefaultHeader?: boolean;\n /**\n * Custom header renderer used in place of the library's own drawer header.\n * Passing `renderHeader` is by itself sufficient to suppress the default\n * header, whether or not `hideDefaultHeader` is also set — the two props are\n * combined with OR. Called once for whichever tab is currently active, so\n * the same header markup (e.g. a hamburger icon, a search field, a close\n * button) is shared uniformly across every tab instead of being repeated\n * inside each tab's own `renderContent`. Omit `renderHeader` and set\n * `hideDefaultHeader: true` to render no header at all and let each tab's\n * `renderContent` supply its own instead.\n * @param tab - the currently active tab\n * @param onClose - call to collapse the sidebar drawer\n * @param onOpen - call to (re-)select this tab\n */\n renderHeader?: (tab: SidebarTab, onClose: () => void, onOpen: () => void) => React.ReactNode;\n /**\n * @internal Marks this instance as a secondary sidebar for context-broadcasting\n * purposes. Set automatically by `<SecondarySidebar>` — do not pass this directly.\n * Default: false\n */\n isSecondary?: boolean;\n /** Main workspace content rendered alongside the sidebar. */\n children?: React.ReactNode;\n}\n\n/**\n * Imperative handle exposed by `<Sidebar ref={...}>`.\n */\nexport interface SidebarHandle {\n openTab: (tabId: string) => void;\n closeDrawer: () => void;\n getActiveTab: () => string | null;\n show: () => void;\n hide: () => void;\n toggle: () => void;\n showStrip: () => void;\n hideStrip: () => void;\n setWidth: (px: number) => void;\n getWidth: () => number;\n}\n\n/**\n * Value provided by `useSidebar()`. Available to any component inside the\n * `<Sidebar>` React tree, including panels rendered via `{children}`.\n */\nexport interface SidebarContextValue {\n openTab: (tabId: string) => void;\n closeDrawer: () => void;\n getActiveTab: () => string | null;\n /** Which side this Sidebar instance is rendering on. */\n position: 'left' | 'right';\n /** True if this instance is a `<SecondarySidebar>`, false for a primary `<Sidebar>`. */\n isSecondary: boolean;\n}\n\n/**\n * Value provided by `useSidebarTab()`. Available only to components rendered\n * inside a sidebar tab's `renderContent` tree.\n */\nexport interface SidebarTabContextValue {\n tabId: string;\n onOpen: () => void;\n onClose: () => void;\n openTab: (tabId: string) => void;\n}\n\n// ==========================================\n// Contexts\n// ==========================================\n\nconst SidebarContext = createContext<SidebarContextValue | null>(null);\nconst SidebarTabContext = createContext<SidebarTabContextValue | null>(null);\n\n// ==========================================\n// SidebarTabProvider (internal)\n// ==========================================\n\ninterface SidebarTabProviderProps {\n tabId: string;\n onClose: () => void;\n onOpen: () => void;\n setActiveTabId: (id: string | null) => void;\n children: React.ReactNode;\n}\n\nfunction SidebarTabProvider({ tabId, onClose, onOpen, setActiveTabId, children }: SidebarTabProviderProps) {\n const value = useMemo<SidebarTabContextValue>(() => ({\n tabId,\n onClose,\n onOpen,\n openTab: (otherId: string) => setActiveTabId(otherId),\n }), [tabId, onClose, onOpen, setActiveTabId]);\n\n return <SidebarTabContext.Provider value={value}>{children}</SidebarTabContext.Provider>;\n}\n\n// ==========================================\n// renderRailEntry (internal helper)\n// Shared by the header/footer areas only — dispatches a SidebarRailEntry to a tab button,\n// a default-styled action button, or a fully custom render. The main tabs-list keeps its own\n// inline JSX below since it only ever renders SidebarTab entries.\n// ==========================================\n\nfunction renderRailEntry(\n entry: SidebarRailEntry,\n index: number,\n activeTabId: string | null | undefined,\n onTabClick: (tabId: string) => void\n): React.ReactNode {\n if (isRailCustom(entry)) {\n return <React.Fragment key={entry.id ?? index}>{entry.render()}</React.Fragment>;\n }\n if (isRailTab(entry)) {\n if (entry.hidden) return null;\n const isActive = activeTabId === entry.id;\n return (\n <button\n key={entry.id}\n type=\"button\"\n onClick={() => onTabClick(entry.id)}\n className={`rdd-sidebar-tab-btn${isActive ? ' rdd-active' : ''}`}\n title={entry.label}\n aria-pressed={isActive}\n >\n {entry.icon}\n </button>\n );\n }\n return (\n <button\n key={entry.id ?? index}\n type=\"button\"\n onClick={entry.onClick}\n disabled={entry.disabled}\n className=\"rdd-sidebar-tab-btn rdd-sidebar-header-action-btn\"\n title={entry.label}\n aria-label={entry.label}\n >\n {entry.icon}\n </button>\n );\n}\n\n// ==========================================\n// SidebarTabStrip (internal sub-component)\n// Re-renders only when tabs, selection, or strip visibility changes —\n// not on drawer width changes during drag.\n// ==========================================\n\ninterface SidebarTabStripProps {\n tabs: SidebarTab[];\n headerEntries: SidebarRailEntry[];\n footerEntries: SidebarRailEntry[];\n activeTabId: string | null | undefined;\n isVisible: boolean;\n position: 'left' | 'right';\n onTabClick: (tabId: string) => void;\n}\n\nconst SidebarTabStrip = memo(function SidebarTabStrip({\n tabs,\n headerEntries,\n footerEntries,\n activeTabId,\n isVisible,\n position,\n onTabClick,\n}: SidebarTabStripProps) {\n return (\n // Outer div drives the collapse transition via overflow:hidden.\n // The inner rdd-sidebar-tabs-strip must NOT have overflow:hidden so the active\n // tab's negative margin can extend into the drawer border without clipping.\n <div\n style={{\n width: isVisible ? '56px' : '0px',\n height: '100%',\n overflow: 'hidden',\n transition: 'width 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n flexShrink: 0,\n }}\n >\n <div\n className={`rdd-sidebar-tabs-strip rdd-${position}${headerEntries.length ? ' rdd-sidebar-tabs-strip--has-header-action' : ''}${footerEntries.length ? ' rdd-sidebar-tabs-strip--has-footer-action' : ''}`}\n style={{ width: '56px', height: '100%' }}\n >\n {headerEntries.length > 0 && (\n <div className=\"rdd-sidebar-header-area\">\n {headerEntries.map((entry, i) => renderRailEntry(entry, i, activeTabId, onTabClick))}\n </div>\n )}\n <div className=\"rdd-sidebar-tabs-list\">\n {tabs.map(tab => {\n if (tab.hidden) return null;\n const isActive = activeTabId === tab.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => onTabClick(tab.id)}\n className={`rdd-sidebar-tab-btn${isActive ? ' rdd-active' : ''}`}\n title={tab.label}\n aria-pressed={isActive}\n >\n {tab.icon}\n </button>\n );\n })}\n </div>\n {footerEntries.length > 0 && (\n <div className=\"rdd-sidebar-footer-area\">\n {footerEntries.map((entry, i) => renderRailEntry(entry, i, activeTabId, onTabClick))}\n </div>\n )}\n </div>\n </div>\n );\n});\n\n// ==========================================\n// SidebarResizeHandle (internal sub-component)\n// Encapsulates all pointer-capture drag logic.\n// Identical interaction pattern to the panel grid resizer in WindowManager.tsx.\n// ==========================================\n\ninterface SidebarResizeHandleProps {\n position: 'left' | 'right';\n currentWidth: number;\n minWidth: number;\n maxWidth: number;\n onWidthChange: (newWidth: number) => void;\n onResizeStart: () => void;\n onResizeEnd: () => void;\n}\n\nfunction SidebarResizeHandle({\n position,\n currentWidth,\n minWidth,\n maxWidth,\n onWidthChange,\n onResizeStart,\n onResizeEnd,\n}: SidebarResizeHandleProps) {\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault();\n const el = e.currentTarget;\n const activeClasses: Array<{ el: HTMLElement; classes: string[] }> = [\n { el, classes: ['rdd-active'] },\n { el: document.body, classes: ['rdd-resizing-active', 'rdd-resizing-col-active'] },\n ];\n // Suppress the drawer's CSS transition so drag feels instant — driven by this\n // instance's own isResizing state (see the drawer's style below), not a DOM\n // class + descendant selector, which would leak across a nested secondary\n // Sidebar's subtree since it's a literal DOM descendant of this one.\n onResizeStart();\n\n startPointerDrag({\n element: el,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => currentWidth,\n activeClasses,\n onMove: (dx, _dy, startWidth) => {\n // Right sidebar: dragging left (negative dx) widens the drawer\n const newW = position === 'right' ? startWidth - dx : startWidth + dx;\n onWidthChange(Math.max(minWidth, Math.min(maxWidth, newW)));\n },\n onEnd: () => onResizeEnd(),\n });\n };\n\n return (\n <div\n className=\"rdd-resizer-bar\"\n style={{\n cursor: 'col-resize',\n width: '1px',\n height: '100%',\n flexShrink: 0,\n zIndex: 20,\n }}\n onPointerDown={handlePointerDown}\n />\n );\n}\n\n// ==========================================\n// Sidebar (main component)\n// ==========================================\n\nexport const Sidebar: React.ForwardRefExoticComponent<SidebarProps & React.RefAttributes<SidebarHandle>> =\n forwardRef<SidebarHandle, SidebarProps>(function Sidebar(\n {\n position = 'right',\n tabs,\n headerAction,\n footerAction,\n defaultWidth,\n minWidth = 150,\n maxWidth = 600,\n onWidthChange,\n activeTabId: controlledActiveTabId,\n onActiveTabChange,\n visible,\n onVisibilityChange,\n stripVisible,\n onStripVisibilityChange,\n showCloseButton = false,\n hideDefaultHeader = false,\n renderHeader,\n isSecondary = false,\n children,\n },\n ref\n ) {\n const isControlled = controlledActiveTabId !== undefined;\n\n const [width, setWidthState] = useState<number>(() => defaultWidth ?? 280);\n\n const setWidth = useCallback((px: number) => {\n setWidthState(px);\n onWidthChange?.(px);\n }, [onWidthChange]);\n\n // Suppresses the drawer's CSS transition during a resize drag — own state,\n // not a DOM class, so it can never leak into a nested secondary Sidebar's\n // drawer (see SidebarResizeHandle's onResizeStart/onResizeEnd below).\n const [isResizing, setIsResizing] = useState(false);\n\n // Internal active tab state (uncontrolled mode)\n const [internalActiveTabId, setInternalActiveTabId] = useState<string | null>(null);\n const activeTabId = isControlled ? controlledActiveTabId : internalActiveTabId;\n\n // Normalized header/footer rail entries, and the SidebarTab-shaped subset of each — a\n // header/footer tab (e.g. \"Settings\") must share the exact same lifecycle as a main tab.\n const normalizedHeaderEntries = useMemo(() => toRailArray(headerAction), [headerAction]);\n const normalizedFooterEntries = useMemo(() => toRailArray(footerAction), [footerAction]);\n const headerTabs = useMemo(() => normalizedHeaderEntries.filter(isRailTab), [normalizedHeaderEntries]);\n const footerTabs = useMemo(() => normalizedFooterEntries.filter(isRailTab), [normalizedFooterEntries]);\n const allTabs = useMemo(() => [...headerTabs, ...tabs, ...footerTabs], [headerTabs, tabs, footerTabs]);\n\n // Tracks which non-eager tabs have been mounted at least once (for lazy-mount / preserveState).\n // eagerMount tabs are folded in via effectiveMountedTabIds below, so no effect needed for them.\n const [mountedTabIds, setMountedTabIds] = useState<Set<string>>(() => new Set<string>());\n\n // Derives the full mounted set during render — no effect needed.\n // Includes: accumulated mountedTabIds + the currently active tab (handles controlled\n // prop changes where setActiveTabId is never called) + all eagerMount tabs.\n const effectiveMountedTabIds = useMemo(() => {\n const result = new Set(mountedTabIds);\n if (activeTabId) result.add(activeTabId);\n for (const tab of allTabs) {\n if (tab.eagerMount) result.add(tab.id);\n }\n return result;\n }, [mountedTabIds, activeTabId, allTabs]);\n\n // Stable refs for imperative handle\n const activeTabIdRef = useRef<string | null>(activeTabId ?? null);\n useEffect(() => { activeTabIdRef.current = activeTabId ?? null; }, [activeTabId]);\n\n const widthRef = useRef<number>(width);\n useEffect(() => { widthRef.current = width; }, [width]);\n\n const setActiveTabId = useCallback(\n (id: string | null) => {\n // Update mounted set in the same render batch as the tab switch — avoids setState-in-effect.\n if (id !== null) {\n setMountedTabIds(prev => {\n if (prev.has(id)) return prev;\n const next = new Set(prev);\n next.add(id);\n return next;\n });\n } else {\n // Drawer closing: evict transient tabs (non-eager, non-preserveState).\n setMountedTabIds(prev => {\n let changed = false;\n const next = new Set(prev);\n for (const tabId of prev) {\n const tab = allTabs.find(t => t.id === tabId);\n if (tab && !tab.eagerMount && !tab.preserveState) {\n next.delete(tabId);\n changed = true;\n }\n }\n return changed ? next : prev;\n });\n }\n if (isControlled) {\n onActiveTabChange?.(id);\n } else {\n setInternalActiveTabId(id);\n onActiveTabChange?.(id);\n }\n },\n [isControlled, onActiveTabChange, allTabs]\n );\n\n // If the active tab stops existing in `tabs`/`headerAction`/`footerAction` (its contributing\n // panel changed/closed, or the tab was otherwise removed), close the drawer rather than\n // leaving it open and empty with no tab button left to click closed — never silently fall\n // back to a different tab the user didn't choose.\n useEffect(() => {\n if (activeTabId != null && !allTabs.some(t => t.id === activeTabId)) {\n setActiveTabId(null);\n }\n }, [activeTabId, allTabs, setActiveTabId]);\n\n useImperativeHandle(ref, () => ({\n openTab: (tabId: string) => setActiveTabId(tabId),\n closeDrawer: () => setActiveTabId(null),\n getActiveTab: () => activeTabIdRef.current,\n show: () => onVisibilityChange?.(true),\n hide: () => onVisibilityChange?.(false),\n toggle: () => onVisibilityChange?.(visible === false ? true : false),\n showStrip: () => onStripVisibilityChange?.(true),\n hideStrip: () => onStripVisibilityChange?.(false),\n setWidth: (px: number) => setWidth(Math.max(minWidth, Math.min(maxWidth, px))),\n getWidth: () => widthRef.current,\n }), [setActiveTabId, visible, onVisibilityChange, onStripVisibilityChange, setWidth, minWidth, maxWidth]);\n\n const handleTabClick = useCallback((tabId: string) => {\n setActiveTabId(activeTabId === tabId ? null : tabId);\n }, [activeTabId, setActiveTabId]);\n\n const handleClose = useCallback(() => setActiveTabId(null), [setActiveTabId]);\n\n // `renderHeader` alone (no `hideDefaultHeader`) also suppresses the default\n // header — see the render condition below. Derived once here so both that\n // condition and the dev-warning effect stay in sync.\n const hasHeaderOverride = hideDefaultHeader || renderHeader != null;\n\n // Dev-only: showCloseButton renders nothing once the default header is\n // suppressed, since its close button is part of that (now-skipped) header.\n // Warns once per mounted Sidebar — closeButtonWarnedRef lives in component\n // scope (not inside the effect) so it survives re-renders; depending on the\n // derived boolean rather than `renderHeader` itself avoids re-running this\n // on every render, since `renderHeader` is typically passed as a fresh\n // inline arrow function each time.\n const closeButtonWarnedRef = useRef(false);\n useEffect(() => {\n if (process.env.NODE_ENV !== 'development') return;\n if (!showCloseButton || !hasHeaderOverride) return;\n if (closeButtonWarnedRef.current) return;\n closeButtonWarnedRef.current = true;\n console.warn(\n '[react-dockable-desktop] `showCloseButton` has no effect because the default header is ' +\n 'suppressed (`hideDefaultHeader` is set, or `renderHeader` was passed). The \"X\" close button ' +\n 'only renders as part of the library\\'s own default header, which is skipped in this case. ' +\n 'Add your own close control inside `renderHeader` (or `renderContent`), wired to its `onClose` ' +\n 'parameter or `useSidebarTab().onClose`.'\n );\n }, [showCloseButton, hasHeaderOverride]);\n\n // Stable context value for useSidebar() consumers\n const sidebarContextValue = useMemo<SidebarContextValue>(() => ({\n openTab: (tabId: string) => setActiveTabId(tabId),\n closeDrawer: () => setActiveTabId(null),\n getActiveTab: () => activeTabIdRef.current,\n position,\n isSecondary,\n }), [setActiveTabId, position, isSecondary]);\n\n // ---- Derived visibility flags ----\n const isSidebarVisible = visible !== false;\n const isStripVisible = isSidebarVisible && stripVisible !== false;\n const isDrawerOpen = isSidebarVisible && activeTabId != null;\n\n // ---- Drawer element (shared between left and right) ----\n const drawer = (\n <div\n className={`rdd-sidebar-content-drawer rdd-${position}`}\n style={{\n // flex-basis drives the visible width; width: 0px has no effect in flex context\n // when flex-basis is set — so we animate flex-basis, not width.\n flexBasis: isDrawerOpen ? `${width}px` : '0px',\n flexShrink: 1,\n flexGrow: 0,\n minWidth: isDrawerOpen ? `${minWidth}px` : '0px',\n maxWidth: isDrawerOpen ? `${maxWidth}px` : '0px',\n overflow: 'hidden',\n // Suppressed during a resize drag via this instance's own isResizing state.\n transition: isResizing\n ? 'none'\n : 'flex-basis 0.2s cubic-bezier(0.4, 0, 0.2, 1), min-width 0.2s cubic-bezier(0.4, 0, 0.2, 1), max-width 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n }}\n >\n {allTabs.map(tab => {\n const isMounted = effectiveMountedTabIds.has(tab.id);\n if (!isMounted) return null;\n\n const isCurrent = activeTabId === 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 — tab label, plus an optional close button (showCloseButton) as\n an extra way to collapse the sidebar; clicking the active tab icon still works too.\n Suppressed for every tab when hideDefaultHeader is set, OR simply when renderHeader\n is passed (either alone is sufficient — see hasHeaderOverride above, which keeps\n this in sync with the dev-warning effect) — onClose/onOpen still flow to either\n one regardless. */}\n {hasHeaderOverride ? (\n renderHeader?.(tab, handleClose, onOpen)\n ) : (\n <div className=\"rdd-sidebar-drawer-header\">\n <span className=\"rdd-sidebar-header-title\">{tab.label}</span>\n {showCloseButton && (\n <button\n type=\"button\"\n className=\"rdd-sidebar-drawer-close-button\"\n onClick={handleClose}\n title=\"Close\"\n aria-label=\"Close\"\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 )}\n\n {/* Drawer body — consumer-supplied content */}\n <div className=\"rdd-sidebar-drawer-body\">\n <SidebarTabProvider\n tabId={tab.id}\n onClose={handleClose}\n onOpen={onOpen}\n setActiveTabId={setActiveTabId}\n >\n {tab.renderContent(tab.id, handleClose, onOpen)}\n </SidebarTabProvider>\n </div>\n </div>\n );\n })}\n </div>\n );\n\n // ---- Resize handle (only interactive when drawer is open) ----\n const resizeHandle = isDrawerOpen ? (\n <SidebarResizeHandle\n position={position}\n currentWidth={width}\n minWidth={minWidth}\n maxWidth={maxWidth}\n onWidthChange={setWidth}\n onResizeStart={() => setIsResizing(true)}\n onResizeEnd={() => setIsResizing(false)}\n />\n ) : null;\n\n return (\n <SidebarContext.Provider value={sidebarContextValue}>\n <div\n style={{\n display: 'flex',\n flexDirection: 'row',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {position === 'left' && (\n <SidebarTabStrip\n tabs={tabs}\n headerEntries={normalizedHeaderEntries}\n footerEntries={normalizedFooterEntries}\n activeTabId={activeTabId}\n isVisible={isStripVisible}\n position={position}\n onTabClick={handleTabClick}\n />\n )}\n {position === 'left' && drawer}\n {position === 'left' && resizeHandle}\n\n {/* Workspace content — fills all remaining space */}\n <div style={{ flex: '1 1 0%', minWidth: 0, overflow: 'hidden' }}>\n {children}\n </div>\n\n {position === 'right' && resizeHandle}\n {position === 'right' && drawer}\n {position === 'right' && (\n <SidebarTabStrip\n tabs={tabs}\n headerEntries={normalizedHeaderEntries}\n footerEntries={normalizedFooterEntries}\n activeTabId={activeTabId}\n isVisible={isStripVisible}\n position={position}\n onTabClick={handleTabClick}\n />\n )}\n </div>\n </SidebarContext.Provider>\n );\n });\n\n// ==========================================\n// SecondarySidebar\n// ==========================================\n\n/**\n * Props for {@link SecondarySidebar} — identical to {@link SidebarProps} except\n * `position` (always the opposite of whatever primary `Sidebar` it's nested inside)\n * and `isSecondary` (always `true`) are not settable.\n */\nexport type SecondarySidebarProps = Omit<SidebarProps, 'position' | 'isSecondary'>;\n\n/**\n * A second, independent `Sidebar` instance for the opposite edge of the screen —\n * same component, same behavior, zero forked code. Must be rendered inside a\n * primary `Sidebar`'s `children`; automatically takes whichever side that primary\n * isn't using, so the side is never specified directly.\n *\n * @throws Error if rendered without an ancestor `Sidebar`, or nested inside another\n * `SecondarySidebar` — this library supports exactly one primary and one secondary,\n * nothing deeper.\n */\nexport const SecondarySidebar: React.ForwardRefExoticComponent<SecondarySidebarProps & React.RefAttributes<SidebarHandle>> =\n forwardRef<SidebarHandle, SecondarySidebarProps>(function SecondarySidebar(props, ref) {\n const primary = useContext(SidebarContext);\n if (!primary) {\n throw new Error('SecondarySidebar must be rendered inside a primary Sidebar\\'s children');\n }\n if (primary.isSecondary) {\n throw new Error('SecondarySidebar cannot be nested inside another SecondarySidebar');\n }\n const opposite = primary.position === 'left' ? 'right' : 'left';\n return <Sidebar ref={ref} {...props} position={opposite} isSecondary />;\n });\n\n// ==========================================\n// Hooks\n// ==========================================\n\n/**\n * Returns sidebar control functions from anywhere inside a `<Sidebar>` tree,\n * including floating panels rendered via `{children}`.\n *\n * @throws Error if used outside of a {@link Sidebar}.\n */\nexport function useSidebar(): SidebarContextValue {\n const ctx = useContext(SidebarContext);\n if (!ctx) throw new Error('useSidebar must be used within Sidebar');\n return ctx;\n}\n\n/**\n * Returns tab-specific control functions for components rendered inside a\n * sidebar tab's `renderContent` tree.\n *\n * @throws Error if used outside of a {@link Sidebar} tab's `renderContent` tree.\n */\nexport function useSidebarTab(): SidebarTabContextValue {\n const ctx = useContext(SidebarTabContext);\n if (!ctx) throw new Error('useSidebarTab must be used within a Sidebar tab renderContent tree');\n return ctx;\n}\n\nexport default Sidebar;\n","/**\n * @file Toolbar.tsx\n * @description Vertical or horizontal toolbar strip hosting action buttons,\n * mutually-exclusive radio tool groups, independent toggle modifiers,\n * and collapsible sub-tool group flyouts.\n * State is library-wide via DockableDesktopProvider / ToolbarContext.\n */\n\nimport React, { forwardRef, useImperativeHandle, useState, useRef, useEffect, useLayoutEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useToolbar } from './ToolbarContext';\nimport type { ToolbarContextValue } from './ToolbarContext';\n\n// ==========================================\n// Item type definitions\n// ==========================================\n\n/** A one-shot action button. */\nexport interface ToolbarActionItem {\n type: 'action';\n id: string;\n label: string;\n icon: React.ReactNode;\n onClick: () => void;\n disabled?: boolean;\n}\n\n/** A mutually-exclusive radio button within a named group. */\nexport interface ToolbarRadioItem {\n type: 'radio';\n id: string;\n group: string;\n label: string;\n icon: React.ReactNode;\n /** Keyboard shortcut hint — displayed in the group flyout; reserved for future custom tooltip. */\n shortcut?: string;\n /** Called when this item becomes active. */\n onActivate?: (id: string) => void;\n disabled?: boolean;\n}\n\n/**\n * An independent on/off toggle modifier (e.g. snap-to-grid).\n *\n * Supports both uncontrolled mode (omit `rdd-active` — state lives in\n * ToolbarContext, keyed by `id`) and controlled mode (provide `rdd-active` —\n * the caller is the single source of truth and must update the prop in\n * response to `onToggle`). Controlled mode is what lets independent\n * instances of the same panel type report independent active state\n * instead of colliding on a shared id.\n */\nexport interface ToolbarToggleItem {\n type: 'toggle';\n id: string;\n label: string;\n icon: React.ReactNode;\n /** Keyboard shortcut hint — reserved for future custom tooltip. */\n shortcut?: string;\n /**\n * Controlled active state. When provided (even as false), the component\n * reads this prop instead of ToolbarContext and does not update context\n * on click. Omit (undefined) for uncontrolled behaviour.\n */\n active?: boolean;\n /** Called after the toggle flips; receives the new active state. */\n onToggle?: (active: boolean) => void;\n disabled?: boolean;\n}\n\n/** A visual divider between button groups. */\nexport interface ToolbarSeparator {\n type: 'separator';\n}\n\n// ==========================================\n// Group item types (sub-tool flyout)\n// ==========================================\n\n/**\n * A single selectable sub-tool inside a group flyout.\n * All sub-items in the same ToolbarGroupItem share one radio group\n * keyed by the parent ToolbarGroupItem's `id`.\n */\nexport interface ToolbarGroupSubItem {\n id: string;\n label: string;\n icon: React.ReactNode;\n /** Keyboard shortcut displayed in the flyout panel. */\n shortcut?: string;\n disabled?: boolean;\n /** Called when this sub-item is selected. */\n onActivate?: (id: string) => void;\n}\n\n/** An entry inside a group flyout — either a sub-item or a separator. */\nexport type ToolbarGroupEntry = ToolbarGroupSubItem | { type: 'separator' };\n\n/**\n * A collapsed tool-family button that opens a flyout panel listing all\n * sub-tools. Only one sub-tool may be active at a time (radio semantics).\n * The parent button's icon morphs to show the currently active sub-tool.\n *\n * Supports both uncontrolled mode (omit activeItemId — state lives in\n * ToolbarContext) and controlled mode (provide activeItemId — the caller\n * is the single source of truth and must update the prop in response to\n * onActiveItemChange).\n */\nexport interface ToolbarGroupItem {\n type: 'group';\n /** Serves as both the button ID and the radio group key in ToolbarContext. */\n id: string;\n /** Tooltip / aria-label shown when no sub-item is active. */\n label: string;\n /** Icon shown when no sub-item is active. */\n defaultIcon: React.ReactNode;\n items: ToolbarGroupEntry[];\n disabled?: boolean;\n /**\n * Controlled active sub-item id. When provided (even as null), the\n * component reads this prop instead of ToolbarContext and fires\n * onActiveItemChange on click instead of updating context.\n * Omit (undefined) for uncontrolled behaviour.\n */\n activeItemId?: string | null;\n /**\n * Called when the user selects a sub-item in controlled mode.\n * The toolbar does not update itself — the caller must update activeItemId.\n */\n onActiveItemChange?: (id: string) => void;\n}\n\nexport type ToolbarItem =\n | ToolbarActionItem\n | ToolbarRadioItem\n | ToolbarToggleItem\n | ToolbarGroupItem\n | ToolbarSeparator;\n\n// ==========================================\n// Props and Handle\n// ==========================================\n\nexport interface ToolbarProps {\n /** Side the strip is attached to. Controls strip orientation. Default: 'left' */\n position?: 'left' | 'right' | 'top' | 'bottom';\n /** Ordered list of items to render. */\n items: ToolbarItem[];\n /** Collapse the strip to zero width/height. State is preserved — no unmount. */\n visible?: boolean;\n /** Called when show/hide/toggle is invoked on the imperative handle. */\n onVisibilityChange?: (visible: boolean) => void;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface ToolbarHandle {\n show(): void;\n hide(): void;\n toggle(): void;\n}\n\n// ==========================================\n// ToolbarGroupButton — internal sub-component\n// Manages its own open/close state and renders the flyout via a portal\n// so it is never clipped by the strip's overflow:hidden.\n// ==========================================\n\ninterface ToolbarGroupButtonProps {\n item: ToolbarGroupItem;\n position: 'left' | 'right' | 'top' | 'bottom';\n toolbar: ToolbarContextValue;\n}\n\nfunction flyoutPosition(\n rect: DOMRect,\n position: 'left' | 'right' | 'top' | 'bottom',\n isRtl = false,\n gap = 8,\n): React.CSSProperties {\n switch (position) {\n case 'left':\n // RTL: flex-row reverses, so 'left' toolbar sits on the right → open leftward\n return isRtl\n ? { right: window.innerWidth - rect.left + gap, top: rect.top }\n : { left: rect.right + gap, top: rect.top };\n case 'right':\n // RTL: 'right' toolbar sits on the left → open rightward\n return isRtl\n ? { left: rect.right + gap, top: rect.top }\n : { right: window.innerWidth - rect.left + gap, top: rect.top };\n case 'top':\n return isRtl\n ? { top: rect.bottom + gap, right: window.innerWidth - rect.right }\n : { top: rect.bottom + gap, left: rect.left };\n case 'bottom':\n return isRtl\n ? { bottom: window.innerHeight - rect.top + gap, right: window.innerWidth - rect.right }\n : { bottom: window.innerHeight - rect.top + gap, left: rect.left };\n }\n}\n\nfunction ToolbarGroupButton({ item, position, toolbar }: ToolbarGroupButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [btnRect, setBtnRect] = useState<DOMRect | null>(null);\n const btnRef = useRef<HTMLButtonElement>(null);\n const flyoutRef = useRef<HTMLDivElement>(null);\n\n const isControlled = item.activeItemId !== undefined;\n const activeId = isControlled ? item.activeItemId : toolbar.getActiveInGroup(item.id);\n const activeSubItem = item.items.find(\n (e): e is ToolbarGroupSubItem => !('type' in e) && e.id === activeId,\n );\n const isActive = activeId !== null;\n const displayIcon = activeSubItem?.icon ?? item.defaultIcon;\n const displayLabel = activeSubItem?.label ?? item.label;\n\n const handleClick = () => {\n if (item.disabled) return;\n if (!isOpen && btnRef.current) {\n setBtnRect(btnRef.current.getBoundingClientRect());\n }\n setIsOpen(prev => !prev);\n };\n\n // Clamp flyout to viewport after it renders (runs before paint to avoid jitter)\n useLayoutEffect(() => {\n if (!isOpen || !flyoutRef.current) return;\n const el = flyoutRef.current;\n const r = el.getBoundingClientRect();\n const PAD = 8;\n if (r.right > window.innerWidth - PAD) {\n el.style.left = `${Math.max(PAD, window.innerWidth - r.width - PAD)}px`;\n el.style.right = 'auto';\n }\n if (r.left < PAD) {\n el.style.left = `${PAD}px`;\n el.style.right = 'auto';\n }\n if (r.bottom > window.innerHeight - PAD) {\n el.style.top = `${Math.max(PAD, window.innerHeight - r.height - PAD)}px`;\n el.style.bottom = 'auto';\n }\n if (r.top < PAD) {\n el.style.top = `${PAD}px`;\n el.style.bottom = 'auto';\n }\n }, [isOpen]);\n\n // Close flyout on click-away (exclude clicks inside the button or flyout itself)\n useEffect(() => {\n if (!isOpen) return;\n const onMouseDown = (e: MouseEvent) => {\n const target = e.target as Node;\n if (btnRef.current?.contains(target)) return;\n if (flyoutRef.current?.contains(target)) return;\n setIsOpen(false);\n };\n document.addEventListener('mousedown', onMouseDown);\n return () => document.removeEventListener('mousedown', onMouseDown);\n }, [isOpen]);\n\n // Close flyout on Escape\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') setIsOpen(false); };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [isOpen]);\n\n return (\n <>\n <button\n ref={btnRef}\n type=\"button\"\n className={`rdd-toolbar-btn rdd-toolbar-btn-group${isActive ? ' rdd-active' : ''}`}\n title={displayLabel}\n aria-label={displayLabel}\n aria-expanded={isOpen}\n aria-haspopup=\"menu\"\n disabled={item.disabled}\n onClick={handleClick}\n >\n {displayIcon}\n </button>\n\n {isOpen && btnRect && createPortal(\n <div\n ref={flyoutRef}\n className={`rdd-toolbar-group-flyout rdd-${position}`}\n style={flyoutPosition(btnRect, position, document.documentElement.dir === 'rtl')}\n role=\"menu\"\n >\n {item.items.map((entry, i) => {\n if ('type' in entry) {\n return <div key={`sep-${i}`} className=\"rdd-toolbar-group-flyout-sep\" role=\"separator\" />;\n }\n const isSubActive = activeId === entry.id;\n return (\n <button\n key={entry.id}\n type=\"button\"\n className={`rdd-toolbar-group-flyout-item${isSubActive ? ' rdd-active' : ''}`}\n disabled={entry.disabled}\n role=\"menuitem\"\n aria-pressed={isSubActive}\n onClick={() => {\n if (isControlled) {\n item.onActiveItemChange?.(entry.id);\n } else {\n toolbar.setActiveInGroup(item.id, entry.id);\n }\n entry.onActivate?.(entry.id);\n setIsOpen(false);\n }}\n >\n <span className=\"rdd-toolbar-group-flyout-icon\">{entry.icon}</span>\n <span className=\"rdd-toolbar-group-flyout-label\">{entry.label}</span>\n {entry.shortcut && (\n <span className=\"rdd-toolbar-group-flyout-shortcut\">{entry.shortcut}</span>\n )}\n </button>\n );\n })}\n </div>,\n document.body,\n )}\n </>\n );\n}\n\n// ==========================================\n// renderItem — pure helper outside component\n// ==========================================\n\nfunction renderItem(\n item: ToolbarItem,\n index: number,\n toolbar: ToolbarContextValue,\n position: 'left' | 'right' | 'top' | 'bottom',\n): React.ReactNode {\n switch (item.type) {\n case 'separator':\n return <div key={`sep-${index}`} className=\"rdd-toolbar-separator\" role=\"separator\" />;\n\n case 'action':\n return (\n <button\n key={item.id}\n type=\"button\"\n className=\"rdd-toolbar-btn rdd-toolbar-btn-action\"\n title={item.label}\n aria-label={item.label}\n disabled={item.disabled}\n onClick={item.onClick}\n >\n {item.icon}\n </button>\n );\n\n case 'radio': {\n const isActive = toolbar.getActiveInGroup(item.group) === item.id;\n return (\n <button\n key={item.id}\n type=\"button\"\n className={`rdd-toolbar-btn rdd-toolbar-btn-radio${isActive ? ' rdd-active' : ''}`}\n title={item.label}\n aria-label={item.label}\n aria-pressed={isActive}\n disabled={item.disabled}\n onClick={() => {\n toolbar.setActiveInGroup(item.group, item.id);\n item.onActivate?.(item.id);\n }}\n >\n {item.icon}\n </button>\n );\n }\n\n case 'toggle': {\n const controlled = item.active !== undefined;\n const isActive = controlled ? item.active! : toolbar.isModifierActive(item.id);\n return (\n <button\n key={item.id}\n type=\"button\"\n className={`rdd-toolbar-btn rdd-toolbar-btn-toggle${isActive ? ' rdd-active' : ''}`}\n title={item.label}\n aria-label={item.label}\n aria-pressed={isActive}\n disabled={item.disabled}\n onClick={() => {\n if (!controlled) toolbar.toggleModifier(item.id);\n item.onToggle?.(!isActive);\n }}\n >\n {item.icon}\n </button>\n );\n }\n\n case 'group':\n return (\n <ToolbarGroupButton\n key={item.id}\n item={item}\n position={position}\n toolbar={toolbar}\n />\n );\n }\n}\n\n// ==========================================\n// Component\n// ==========================================\n\nexport const Toolbar: React.ForwardRefExoticComponent<ToolbarProps & React.RefAttributes<ToolbarHandle>> = forwardRef<ToolbarHandle, ToolbarProps>(function Toolbar(\n { position = 'left', items, visible, onVisibilityChange, className, style },\n ref\n) {\n const toolbar = useToolbar();\n const isVertical = position === 'left' || position === 'right';\n\n useImperativeHandle(ref, () => ({\n show: () => onVisibilityChange?.(true),\n hide: () => onVisibilityChange?.(false),\n toggle: () => onVisibilityChange?.(visible === false ? true : false),\n }), [visible, onVisibilityChange]);\n\n // CSS owns the open-state dimensions (including the touch @media 56px override).\n // Inline style only forces 0px when collapsed so the transition animates correctly.\n const collapseStyle: React.CSSProperties = visible !== false\n ? {}\n : isVertical\n ? { width: '0px' }\n : { height: '0px' };\n\n return (\n <div\n className={`rdd-toolbar-strip rdd-${position}${className ? ` ${className}` : ''}`}\n role=\"toolbar\"\n aria-orientation={isVertical ? 'vertical' : 'horizontal'}\n style={{ ...collapseStyle, ...style }}\n >\n {items.map((item, i) => renderItem(item, i, toolbar, position))}\n </div>\n );\n});\n\n// ==========================================\n// Barrel re-exports from ToolbarContext\n// ==========================================\n\nexport { useToolbar, ToolbarProvider } from './ToolbarContext';\nexport type { ToolbarContextValue } from './ToolbarContext';\n","import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/** Visual type of a toast notification. Determines the icon and accent color. */\nexport type ToastType = 'info' | 'success' | 'warning' | 'error';\n\n/** Corner position of the `<ToastContainer>` relative to the viewport. */\nexport type ToastPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n\n/**\n * Per-notification options passed to `toast()`, `toast.info()`, etc.\n * All fields are optional and fall back to `<ToastContainer>` defaults when unset.\n */\nexport interface ToastOptions {\n /** Visual type. Overridden by the `toast.info/success/warning/error` shorthands. @default 'info' */\n type?: ToastType;\n /** Auto-dismiss delay in ms. `0` = sticky (never auto-dismisses). @default from container */\n duration?: number;\n /** Explicit ID for dedup — calling `toast.*` with the same `id` updates the existing card in-place. */\n id?: string;\n /** Show the × close button on this notification. @default from container */\n closable?: boolean;\n /** Override the built-in type icon with arbitrary content. */\n icon?: React.ReactNode;\n /** Replace the string message with arbitrary JSX. */\n content?: React.ReactNode;\n /** Called when the notification is dismissed by timer, close button, or `toast.dismiss()`. */\n onClose?: () => void;\n}\n\n/**\n * Fully-resolved options passed to `ToastAdapter.show()` and `ToastAdapter.update()`.\n * All optional `ToastOptions` fields are resolved against the container defaults.\n */\nexport interface ResolvedToastOptions {\n id: string;\n type: ToastType;\n duration: number;\n closable: boolean;\n icon?: React.ReactNode;\n content?: React.ReactNode;\n onClose?: () => void;\n}\n\n/**\n * Props for `<ToastContainer>`. Mount one instance at your app root alongside `ModalStackRenderer`.\n * @example\n * <ToastContainer position=\"top-right\" progressBar />\n */\nexport interface ToastContainerProps {\n /** Where notifications appear in the viewport. @default 'top-right' */\n position?: ToastPosition;\n /** Maximum number of notifications shown simultaneously. Extras are queued. @default 3 */\n maxVisible?: number;\n /** Default auto-dismiss delay in ms. `0` = all notifications sticky. @default 5000 */\n defaultDuration?: number;\n /** Show the × close button on all notifications unless overridden per-toast. @default true */\n defaultClosable?: boolean;\n /** Pause the auto-dismiss timer while the cursor is over a notification. @default true */\n pauseOnHover?: boolean;\n /** Entry/exit animation style. @default 'slide' */\n animation?: 'slide' | 'fade' | 'none';\n /** When `true`, newest notification appears at the top of the stack. @default false */\n newestOnTop?: boolean;\n /** Show a countdown progress bar at the bottom of each notification. @default false */\n progressBar?: boolean;\n /** Width of each notification card in pixels. @default 320 */\n width?: number;\n /** Delegate all `toast.*` calls to a custom renderer (Ant Design, MUI, Sonner, etc.). */\n adapter?: ToastAdapter;\n}\n\n/**\n * Message set for `toast.promise()`. Each field may be static content or a function\n * that receives the resolved/rejected value and returns renderable content.\n * @template T The resolved value type of the tracked promise.\n */\nexport interface ToastPromiseMessages<T> {\n /** Shown while the promise is pending. */\n pending: React.ReactNode;\n /** Shown on fulfillment. Pass a function to include the resolved value. */\n success: React.ReactNode | ((result: T) => React.ReactNode);\n /** Shown on rejection. Pass a function to include the error reason. */\n error: React.ReactNode | ((err: unknown) => React.ReactNode);\n}\n\n/**\n * Strategy interface for replacing the built-in toast renderer with an external library.\n * Pass an instance via `<ToastContainer adapter={...} />` to redirect all `toast.*` calls\n * without changing any call sites in your application.\n * @see ToastContainerProps.adapter\n */\nexport interface ToastAdapter {\n /** Called when a new notification is requested. */\n show(id: string, message: React.ReactNode, options: ResolvedToastOptions): void;\n /** Called when an existing notification is updated (e.g. after `toast.promise()` resolves). */\n update(id: string, message: React.ReactNode, options: Partial<ResolvedToastOptions>): void;\n /** Called to dismiss one notification (`id` provided) or all active notifications (no `id`). */\n dismiss(id?: string): void;\n /**\n * `null` means the adapter manages its own DOM and `<ToastContainer>` renders nothing.\n * A component causes `<ToastContainer>` to portal-render it with a `position` prop.\n */\n Container: React.ComponentType<{ position: ToastPosition }> | null;\n}\n\n// ─── Internal types ───────────────────────────────────────────────────────────\n\ntype ToastEvent =\n | { kind: 'show'; id: string; message: React.ReactNode; rawOpts: ToastOptions & { id: string } }\n | { kind: 'update'; id: string; message: React.ReactNode; patch: Partial<ResolvedToastOptions> }\n | { kind: 'dismiss'; id?: string };\n\ninterface ActiveToast {\n id: string;\n message: React.ReactNode;\n options: ResolvedToastOptions;\n exiting: boolean;\n}\n\n// ─── ToastEmitter ─────────────────────────────────────────────────────────────\n\nclass ToastEmitter {\n private listeners = new Set<(e: ToastEvent) => void>();\n private counter = 0;\n\n subscribe(fn: (e: ToastEvent) => void) { this.listeners.add(fn); }\n unsubscribe(fn: (e: ToastEvent) => void) { this.listeners.delete(fn); }\n\n show(message: React.ReactNode, opts: ToastOptions = {}): string {\n const id = opts.id ?? `toast-${++this.counter}`;\n this.emit({ kind: 'show', id, message, rawOpts: { ...opts, id } });\n return id;\n }\n\n update(id: string, message: React.ReactNode, patch: Partial<ResolvedToastOptions>) {\n this.emit({ kind: 'update', id, message, patch });\n }\n\n dismiss(id?: string) { this.emit({ kind: 'dismiss', id }); }\n\n private emit(e: ToastEvent) { this.listeners.forEach(fn => fn(e)); }\n}\n\nconst emitter = new ToastEmitter();\n\n// ─── toast public API ─────────────────────────────────────────────────────────\n\n/**\n * Type of the `toast` singleton. Callable directly or via named shorthand methods.\n * Import this type to annotate variables or props that accept the `toast` object.\n * @example\n * function notify(fn: ToastFunction) { fn.success('Done!'); }\n */\nexport interface ToastFunction {\n /** Show a notification. `opts.type` defaults to `'info'`. Returns the notification ID. */\n (msg: React.ReactNode, opts?: ToastOptions): string;\n /** Show an info notification. Returns the notification ID. */\n info: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Show a success notification. Returns the notification ID. */\n success: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Show a warning notification. Returns the notification ID. */\n warning: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Show an error notification. Returns the notification ID. */\n error: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Dismiss a notification by ID, or all active notifications when called with no argument. */\n dismiss: (id?: string) => void;\n /**\n * Track a promise through pending → success/error states.\n * Shows a sticky pending notification immediately, then transitions it on settlement.\n * @template T The resolved value type of the promise.\n */\n promise: <T>(promise: Promise<T>, messages: ToastPromiseMessages<T>, opts?: ToastOptions) => Promise<T>;\n}\n\n/**\n * Imperative notification singleton. Call from anywhere — inside or outside React.\n * Mount `<ToastContainer>` once at your app root to activate the renderer.\n * @example\n * toast.success('File saved.');\n * toast.error('Upload failed.', { duration: 0 }); // sticky\n * toast.promise(saveFile(), { pending: 'Saving…', success: 'Saved!', error: 'Failed.' });\n */\nexport const toast: ToastFunction = Object.assign(\n (msg: React.ReactNode, opts?: ToastOptions): string => emitter.show(msg, opts),\n {\n info: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'info' }),\n success: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'success' }),\n warning: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'warning' }),\n error: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'error' }),\n dismiss: (id?: string): void => emitter.dismiss(id),\n promise: <T,>(\n promise: Promise<T>,\n messages: ToastPromiseMessages<T>,\n opts?: ToastOptions\n ): Promise<T> => {\n const id = emitter.show(messages.pending, { ...opts, type: 'info', duration: 0 });\n promise.then(\n result => {\n const msg = typeof messages.success === 'function' ? messages.success(result) : messages.success;\n emitter.update(id, msg, { type: 'success', duration: opts?.duration ?? 5000 });\n },\n err => {\n const msg = typeof messages.error === 'function' ? messages.error(err) : messages.error;\n emitter.update(id, msg, { type: 'error', duration: opts?.duration ?? 5000 });\n }\n );\n return promise;\n },\n }\n);\n\n// ─── Icons ────────────────────────────────────────────────────────────────────\n\nconst InfoIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.5\"/>\n <path d=\"M8 5v.01M8 7.5v3.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\nconst SuccessIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.5\"/>\n <path d=\"M5 8l2 2 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n);\nconst WarningIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8 2.5L14 13.5H2L8 2.5z\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinejoin=\"round\"/>\n <path d=\"M8 7v2.5M8 11.5v.01\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\nconst ErrorIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.5\"/>\n <path d=\"M5.5 5.5l5 5M10.5 5.5l-5 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\nconst CloseIcon = () => (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 4l8 8M12 4l-8 8\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\n\nconst DEFAULT_ICONS: Record<ToastType, React.ReactNode> = {\n info: <InfoIcon />,\n success: <SuccessIcon />,\n warning: <WarningIcon />,\n error: <ErrorIcon />,\n};\n\n// ─── ToastItem ────────────────────────────────────────────────────────────────\n\ninterface ToastItemProps {\n id: string;\n message: React.ReactNode;\n options: ResolvedToastOptions;\n exiting: boolean;\n isLeft: boolean;\n showProgress: boolean;\n pauseOnHover: boolean;\n animation: 'slide' | 'fade' | 'none';\n onDismiss: (id: string) => void;\n onExited: (id: string) => void;\n}\n\nfunction ToastItem({\n id, message, options, exiting, isLeft,\n showProgress, pauseOnHover, animation, onDismiss, onExited,\n}: ToastItemProps) {\n const divRef = useRef<HTMLDivElement>(null);\n const bodyRef = useRef<HTMLDivElement>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const remainRef = useRef<number>(options.duration);\n const startRef = useRef<number>(0);\n const [paused, setPaused] = useState(false);\n\n const startEntry =\n animation === 'none' ? 'rdd-toast--visible' :\n animation === 'fade' ? 'rdd-toast--fade-entering' :\n isLeft ? 'rdd-toast--entering-left' :\n 'rdd-toast--entering';\n const [entryClass, setEntryClass] = useState(startEntry);\n\n // Keep max-height in sync with the card's true content height, so content that\n // grows after mount (e.g. toast.promise()'s pending -> error message) never gets\n // clipped by the overflow: hidden below. The card's own box is exactly what this\n // effect holds at a fixed height, so it never reports a resize on its own — the\n // ResizeObserver instead watches the unconstrained inner body (the only thing\n // that actually grows with its content) purely as a trigger, and reads the\n // outer card's scrollHeight (which reports the true, uncapped content height\n // even while a stale cap is still clipping it — offsetHeight/clientHeight would\n // just return that stale cap) to compute the new value. Frozen once exiting\n // starts: .rdd-toast--exiting's `max-height: 0 !important` below takes over\n // from there regardless of this inline value.\n useLayoutEffect(() => {\n const el = divRef.current;\n const body = bodyRef.current;\n if (!el || !body || exiting) return;\n\n const applyHeight = () => { el.style.maxHeight = `${el.scrollHeight}px`; };\n applyHeight();\n\n const observer = new ResizeObserver(applyHeight);\n observer.observe(body);\n return () => observer.disconnect();\n }, [exiting]);\n\n // Trigger entry transition on next frame\n useEffect(() => {\n if (animation === 'none') return;\n const raf = requestAnimationFrame(() => setEntryClass('rdd-toast--visible'));\n return () => cancelAnimationFrame(raf);\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Auto-dismiss timer\n const scheduleDismiss = useCallback((ms: number) => {\n if (ms <= 0) return;\n startRef.current = Date.now();\n timerRef.current = setTimeout(() => onDismiss(id), ms);\n }, [id, onDismiss]);\n\n useEffect(() => {\n if (timerRef.current) clearTimeout(timerRef.current);\n remainRef.current = options.duration;\n scheduleDismiss(options.duration);\n return () => { if (timerRef.current) clearTimeout(timerRef.current); };\n }, [options.duration, scheduleDismiss]);\n\n // Exit animation → call onExited after transition\n useEffect(() => {\n if (!exiting) return;\n const el = divRef.current;\n if (!el || animation === 'none') {\n onExited(id);\n return;\n }\n const handle = (e: TransitionEvent) => {\n if (e.propertyName === 'max-height') onExited(id);\n };\n el.addEventListener('transitionend', handle);\n const fallback = setTimeout(() => onExited(id), 520);\n return () => {\n el.removeEventListener('transitionend', handle);\n clearTimeout(fallback);\n };\n }, [exiting, id, onExited, animation]);\n\n const handleMouseEnter = () => {\n if (!pauseOnHover || options.duration === 0) return;\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n remainRef.current = Math.max(0, remainRef.current - (Date.now() - startRef.current));\n }\n setPaused(true);\n };\n\n const handleMouseLeave = () => {\n if (!pauseOnHover || options.duration === 0) return;\n setPaused(false);\n scheduleDismiss(remainRef.current);\n };\n\n const cls = [\n 'rdd-toast',\n options.type && `rdd-toast--${options.type}`,\n entryClass,\n exiting && 'rdd-toast--exiting',\n paused && 'rdd-toast--paused',\n ].filter(Boolean).join(' ');\n\n const icon = options.icon !== undefined ? options.icon : (options.type ? DEFAULT_ICONS[options.type] : null);\n\n return (\n <div\n ref={divRef}\n role=\"status\"\n aria-live=\"polite\"\n className={cls}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n {icon && icon}\n <div ref={bodyRef} className=\"rdd-toast__body\">\n {options.content !== undefined ? options.content : message}\n </div>\n {options.closable && (\n <button\n type=\"button\"\n className=\"rdd-toast__close\"\n onClick={() => onDismiss(id)}\n aria-label=\"Close notification\"\n >\n <CloseIcon />\n </button>\n )}\n {showProgress && options.duration > 0 && (\n <div\n className=\"rdd-toast__progress\"\n style={{ animationDuration: `${options.duration}ms` }}\n />\n )}\n </div>\n );\n}\n\n// ─── ToastContainer ───────────────────────────────────────────────────────────\n\nfunction resolveOpts(\n raw: ToastOptions & { id: string },\n defaultDuration: number,\n defaultClosable: boolean\n): ResolvedToastOptions {\n return {\n id: raw.id,\n type: raw.type ?? 'info',\n duration: raw.duration ?? defaultDuration,\n closable: raw.closable ?? defaultClosable,\n icon: raw.icon,\n content: raw.content,\n onClose: raw.onClose,\n };\n}\n\n/**\n * Portal-rendered notification host. Mount once at your app root, outside the workspace\n * container. All `toast.*` calls are routed here automatically via the internal event emitter.\n * @example\n * <ToastContainer position=\"top-right\" progressBar />\n */\nexport function ToastContainer({\n position = 'top-right',\n maxVisible = 3,\n defaultDuration = 5000,\n defaultClosable = true,\n pauseOnHover = true,\n animation = 'slide',\n newestOnTop = false,\n progressBar = false,\n width = 320,\n adapter,\n}: ToastContainerProps): React.ReactElement | null {\n const [toasts, setToasts] = useState<ActiveToast[]>([]);\n const queueRef = useRef<Array<{ id: string; message: React.ReactNode; rawOpts: ToastOptions & { id: string } }>>([]);\n const toastsRef = useRef<ActiveToast[]>(toasts);\n toastsRef.current = toasts;\n\n const handleDismiss = useCallback((id: string) => {\n setToasts(prev => prev.map(t => t.id === id ? { ...t, exiting: true } : t));\n toastsRef.current.find(t => t.id === id)?.options.onClose?.();\n }, []);\n\n const handleExited = useCallback((id: string) => {\n // Shift outside the updater (once) so the updater is pure and safe for StrictMode\n const promoted = queueRef.current.shift() ?? null;\n setToasts(prev => {\n const filtered = prev.filter(t => t.id !== id);\n if (!promoted) return filtered;\n const options = resolveOpts(promoted.rawOpts, defaultDuration, defaultClosable);\n return [...filtered, { id: promoted.id, message: promoted.message, options, exiting: false }];\n });\n }, [defaultDuration, defaultClosable]);\n\n // Subscribe to emitter (built-in path)\n useEffect(() => {\n if (adapter) return;\n\n const handle = (e: ToastEvent) => {\n if (e.kind === 'show') {\n // Resolve options once outside the updater so the updater stays pure\n const options = resolveOpts(e.rawOpts, defaultDuration, defaultClosable);\n const newEntry: ActiveToast = { id: e.id, message: e.message, options, exiting: false };\n const rawEntry = { id: e.id, message: e.message, rawOpts: e.rawOpts };\n\n setToasts(prev => {\n // Dedup check against actual prev (not stale ref) so batched calls are safe\n const existing = prev.find(t => t.id === e.id);\n if (existing) {\n return prev.map(t => t.id === e.id ? { ...t, message: e.message, options } : t);\n }\n // Count against actual prev so multiple synchronous toast() calls batch correctly\n const visible = prev.filter(t => !t.exiting).length;\n if (visible < maxVisible) {\n return [...prev, newEntry];\n }\n // Queue — guard prevents duplicate push when React calls updater twice (StrictMode)\n if (!queueRef.current.some(q => q.id === rawEntry.id)) {\n queueRef.current.push(rawEntry);\n }\n return prev;\n });\n } else if (e.kind === 'update') {\n setToasts(prev => prev.map(t => {\n if (t.id !== e.id) return t;\n const merged: ResolvedToastOptions = { ...t.options, ...e.patch, id: t.id };\n return { ...t, message: e.message, options: merged };\n }));\n queueRef.current = queueRef.current.map(q => {\n if (q.id !== e.id) return q;\n return { ...q, message: e.message, rawOpts: { ...q.rawOpts, ...e.patch } };\n });\n } else if (e.kind === 'dismiss') {\n if (e.id === undefined) {\n setToasts(prev => prev.map(t => ({ ...t, exiting: true })));\n queueRef.current = [];\n } else {\n const isActive = toastsRef.current.some(t => t.id === e.id);\n if (isActive) {\n handleDismiss(e.id);\n } else {\n queueRef.current = queueRef.current.filter(q => q.id !== e.id);\n }\n }\n }\n };\n\n emitter.subscribe(handle);\n return () => emitter.unsubscribe(handle);\n }, [adapter, maxVisible, defaultDuration, defaultClosable, handleDismiss]);\n\n // Subscribe to emitter (adapter path)\n useEffect(() => {\n if (!adapter) return;\n const handle = (e: ToastEvent) => {\n if (e.kind === 'show') {\n const opts = resolveOpts(e.rawOpts, defaultDuration, defaultClosable);\n adapter.show(e.id, e.message, opts);\n } else if (e.kind === 'update') {\n adapter.update(e.id, e.message, e.patch);\n } else if (e.kind === 'dismiss') {\n adapter.dismiss(e.id);\n }\n };\n emitter.subscribe(handle);\n return () => emitter.unsubscribe(handle);\n }, [adapter, defaultDuration, defaultClosable]);\n\n if (adapter) {\n if (!adapter.Container) return null;\n const AdapterContainer = adapter.Container;\n return createPortal(<AdapterContainer position={position} />, document.body);\n }\n\n const isLeft = position.endsWith('left');\n let dirMod = '';\n if (newestOnTop === true) dirMod = 'rdd-toast-container--newest-top';\n if (newestOnTop === false) dirMod = 'rdd-toast-container--newest-bottom';\n\n const cls = ['rdd-toast-container', `rdd-toast-container--${position}`, dirMod]\n .filter(Boolean).join(' ');\n\n return createPortal(\n <div className={cls} style={{ width }} aria-label=\"Notifications\" aria-live=\"polite\">\n {toasts.map(t => (\n <ToastItem\n key={t.id}\n id={t.id}\n message={t.message}\n options={t.options}\n exiting={t.exiting}\n isLeft={isLeft}\n showProgress={progressBar}\n pauseOnHover={pauseOnHover}\n animation={animation}\n onDismiss={handleDismiss}\n onExited={handleExited}\n />\n ))}\n </div>,\n document.body\n );\n}\n","import React, {\n useState,\n useContext,\n createContext,\n useRef,\n useLayoutEffect,\n useCallback,\n useMemo,\n useEffect,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { WindowStateContext } from './WindowManagerContext';\nimport type { FloatAnchor } from './WindowManagerContext';\nimport { flipZoneHorizontal } from './anchorGeometry';\nimport { startPointerDrag, computeResizedRect } from './dragResize';\nimport type { ResizeDir } from './dragResize';\nexport type { FloatAnchor };\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\n/** Edge of a panel to which a `PanelToolbar` attaches. */\nexport type ToolbarPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/**\n * Which of a docked widget's axes span the host panel instead of carrying a fixed size.\n *\n * A docked widget normally pins one end of each axis and carries an explicit size. A stretched\n * axis pins **both** ends and carries no size at all, so the widget tracks the panel as it\n * resizes — with no `ResizeObserver` and no JS, because CSS already does exactly this.\n *\n * - `'width'` — spans the panel's inline axis; height still fixed. A status or timeline strip.\n * - `'height'` — spans the block axis; width still fixed. A full-height side column.\n * - `'both'` — fills the panel, the inner-widget equivalent of maximizing a floating window.\n */\nexport type Stretch = 'width' | 'height' | 'both';\n\n/**\n * Where a docked widget sits: which corner it is anchored to, plus which axes (if any) span the\n * panel. Reported as a unit because a single gesture can change both at once — dropping a\n * full-width bottom strip onto the left edge flips the anchor *and* the stretched axis together,\n * and reporting those separately would expose a state that is never actually valid.\n */\nexport interface PanelFloatPlacement {\n anchor: FloatAnchor;\n stretch: Stretch | null;\n}\n\nconst stretchesInline = (s: Stretch | null): boolean => s === 'width' || s === 'both';\nconst stretchesBlock = (s: Stretch | null): boolean => s === 'height' || s === 'both';\n\n/** Adds one axis to a stretch value, keeping whatever was already stretched. */\nconst addAxis = (s: Stretch | null, axis: 'inline' | 'block'): Stretch => {\n if (axis === 'inline') return stretchesBlock(s) ? 'both' : 'width';\n return stretchesInline(s) ? 'both' : 'height';\n};\n\n/** Drops one axis from a stretch value, keeping the other. */\nconst releaseAxis = (s: Stretch | null, axis: 'inline' | 'block'): Stretch | null => {\n if (axis === 'inline') return s === 'both' ? 'height' : stretchesInline(s) ? null : s;\n return s === 'both' ? 'width' : stretchesBlock(s) ? null : s;\n};\n\n/**\n * Which stack buckets a placement occupies.\n *\n * The four corner buckets are really a proxy for *\"do these overlap on the inline axis?\"* — two\n * widgets in the same corner overlap and so stack; widgets in opposite corners sit side by side and\n * don't. A full-width strip overlaps everything on its edge, so it belongs to **both** buckets of\n * that edge and pushes the widgets in each. (Computing real inline overlap was rejected: widths\n * change continuously during a resize drag, so widgets would reshuffle mid-gesture.)\n *\n * A block-stretched widget spans the very axis stacking uses to separate siblings, so it can't\n * participate at all and occupies no bucket — z-order decides any overlap.\n */\nconst bucketsFor = (anchor: FloatAnchor, stretch: Stretch | null): FloatAnchor[] => {\n if (stretchesBlock(stretch)) return [];\n if (stretchesInline(stretch)) {\n return anchor.startsWith('top-')\n ? ['top-left', 'top-right']\n : ['bottom-left', 'bottom-right'];\n }\n return [anchor];\n};\n\n/** Replaces one half of a corner anchor, leaving the other axis alone. */\nconst withInlineHalf = (a: FloatAnchor, half: 'left' | 'right'): FloatAnchor =>\n `${a.startsWith('top-') ? 'top' : 'bottom'}-${half}` as FloatAnchor;\nconst withBlockHalf = (a: FloatAnchor, half: 'top' | 'bottom'): FloatAnchor =>\n `${half}-${a.endsWith('-right') ? 'right' : 'left'}` as FloatAnchor;\n\nconst ANCHORS: readonly FloatAnchor[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/**\n * Configuration for a window spawned imperatively via `usePanelFloatingWindowManager().open()`.\n * @see usePanelFloatingWindowManager\n */\nexport interface ManagedWindowConfig {\n /** Text shown in the window's header bar. */\n title: string;\n /** Optional icon shown to the left of the title in the header. */\n icon?: React.ReactNode;\n /** Window body content. */\n content: React.ReactNode;\n /** Corner of the panel to dock to on first render. @default 'top-right' */\n anchor?: FloatAnchor;\n /** Initial width in pixels. */\n width?: number;\n /** Initial height in pixels. */\n height?: number;\n /**\n * Which axes span the panel instead of carrying a fixed size. `width`/`height` above still apply\n * to any axis that isn't spanning, and are what a spanning axis returns to when released.\n * @see Stretch\n */\n stretch?: Stretch;\n}\n\n// ─── Internal contexts ────────────────────────────────────────────────────────\n\ninterface PanelToolbarCtx {\n registerToolbar(pos: ToolbarPosition, size: number): () => void;\n insetTop: number;\n insetBottom: number;\n}\nconst PanelToolbarContext = createContext<PanelToolbarCtx | null>(null);\n\ninterface PanelManagerCtx {\n managedWindowIds: string[];\n openManaged(id: string, config: ManagedWindowConfig): void;\n closeManaged(id: string): void;\n closeAllManaged(): void;\n}\nconst PanelManagerContext = createContext<PanelManagerCtx | null>(null);\n\ninterface PanelOverlayCtx {\n topId: string | null;\n zOrders: Record<string, number>;\n focusWindow(id: string): void;\n containerRef: React.RefObject<HTMLDivElement>;\n stacks: Record<FloatAnchor, string[]>;\n dockedSizes: Record<string, number>;\n dockWindow(id: string, anchor: FloatAnchor, stretch?: Stretch | null): void;\n undockWindow(id: string): void;\n reportDockedSize(id: string, size: number): void;\n draggingId: string | null;\n setDraggingId(id: string | null): void;\n hoveredZone: FloatAnchor | null;\n setHoveredZone(zone: FloatAnchor | null): void;\n /** Block-axis space claimed by `PanelToolbar`s on the top/bottom edges. */\n insetTop: number;\n insetBottom: number;\n /**\n * Inline-axis space claimed by `PanelToolbar`s on the `left`/`right` edges. Logical, matching\n * how `PanelToolbar` positions itself (`insetInlineStart`/`insetInlineEnd`), so `left` means\n * inline-start regardless of direction. `registerToolbar` has always recorded these; they simply\n * weren't surfaced, so nothing could keep clear of a side toolbar the way the block axis does.\n */\n insetInlineStart: number;\n insetInlineEnd: number;\n}\nconst PanelOverlayContext = createContext<PanelOverlayCtx | null>(null);\n\n// ─── Helper ───────────────────────────────────────────────────────────────────\n\nconst DROP_ZONE_SIZE = 80;\n\nfunction getHoveredZone(container: HTMLElement, clientX: number, clientY: number): FloatAnchor | null {\n const rect = container.getBoundingClientRect();\n const x = clientX - rect.left;\n const y = clientY - rect.top;\n if (x < DROP_ZONE_SIZE && y < DROP_ZONE_SIZE) return 'top-left';\n if (x > rect.width - DROP_ZONE_SIZE && y < DROP_ZONE_SIZE) return 'top-right';\n if (x < DROP_ZONE_SIZE && y > rect.height - DROP_ZONE_SIZE) return 'bottom-left';\n if (x > rect.width - DROP_ZONE_SIZE && y > rect.height - DROP_ZONE_SIZE) return 'bottom-right';\n return null;\n}\n\n// ─── PanelOverlayRoot ─────────────────────────────────────────────────────────\n\n/** Props for `<PanelOverlayRoot>`. */\nexport interface PanelOverlayRootProps {\n children: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Context provider and layout root for the Panel Overlay system. Wrap your panel content\n * with this to enable `PanelToolbar`, `PanelFloatingWindow`, and `usePanelFloatingWindowManager`.\n * @example\n * function MyPanel() {\n * return (\n * <PanelOverlayRoot style={{ position: 'relative', width: '100%', height: '100%' }}>\n * <PanelToolbar position=\"top\">...</PanelToolbar>\n * <div className=\"panel-body\">content</div>\n * </PanelOverlayRoot>\n * );\n * }\n */\nexport function PanelOverlayRoot({ children, className, style }: PanelOverlayRootProps): React.ReactElement {\n const [toolbarSizes, setToolbarSizes] = useState<Partial<Record<ToolbarPosition, number>>>({});\n const [zOrders, setZOrders] = useState<Record<string, number>>({});\n const [stacks, setStacks] = useState<Record<FloatAnchor, string[]>>({\n 'top-left': [], 'top-right': [], 'bottom-left': [], 'bottom-right': [],\n });\n const [dockedSizes, setDockedSizes] = useState<Record<string, number>>({});\n const [draggingId, setDraggingId] = useState<string | null>(null);\n const [hoveredZone, setHoveredZone] = useState<FloatAnchor | null>(null);\n const [topId, setTopId] = useState<string | null>(null);\n const [managedWindows, setManagedWindows] = useState<Map<string, ManagedWindowConfig>>(() => new Map());\n const zCounterRef = useRef(100);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const registerToolbar = useCallback((pos: ToolbarPosition, size: number): (() => void) => {\n setToolbarSizes(prev => ({ ...prev, [pos]: size }));\n return () => setToolbarSizes(prev => {\n const next = { ...prev };\n delete next[pos];\n return next;\n });\n }, []);\n\n const focusWindow = useCallback((id: string): void => {\n zCounterRef.current += 1;\n const z = zCounterRef.current;\n setZOrders(prev => ({ ...prev, [id]: z }));\n setTopId(id);\n }, []);\n\n const dockWindow = useCallback((id: string, anchor: FloatAnchor, stretch: Stretch | null = null): void => {\n const buckets = bucketsFor(anchor, stretch);\n setStacks(prev => {\n const next: Record<FloatAnchor, string[]> = {\n 'top-left': prev['top-left'].filter(x => x !== id),\n 'top-right': prev['top-right'].filter(x => x !== id),\n 'bottom-left': prev['bottom-left'].filter(x => x !== id),\n 'bottom-right': prev['bottom-right'].filter(x => x !== id),\n };\n for (const bucket of buckets) next[bucket] = [...next[bucket], id];\n // Re-registering identical membership would allocate fresh arrays on every placement effect\n // and churn every consumer of `stacks`, so bail out when nothing actually moved.\n const unchanged = ANCHORS.every(a =>\n next[a].length === prev[a].length && next[a].every((x, i) => x === prev[a][i]));\n return unchanged ? prev : next;\n });\n }, []);\n\n const undockWindow = useCallback((id: string): void => {\n setStacks(prev => ({\n 'top-left': prev['top-left'].filter(x => x !== id),\n 'top-right': prev['top-right'].filter(x => x !== id),\n 'bottom-left': prev['bottom-left'].filter(x => x !== id),\n 'bottom-right': prev['bottom-right'].filter(x => x !== id),\n }));\n }, []);\n\n const reportDockedSize = useCallback((id: string, size: number): void => {\n setDockedSizes(prev => {\n if (prev[id] === size) return prev;\n return { ...prev, [id]: size };\n });\n }, []);\n\n const openManaged = useCallback((id: string, config: ManagedWindowConfig): void => {\n setManagedWindows(prev => {\n const next = new Map(prev);\n next.set(id, config);\n return next;\n });\n }, []);\n\n const closeManaged = useCallback((id: string): void => {\n setManagedWindows(prev => {\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n const closeAllManaged = useCallback((): void => {\n setManagedWindows(new Map());\n }, []);\n\n const managedWindowIds = useMemo(() => Array.from(managedWindows.keys()), [managedWindows]);\n\n const toolbarCtxValue = useMemo<PanelToolbarCtx>(() => ({\n registerToolbar,\n insetTop: toolbarSizes.top ?? 0,\n insetBottom: toolbarSizes.bottom ?? 0,\n }), [registerToolbar, toolbarSizes]);\n\n const managerCtxValue = useMemo<PanelManagerCtx>(() => ({\n managedWindowIds,\n openManaged,\n closeManaged,\n closeAllManaged,\n }), [managedWindowIds, openManaged, closeManaged, closeAllManaged]);\n\n const coreCtxValue = useMemo<PanelOverlayCtx>(() => ({\n topId,\n zOrders,\n focusWindow,\n containerRef: containerRef as React.RefObject<HTMLDivElement>,\n stacks,\n dockedSizes,\n dockWindow,\n undockWindow,\n reportDockedSize,\n draggingId,\n setDraggingId,\n hoveredZone,\n setHoveredZone,\n insetTop: toolbarSizes.top ?? 0,\n insetBottom: toolbarSizes.bottom ?? 0,\n insetInlineStart: toolbarSizes.left ?? 0,\n insetInlineEnd: toolbarSizes.right ?? 0,\n }), [topId, zOrders, focusWindow, stacks, dockedSizes, dockWindow, undockWindow,\n reportDockedSize, draggingId, hoveredZone, toolbarSizes]);\n\n return (\n <PanelToolbarContext.Provider value={toolbarCtxValue}>\n <PanelManagerContext.Provider value={managerCtxValue}>\n <PanelOverlayContext.Provider value={coreCtxValue}>\n <div\n ref={containerRef}\n className={`rdd-panel-overlay-root${draggingId !== null ? ' rdd-dragging-active' : ''}${className ? ' ' + className : ''}`}\n style={style}\n >\n {children}\n {draggingId !== null && <DropZoneOverlay hoveredZone={hoveredZone} />}\n {Array.from(managedWindows.entries()).map(([id, cfg]) => (\n <PanelFloatingWindow\n key={id}\n id={id}\n title={cfg.title}\n icon={cfg.icon}\n open={true}\n onClose={() => closeManaged(id)}\n defaultAnchor={cfg.anchor ?? 'top-right'}\n defaultWidth={cfg.width ?? 320}\n defaultHeight={cfg.height ?? 240}\n defaultStretch={cfg.stretch}\n >\n {cfg.content}\n </PanelFloatingWindow>\n ))}\n </div>\n </PanelOverlayContext.Provider>\n </PanelManagerContext.Provider>\n </PanelToolbarContext.Provider>\n );\n}\n\n// ─── Internal: DropZoneOverlay ────────────────────────────────────────────────\n\nfunction DropZoneOverlay({ hoveredZone }: { hoveredZone: FloatAnchor | null }): React.ReactElement {\n return (\n <>\n {ANCHORS.map(zone => (\n <div\n key={zone}\n className={`rdd-panel-float-dropzone rdd-panel-float-dropzone--${zone}${hoveredZone === zone ? ' rdd-panel-float-dropzone--hovered' : ''}`}\n aria-hidden=\"true\"\n />\n ))}\n </>\n );\n}\n\n// ─── PanelToolbar ─────────────────────────────────────────────────────────────\n\n/** Background style of a `PanelToolbar`. */\nexport type ToolbarVariant = 'transparent' | 'frosted' | 'solid';\n\n/** Visual style applied to `ToolbarButton` and `ToolbarToggle` components. */\nexport type ButtonVariant = 'ghost' | 'soft' | 'outlined' | 'filled';\n\n/** Props for `<PanelToolbar>`. */\nexport interface PanelToolbarProps {\n /** Edge of the panel overlay to attach to. @see ToolbarPosition */\n position: ToolbarPosition;\n /** Background style of the toolbar strip. @default 'transparent' */\n variant?: ToolbarVariant;\n /** Default button style inherited by `ToolbarButton` and `ToolbarToggle` children. @default 'ghost' */\n buttonVariant?: ButtonVariant;\n /** Icon size in pixels for all buttons in this toolbar. Falls back to CSS default when unset. */\n buttonSize?: number;\n style?: React.CSSProperties;\n className?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Toolbar strip that attaches to any edge of a `PanelOverlayRoot`.\n * Left/right toolbars inset automatically to avoid overlapping top/bottom toolbars.\n * RTL layouts are detected and handled automatically.\n * @example\n * <PanelToolbar position=\"top\" variant=\"frosted\">\n * <ToolbarButton icon={<SaveIcon />} title=\"Save\" onClick={save} />\n * <ToolbarToggle icon={<GridIcon />} title=\"Grid\" active={grid} onToggle={() => setGrid(v => !v)} />\n * </PanelToolbar>\n */\nexport function PanelToolbar({ position, variant = 'transparent', buttonVariant = 'ghost', buttonSize, style, className, children }: PanelToolbarProps): React.ReactElement {\n const ctx = useContext(PanelToolbarContext);\n const ref = useRef<HTMLDivElement>(null);\n const cleanupRef = useRef<(() => void) | null>(null);\n\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el) return;\n if (!ctx) return;\n const measure = () => {\n const size = (position === 'top' || position === 'bottom') ? el.offsetHeight : el.offsetWidth;\n cleanupRef.current?.();\n cleanupRef.current = ctx.registerToolbar(position, size);\n };\n measure();\n // A one-shot measurement is correct for a live mount (already at final size), but during a\n // layout restore (loadLayout()/initialState) the panel's DOM isn't necessarily settled yet at\n // this exact instant — without re-measuring, a wrong size (often 0) is baked in permanently,\n // and every docked float ends up positioned at the toolbar's own y/x, covering it. This also\n // catches any later size change (button wrapping, a buttonSize/variant change, content change).\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => {\n ro.disconnect();\n cleanupRef.current?.();\n cleanupRef.current = null;\n };\n // ctx?.registerToolbar is a stable useCallback — depending on ctx directly\n // would re-run on every toolbarSizes update, causing an infinite loop.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [position, ctx?.registerToolbar]);\n\n const posStyle: React.CSSProperties = { position: 'absolute', zIndex: 5, pointerEvents: 'none', boxSizing: 'border-box' };\n\n if (position === 'top') {\n posStyle.top = 0; posStyle.left = 0; posStyle.right = 0;\n } else if (position === 'bottom') {\n posStyle.bottom = 0; posStyle.left = 0; posStyle.right = 0;\n } else if (position === 'left') {\n posStyle.insetInlineStart = 0;\n posStyle.top = ctx?.insetTop ?? 0;\n posStyle.bottom = ctx?.insetBottom ?? 0;\n } else {\n posStyle.insetInlineEnd = 0;\n posStyle.top = ctx?.insetTop ?? 0;\n posStyle.bottom = ctx?.insetBottom ?? 0;\n }\n\n const isSide = position === 'left' || position === 'right';\n const sideStyle: React.CSSProperties = isSide ? {\n ...(ctx?.insetTop ?? 0) > 0 ? { paddingTop: 0 } : {},\n ...(ctx?.insetBottom ?? 0) > 0 ? { paddingBottom: 0 } : {},\n } : {};\n\n const sizeStyle: React.CSSProperties = buttonSize != null\n ? { ['--rdd-panel-toolbar-btn-size' as string]: `${buttonSize}px` }\n : {};\n\n return (\n <div\n ref={ref}\n className={`rdd-panel-toolbar rdd-panel-toolbar--${position}${className ? ' ' + className : ''}`}\n data-variant={variant}\n data-btn-variant={buttonVariant}\n style={{ ...posStyle, ...sideStyle, ...sizeStyle, ...style }}\n >\n {children}\n </div>\n );\n}\n\n// ─── ToolbarButton ────────────────────────────────────────────────────────────\n\n/** Props for `<ToolbarButton>`. */\nexport interface ToolbarButtonProps {\n /** Button icon — typically a small SVG component. */\n icon: React.ReactNode;\n /** Click handler. */\n onClick(): void;\n disabled?: boolean;\n /** Tooltip text and accessible `aria-label`. */\n title?: string;\n /** Visual style override. Falls back to the parent `PanelToolbar`'s `buttonVariant`. */\n variant?: ButtonVariant;\n}\n\n/** Icon button for use inside a `PanelToolbar`. */\nexport function ToolbarButton({ icon, onClick, disabled, title, variant }: ToolbarButtonProps): React.ReactElement {\n return (\n <button\n type=\"button\"\n className=\"rdd-panel-toolbar-btn\"\n onClick={onClick}\n disabled={disabled}\n title={title}\n aria-label={title}\n {...(variant ? { 'data-variant': variant } : {})}\n >\n {icon}\n </button>\n );\n}\n\n// ─── ToolbarToggle ────────────────────────────────────────────────────────────\n\n/** Props for `<ToolbarToggle>`. */\nexport interface ToolbarToggleProps {\n /** Button icon — typically a small SVG component. */\n icon: React.ReactNode;\n /** Whether the toggle is in the active/pressed state. Sets `aria-pressed` automatically. */\n active: boolean;\n /** Called when the button is clicked. Toggle `active` in response. */\n onToggle(): void;\n disabled?: boolean;\n /** Tooltip text and accessible `aria-label`. */\n title?: string;\n /** Visual style override. Falls back to the parent `PanelToolbar`'s `buttonVariant`. */\n variant?: ButtonVariant;\n}\n\n/** Two-state icon toggle button for use inside a `PanelToolbar`. Sets `aria-pressed` automatically. */\nexport function ToolbarToggle({ icon, active, onToggle, disabled, title, variant }: ToolbarToggleProps): React.ReactElement {\n return (\n <button\n type=\"button\"\n className={`rdd-panel-toolbar-btn${active ? ' rdd-panel-toolbar-btn--active' : ''}`}\n onClick={onToggle}\n disabled={disabled}\n title={title}\n aria-label={title}\n aria-pressed={active}\n {...(variant ? { 'data-variant': variant } : {})}\n >\n {icon}\n </button>\n );\n}\n\n// ─── ToolbarSeparator ─────────────────────────────────────────────────────────\n\n/** Vertical (or horizontal) divider line between groups of toolbar items. */\nexport function ToolbarSeparator(): React.ReactElement {\n return <span className=\"rdd-panel-toolbar__sep\" aria-hidden=\"true\" />;\n}\n\n// ─── ToolbarSpacer ────────────────────────────────────────────────────────────\n\n/** Flex-grow spacer that pushes subsequent toolbar items to the far edge. */\nexport function ToolbarSpacer(): React.ReactElement {\n return <span className=\"rdd-panel-toolbar__spacer\" aria-hidden=\"true\" />;\n}\n\n// ─── ToolbarItem (custom control wrapper) ────────────────────────────────────\n\n/** Wrapper for a custom non-button control (e.g. a dropdown or input) inside a `PanelToolbar`. */\nexport function ToolbarItem({ children }: { children: React.ReactNode }): React.ReactElement {\n return <span className=\"rdd-panel-toolbar__item\">{children}</span>;\n}\n\n// ─── ToolbarCenter ────────────────────────────────────────────────────────────\n\n/** Centers its children within the toolbar using absolute positioning. */\nexport function ToolbarCenter({ children }: { children: React.ReactNode }): React.ReactElement {\n return <div className=\"rdd-panel-toolbar__center\">{children}</div>;\n}\n\n// ─── ToolbarSearchInput ───────────────────────────────────────────────────────\n\n/** A single result item returned by `ToolbarSearchInputProps.onSearch`. */\nexport interface SearchResult {\n /** Unique identifier for this result — passed to `onSelect`. */\n id: string;\n /** Primary display text. */\n label: string;\n /** Optional secondary text shown below the label in the dropdown. */\n description?: string;\n /** Optional group header used to bucket results visually. */\n group?: string;\n /** Optional icon shown to the left of the label. */\n icon?: React.ReactNode;\n}\n\n/** Props for `<ToolbarSearchInput>`. */\nexport interface ToolbarSearchInputProps {\n /** Placeholder text shown in the expanded input field. @default 'Search…' */\n placeholder?: string;\n /**\n * Called with the current query and an `AbortSignal` each time the input changes (debounced).\n * Return `SearchResult[]` directly for synchronous sources, or `Promise<SearchResult[]>` for async.\n * Abort in-flight requests when the signal fires to prevent stale result races.\n */\n onSearch(query: string, signal: AbortSignal): Promise<SearchResult[]> | SearchResult[];\n /** Called when the user selects a result from the dropdown. */\n onSelect(result: SearchResult): void;\n}\n\n/**\n * Debounced async search field for use inside a `PanelToolbar`.\n * Renders as a compact icon button that expands into a text input on activation.\n * Results appear in a portal-rendered dropdown below the input.\n * @example\n * <ToolbarSearchInput\n * placeholder=\"Find layer…\"\n * onSearch={(q, signal) => fetchLayers(q, { signal })}\n * onSelect={result => workspace.focusLayer(result.id)}\n * />\n */\nexport function ToolbarSearchInput({ placeholder = 'Search…', onSearch, onSelect }: ToolbarSearchInputProps): React.ReactElement {\n const [expanded, setExpanded] = useState(false);\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResult[]>([]);\n const [dropdownPos, setDropdownPos] = useState<{ top: number; left: number; width: number } | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const abortRef = useRef<AbortController | null>(null);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const openSearch = (): void => {\n setExpanded(true);\n setTimeout(() => inputRef.current?.focus({ preventScroll: true }), 0);\n };\n\n const closeSearch = (): void => {\n setExpanded(false);\n setQuery('');\n setResults([]);\n setDropdownPos(null);\n abortRef.current?.abort();\n if (debounceRef.current) clearTimeout(debounceRef.current);\n };\n\n const handleQueryChange = (e: React.ChangeEvent<HTMLInputElement>): void => {\n const q = e.target.value;\n setQuery(q);\n abortRef.current?.abort();\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (!q.trim()) { setResults([]); setDropdownPos(null); return; }\n\n debounceRef.current = setTimeout(async () => {\n const ctrl = new AbortController();\n abortRef.current = ctrl;\n try {\n const res = await onSearch(q, ctrl.signal);\n if (!ctrl.signal.aborted) {\n setResults(res);\n const el = containerRef.current;\n if (el && res.length > 0) {\n const r = el.getBoundingClientRect();\n const dropW = Math.max(r.width, 240);\n let left = r.left;\n if (left + dropW > window.innerWidth - 8) left = window.innerWidth - dropW - 8;\n setDropdownPos({ top: r.bottom + 4, left, width: dropW });\n } else {\n setDropdownPos(null);\n }\n }\n } catch {\n // AbortError or user-thrown — ignore\n }\n }, 300);\n };\n\n const handleSelect = (result: SearchResult): void => {\n onSelect(result);\n closeSearch();\n };\n\n const handleBlur = (e: React.FocusEvent): void => {\n if (!containerRef.current?.contains(e.relatedTarget as Node)) {\n closeSearch();\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent): void => {\n if (e.key === 'Escape') closeSearch();\n };\n\n const grouped = useMemo((): Record<string, SearchResult[]> => {\n const map: Record<string, SearchResult[]> = {};\n for (const r of results) {\n const g = r.group ?? '';\n if (!map[g]) map[g] = [];\n map[g].push(r);\n }\n return map;\n }, [results]);\n\n const SearchIcon = (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"6.5\" cy=\"6.5\" r=\"4.5\" />\n <line x1=\"10\" y1=\"10\" x2=\"14\" y2=\"14\" />\n </svg>\n );\n\n if (!expanded) {\n return (\n <div ref={containerRef} className=\"rdd-panel-toolbar-search\">\n <button type=\"button\" className=\"rdd-panel-toolbar-btn\" onClick={openSearch} title=\"Search\" aria-label=\"Search\">\n {SearchIcon}\n </button>\n </div>\n );\n }\n\n return (\n <div ref={containerRef} className=\"rdd-panel-toolbar-search rdd-panel-toolbar-search--open\" onBlur={handleBlur}>\n <button type=\"button\" className=\"rdd-panel-toolbar-btn\" onClick={closeSearch} aria-label=\"Close search\" title=\"Close search\">\n {SearchIcon}\n </button>\n <input\n ref={inputRef}\n className=\"rdd-panel-toolbar-search__input\"\n type=\"text\"\n value={query}\n onChange={handleQueryChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n autoComplete=\"off\"\n />\n {dropdownPos && results.length > 0 && createPortal(\n <div\n className=\"rdd-panel-toolbar-search__dropdown\"\n // z-index from .rdd-panel-toolbar-search__dropdown (+8502), not inline, so\n // zIndexBase shifts it too. Resolves to the same 9502 by default.\n style={{ position: 'fixed', top: dropdownPos.top, left: dropdownPos.left, width: dropdownPos.width }}\n onMouseDown={e => e.preventDefault()}\n >\n {Object.entries(grouped).map(([group, items]) => (\n <React.Fragment key={group || '__default__'}>\n {group && <div className=\"rdd-panel-toolbar-search__group\">{group}</div>}\n {items.map(item => (\n <button\n key={item.id}\n type=\"button\"\n className=\"rdd-panel-toolbar-search__item\"\n onClick={() => handleSelect(item)}\n >\n {item.icon && <span className=\"rdd-panel-toolbar-search__item-icon\">{item.icon}</span>}\n <span className=\"rdd-panel-toolbar-search__item-label\">{item.label}</span>\n {item.description && <span className=\"rdd-panel-toolbar-search__item-desc\">{item.description}</span>}\n </button>\n ))}\n </React.Fragment>\n ))}\n </div>,\n document.body,\n )}\n </div>\n );\n}\n\n// ─── PanelFloatingWindow ──────────────────────────────────────────────────────\n\n/** Props for `<PanelFloatingWindow>`. */\nexport interface PanelFloatingWindowProps {\n /** Unique identifier within the panel overlay. Used for z-order and stack tracking. */\n id: string;\n /** Text shown in the window's header bar. */\n title: string;\n /** Optional icon shown to the left of the title in the header. */\n icon?: React.ReactNode;\n /** Whether the window is mounted and visible. Set to `false` to close/unmount it. */\n open: boolean;\n /** Called when the user clicks the × button. Set `open` to `false` in response. */\n onClose(): void;\n /** Corner of the panel to dock to on first render. @see FloatAnchor */\n defaultAnchor: FloatAnchor;\n /** Initial width in pixels. Ignored on an axis that starts stretched, and restored to when that\n * axis is later released. */\n defaultWidth: number;\n /** Initial height in pixels. Ignored on an axis that starts stretched, and restored to when that\n * axis is later released. */\n defaultHeight: number;\n /**\n * Which axes span the panel on first render. Uncontrolled: gestures update it from here.\n * @see Stretch\n */\n defaultStretch?: Stretch;\n /**\n * Controlled stretch state. When provided — **including as `null`** — the caller is the single\n * source of truth: gestures report through {@link PanelFloatingWindowProps.onPlacementChange}\n * instead of updating internally, and the caller must echo the new value back. Omit entirely\n * (`undefined`) for uncontrolled behaviour, matching `ToolbarToggleItem.active` and\n * `Sidebar.activeTabId`.\n */\n stretch?: Stretch | null;\n /**\n * Called whenever a gesture changes where the widget sits — a stretched axis released, a\n * re-dock, or a detach. Reports anchor and stretch **together**, because one gesture can change\n * both at once and reporting them separately would surface a state that is never valid.\n *\n * This is also the only way to persist placement: the library serialises nothing about inner\n * widgets, so store what you receive here and feed it back via `defaultAnchor`/`stretch`.\n */\n onPlacementChange?: (placement: PanelFloatPlacement) => void;\n /**\n * Whether this widget may span the panel at all. `false` disables resize-to-stretch snapping,\n * for content that only makes sense at a bounded size. Default `true`.\n */\n stretchable?: boolean;\n children?: React.ReactNode;\n}\n\n/**\n * Declarative floating window anchored inside a `PanelOverlayRoot`.\n *\n * Docks to any corner, drags free of it, and drops back onto one. Windows sharing a corner stack\n * along the block axis with animated offsets. An axis can also **span the panel** instead of\n * carrying a fixed size, so the window tracks the panel as it resizes — see\n * {@link PanelFloatingWindowProps.defaultStretch} and {@link Stretch}.\n *\n * Resize handles follow what is actually movable: a free-floating window is pinned by nothing and\n * offers all eight, while a docked one offers only its free edges — plus both ends of any spanning\n * axis, either of which releases it.\n *\n * @example\n * const info = usePanelFloatingWindow();\n * <PanelFloatingWindow\n * id=\"layer-info\" title=\"Layer Info\"\n * open={info.isOpen} onClose={info.close}\n * defaultAnchor=\"top-right\" defaultWidth={300} defaultHeight={200}\n * >\n * <LayerInfoContent />\n * </PanelFloatingWindow>\n *\n * @example\n * // A full-width status strip along the bottom, tracking the panel's width.\n * // defaultHeight still applies; defaultWidth is what the inline axis returns to if released.\n * <PanelFloatingWindow\n * id=\"timeline\" title=\"Timeline\"\n * open onClose={close}\n * defaultAnchor=\"bottom-left\" defaultStretch=\"width\"\n * defaultWidth={240} defaultHeight={120}\n * >\n * <TimelineContent />\n * </PanelFloatingWindow>\n */\nexport function PanelFloatingWindow(props: PanelFloatingWindowProps): React.ReactElement | null {\n const ctx = useContext(PanelOverlayContext);\n if (!props.open) return null;\n return <FloatingWindowBody key={props.id} ctx={ctx} {...props} />;\n}\n\n// ─── Internal: FloatingWindowBody ─────────────────────────────────────────────\n\ninterface FloatingWindowBodyProps extends PanelFloatingWindowProps {\n ctx: PanelOverlayCtx | null;\n}\n\ntype WindowMode = 'docked' | 'free';\n\nconst MIN_W = 120;\nconst MIN_H = 60;\nconst DOCK_INSET = 8;\nconst DOCK_GAP = 8;\n/**\n * Resize-to-stretch snapping. Asymmetric on purpose: arming within `SNAP_IN` of the full extent\n * but only disarming once the drag pulls back past the wider `SNAP_OUT`. Without that hysteresis,\n * releasing a stretched axis by dragging a few pixels inward would immediately re-arm and snap\n * straight back on release, which makes the gesture feel broken.\n */\nconst SNAP_IN = 16;\nconst SNAP_OUT = 40;\n\nfunction FloatingWindowBody({ id, title, icon, defaultAnchor, defaultWidth, defaultHeight, defaultStretch, stretch: stretchProp, onPlacementChange, stretchable = true, children, ctx, onClose }: FloatingWindowBodyProps): React.ReactElement {\n const isRtl = useContext(WindowStateContext)?.isRtl ?? false;\n const [mode, setMode] = useState<WindowMode>('docked');\n const [currentAnchor, setCurrentAnchor] = useState<FloatAnchor>(defaultAnchor);\n // `size` is deliberately left untouched while an axis is stretched — the render branch below\n // simply stops reading it, exactly as a maximized workspace window keeps its x/y/w/h. Releasing\n // the axis therefore restores the previous size with no snapshot and no bookkeeping.\n const [internalStretch, setInternalStretch] = useState<Stretch | null>(defaultStretch ?? null);\n // Controlled when the prop is present at all — `null` is a meaningful value (\"not stretched\"),\n // so only `undefined` means \"manage it yourself\".\n const isStretchControlled = stretchProp !== undefined;\n const stretch = isStretchControlled ? (stretchProp ?? null) : internalStretch;\n const [freePos, setFreePos] = useState<{ x: number; y: number } | null>(null);\n const [size, setSize] = useState({ w: defaultWidth, h: defaultHeight });\n const windowRef = useRef<HTMLDivElement>(null);\n\n // Refs to avoid stale closures in pointer handlers\n const modeRef = useRef(mode);\n modeRef.current = mode;\n const freePosRef = useRef(freePos);\n freePosRef.current = freePos;\n const sizeRef = useRef(size);\n sizeRef.current = size;\n const stretchRef = useRef(stretch);\n stretchRef.current = stretch;\n const currentAnchorRef = useRef(currentAnchor);\n currentAnchorRef.current = currentAnchor;\n const onPlacementChangeRef = useRef(onPlacementChange);\n onPlacementChangeRef.current = onPlacementChange;\n /** Which axes would snap to stretched if the drag were released now — drives the visual cue. */\n const [snapArmed, setSnapArmed] = useState<{ inline: boolean; block: boolean }>({ inline: false, block: false });\n const snapArmedRef = useRef(snapArmed);\n snapArmedRef.current = snapArmed;\n /** The block extent available to this widget depends on what it is stacked behind. */\n const stackOffsetRef = useRef(0);\n\n /**\n * The single write path for placement. Anchor is always internal; stretch is internal only when\n * uncontrolled. Either way the pair is reported once, so a listener never observes a half-applied\n * transition.\n */\n const applyPlacement = useCallback((anchor: FloatAnchor, next: Stretch | null): void => {\n setCurrentAnchor(anchor);\n if (!isStretchControlled) setInternalStretch(next);\n onPlacementChangeRef.current?.({ anchor, stretch: next });\n }, [isStretchControlled]);\n\n const dragState = useRef<{ mouseX: number; mouseY: number; posX: number; posY: number; hasDragged: boolean } | null>(null);\n\n // Bucket membership depends on the whole placement (see bucketsFor), so this re-runs whenever\n // the anchor or a stretched axis changes — not only on mount. Free-floating widgets are in no\n // stack at all.\n useLayoutEffect(() => {\n if (mode !== 'docked') return;\n ctx?.dockWindow(id, currentAnchor, stretch);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mode, currentAnchor, stretch]);\n\n // Leave the stack on unmount (close). Closing resets to the defaults on the next open, since a\n // fresh mount means fresh state.\n useLayoutEffect(() => () => { ctx?.undockWindow(id); },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []);\n\n // Dev-only: a block-stretched widget spans the whole block axis, so it cannot stack with\n // anything — it will simply overlap siblings on its own inline side, with z-order deciding.\n // Warns once per widget, matching the warning conventions in Sidebar/WindowManager.\n const blockStretchWarnedRef = useRef(false);\n useEffect(() => {\n if (process.env.NODE_ENV !== 'development') return;\n if (blockStretchWarnedRef.current) return;\n if (mode !== 'docked' || !stretchesBlock(stretch) || !ctx) return;\n const half = currentAnchor.endsWith('-right') ? 'right' : 'left';\n const neighbours = ([`top-${half}`, `bottom-${half}`] as FloatAnchor[])\n .flatMap(bucket => ctx.stacks[bucket] ?? [])\n .filter(other => other !== id);\n if (neighbours.length === 0) return;\n blockStretchWarnedRef.current = true;\n console.warn(\n `[react-dockable-desktop] PanelFloatingWindow \"${id}\" stretches the block axis ` +\n `(stretch: \"${stretch}\") while ${neighbours.length} other widget(s) are anchored to the ` +\n `same side (${neighbours.join(', ')}). A block-stretched widget spans the axis that stacking ` +\n `uses to separate siblings, so it cannot stack and will overlap them — z-order decides which ` +\n `is on top. Either give it a fixed height, or move the other widgets to the opposite side.`\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mode, stretch, currentAnchor, ctx?.stacks, id]);\n\n // Report height whenever size changes so stack peers can compute their offset.\n useEffect(() => {\n ctx?.reportDockedSize(id, size.h);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [size.h]);\n\n const zOrder = ctx?.zOrders[id] ?? 101;\n\n const isActive = !ctx || ctx.topId === id;\n\n const getContainerBounds = (): { cw: number; ch: number } => {\n const container = windowRef.current?.offsetParent as HTMLElement | null;\n return { cw: container?.clientWidth ?? 9999, ch: container?.clientHeight ?? 9999 };\n };\n\n /**\n * The band a docked widget is allowed to occupy, in physical pixels from the container's edges.\n *\n * The block axis keeps clear of top/bottom `PanelToolbar`s only; the inline axis also adds the\n * `DOCK_INSET` gutter, matching how a docked widget is already positioned (one inline inset of\n * `DOCK_INSET`, one block inset of the toolbar size). Growth previously stopped at the raw\n * container edge, so a docked widget could be resized straight over the toolbar on the far side —\n * which the library elsewhere treats as a bug (a 5.x fix stopped docked floats *positioning*\n * themselves over a toolbar; the resize path never got the same treatment).\n *\n * Inline is converted from logical to physical here because handle directions and measured rects\n * are physical, while `PanelToolbar` claims its space logically.\n */\n const dockedBand = (): { left: number; right: number; top: number; bottom: number } => {\n const logicalStart = ctx?.insetInlineStart ?? 0;\n const logicalEnd = ctx?.insetInlineEnd ?? 0;\n return {\n left: (isRtl ? logicalEnd : logicalStart) + DOCK_INSET,\n right: (isRtl ? logicalStart : logicalEnd) + DOCK_INSET,\n top: ctx?.insetTop ?? 0,\n bottom: ctx?.insetBottom ?? 0,\n };\n };\n\n const handleWindowPointerDown = (): void => {\n ctx?.focusWindow(id);\n };\n\n const handleHeaderPointerDown = (e: React.PointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return;\n e.preventDefault();\n\n let startX: number;\n let startY: number;\n\n if (modeRef.current === 'docked') {\n // Snapshot the rendered position so that *if* this becomes a real drag, switching to free\n // positioning causes no visual jump. Undocking itself is deferred to the drag threshold\n // below — doing it here meant a plain click on the header silently tore the widget off its\n // anchor: it looked unchanged, but its stacked siblings reflowed to close the gap and it\n // stopped tracking the corner on every later panel resize.\n const el = windowRef.current;\n const container = ctx?.containerRef?.current;\n if (el && container) {\n const elRect = el.getBoundingClientRect();\n const cRect = container.getBoundingClientRect();\n startX = elRect.left - cRect.left;\n startY = elRect.top - cRect.top;\n } else {\n startX = DOCK_INSET;\n startY = ctx?.insetTop ?? 0;\n }\n } else {\n startX = freePosRef.current?.x ?? 0;\n startY = freePosRef.current?.y ?? 0;\n }\n\n dragState.current = { mouseX: e.clientX, mouseY: e.clientY, posX: startX, posY: startY, hasDragged: false };\n windowRef.current?.setPointerCapture(e.pointerId);\n };\n\n const handleResizePointerDown = (dir: ResizeDir) => (e: React.PointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n // Snapshot current rendered position for offset-from-edge calculations\n let startX = 0, startY = 0;\n if (modeRef.current === 'free') {\n startX = freePosRef.current?.x ?? 0;\n startY = freePosRef.current?.y ?? 0;\n } else {\n const el = windowRef.current;\n const container = el?.offsetParent as HTMLElement | null;\n if (el && container) {\n const er = el.getBoundingClientRect();\n const cr = container.getBoundingClientRect();\n startX = er.left - cr.left;\n startY = er.top - cr.top;\n }\n }\n // For a stretched axis the stored size is stale by design (the render branch stops reading it),\n // so the drag has to start from the *measured* extent or the widget would jump.\n const measured = windowRef.current?.getBoundingClientRect();\n const startRect = {\n x: startX,\n y: startY,\n w: stretchesInline(stretchRef.current) && measured ? measured.width : sizeRef.current.w,\n h: stretchesBlock(stretchRef.current) && measured ? measured.height : sizeRef.current.h,\n };\n\n // Dragging an end of a stretched axis releases that axis: the edge under the pointer becomes\n // the moving one and the opposite end becomes the new pin, so it reads exactly like an ordinary\n // resize. Done once per drag; `released` guards against repeat moves before the re-render.\n const dragsInline = dir.includes('e') || dir.includes('w');\n const dragsBlock = dir.includes('n') || dir.includes('s');\n let released = false;\n let armed = { inline: false, block: false };\n const releaseIfNeeded = (): void => {\n if (released || modeRef.current !== 'docked') return;\n const st = stretchRef.current;\n const releasingInline = dragsInline && stretchesInline(st);\n const releasingBlock = dragsBlock && stretchesBlock(st);\n if (!releasingInline && !releasingBlock) return;\n released = true;\n\n let next = st;\n let nextAnchor = currentAnchorRef.current;\n if (releasingInline) {\n next = releaseAxis(next, 'inline');\n // Pin the end opposite the dragged edge. Handle dirs are physical, anchors are logical.\n const pinsPhysicalLeft = dir.includes('e');\n nextAnchor = withInlineHalf(nextAnchor, (pinsPhysicalLeft !== isRtl) ? 'left' : 'right');\n }\n if (releasingBlock) {\n next = releaseAxis(next, 'block');\n nextAnchor = withBlockHalf(nextAnchor, dir.includes('s') ? 'top' : 'bottom');\n }\n applyPlacement(nextAnchor, next);\n };\n\n startPointerDrag({\n element: e.currentTarget,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => startRect,\n activeClasses: [{ el: document.body, classes: ['rdd-resizing-active'] }],\n onMove: (dx, dy, start) => {\n // Re-measured every move, matching the original's live re-measurement —\n // the container can in principle change size during a drag.\n const { cw, ch } = getContainerBounds();\n // Docked widgets stop at the toolbar band; free-floating ones stay unconstrained beyond the\n // container itself, since \"free\" means free.\n const band = modeRef.current === 'docked'\n ? dockedBand()\n : { left: 0, right: 0, top: 0, bottom: 0 };\n const { x: newX, y: newY, w: newW, h: newH } = computeResizedRect(dir, dx, dy, start, {\n minW: MIN_W, minH: MIN_H,\n maxW: (cw - band.right) - start.x, maxH: (ch - band.bottom) - start.y,\n minX: band.left, minY: band.top,\n });\n releaseIfNeeded();\n\n // ── resize-to-stretch snapping ──\n // The clamps above already stop growth exactly where a stretched axis would sit, so an\n // armed drag is already visually at its target; the cue is an outline rather than a ghost.\n if (modeRef.current === 'docked' && stretchable) {\n const fullInline = cw - band.left - band.right;\n const fullBlock = ch - band.top - band.bottom - stackOffsetRef.current;\n const st = stretchRef.current;\n const nextArmed = { ...armed };\n if (dragsInline && !stretchesInline(st)) {\n if (newW >= fullInline - SNAP_IN) nextArmed.inline = true;\n else if (armed.inline && newW < fullInline - SNAP_OUT) nextArmed.inline = false;\n }\n if (dragsBlock && !stretchesBlock(st)) {\n if (newH >= fullBlock - SNAP_IN) nextArmed.block = true;\n else if (armed.block && newH < fullBlock - SNAP_OUT) nextArmed.block = false;\n }\n if (nextArmed.inline !== armed.inline || nextArmed.block !== armed.block) {\n armed = nextArmed;\n setSnapArmed(nextArmed);\n }\n }\n // Only write an axis that carries a size. A still-stretched axis must keep its stored\n // value, so releasing it later restores the size it had before stretching.\n const st = released ? releaseAxis(releaseAxis(stretchRef.current,\n dragsInline ? 'inline' : 'block'), dragsBlock ? 'block' : 'inline') : stretchRef.current;\n setSize(prev => ({\n w: stretchesInline(st) ? prev.w : newW,\n h: stretchesBlock(st) ? prev.h : newH,\n }));\n if (modeRef.current === 'free') {\n setFreePos({ x: newX, y: newY });\n }\n },\n onEnd: (start) => {\n if (!armed.inline && !armed.block) {\n if (snapArmedRef.current.inline || snapArmedRef.current.block) {\n setSnapArmed({ inline: false, block: false });\n }\n return;\n }\n // Restore the size the axis had *before* this drag: while an axis is stretched its stored\n // size is what releasing it later returns to, so it should be the size the user last chose\n // deliberately — not the full-bleed value the drag happened to pass through.\n setSize(prev => ({\n w: armed.inline ? start.w : prev.w,\n h: armed.block ? start.h : prev.h,\n }));\n let next = stretchRef.current;\n if (armed.inline) next = addAxis(next, 'inline');\n if (armed.block) next = addAxis(next, 'block');\n applyPlacement(currentAnchorRef.current, next);\n setSnapArmed({ inline: false, block: false });\n },\n });\n };\n\n const handleWindowPointerMove = (e: React.PointerEvent): void => {\n if (dragState.current) {\n const ds = dragState.current;\n if (!ds.hasDragged) {\n const dist = Math.abs(e.clientX - ds.mouseX) + Math.abs(e.clientY - ds.mouseY);\n if (dist < 4) return;\n ds.hasDragged = true;\n // This, not pointerdown, is the moment the widget leaves its anchor.\n if (modeRef.current === 'docked') {\n // A stretched axis carries no size, so free mode — which positions from an explicit box —\n // would otherwise snap back to whatever the size was before stretching. Materialise what\n // is actually on screen, then clear stretch: \"free\" and \"spanning the panel\" are\n // mutually exclusive.\n if (stretchRef.current) {\n const r = windowRef.current?.getBoundingClientRect();\n if (r) setSize({ w: Math.round(r.width), h: Math.round(r.height) });\n applyPlacement(currentAnchorRef.current, null);\n }\n ctx?.undockWindow(id);\n setMode('free');\n }\n document.body.classList.add('rdd-dragging-active');\n ctx?.setDraggingId(id);\n }\n const { cw, ch } = getContainerBounds();\n const newX = Math.max(0, Math.min(ds.posX + e.clientX - ds.mouseX, cw - sizeRef.current.w));\n const newY = Math.max(0, Math.min(ds.posY + e.clientY - ds.mouseY, ch - sizeRef.current.h));\n setFreePos({ x: newX, y: newY });\n\n const container = ctx?.containerRef?.current;\n if (container) {\n const rawZone = getHoveredZone(container, e.clientX, e.clientY);\n ctx?.setHoveredZone(rawZone && isRtl ? flipZoneHorizontal(rawZone) : rawZone);\n }\n }\n };\n\n const handleWindowPointerUp = (): void => {\n if (dragState.current?.hasDragged) {\n const zone = ctx?.hoveredZone;\n if (zone) {\n ctx?.dockWindow(id, zone, stretchRef.current);\n setMode('docked');\n setFreePos(null);\n applyPlacement(zone, stretchRef.current);\n }\n ctx?.setHoveredZone(null);\n ctx?.setDraggingId(null);\n }\n document.body.classList.remove('rdd-dragging-active');\n dragState.current = null;\n };\n\n const handleWindowPointerCancel = (): void => {\n if (dragState.current?.hasDragged) {\n ctx?.setHoveredZone(null);\n ctx?.setDraggingId(null);\n }\n document.body.classList.remove('rdd-dragging-active');\n dragState.current = null;\n };\n\n // ── Compute position style ─────────────────────────────────────────────────\n let windowStyle: React.CSSProperties;\n\n if (mode === 'docked' && ctx) {\n // Offset is the largest offset across every bucket this widget occupies, so a strip spanning\n // an edge clears whatever is stacked in *both* of that edge's corners.\n const buckets = bucketsFor(currentAnchor, stretch);\n let stackOffset = 0;\n // A widget with no buckets (block-stretched) is never \"in\" a stack, so it must not be held\n // invisible by the not-yet-registered guard below.\n let registered = buckets.length === 0;\n for (const bucket of buckets) {\n const stack = ctx.stacks[bucket] ?? [];\n const idx = stack.indexOf(id);\n if (idx === -1) continue;\n registered = true;\n let offset = 0;\n for (let i = 0; i < idx; i++) {\n offset += (ctx.dockedSizes[stack[i]] ?? defaultHeight) + DOCK_GAP;\n }\n stackOffset = Math.max(stackOffset, offset);\n }\n stackOffsetRef.current = stackOffset;\n\n const band = dockedBand();\n\n windowStyle = {\n zIndex: zOrder,\n transition: 'top 0.2s ease, bottom 0.2s ease',\n // Hide until registered in stack (first layout effect hasn't run yet)\n opacity: registered ? undefined : 0,\n pointerEvents: registered ? undefined : 'none',\n };\n\n // Inline axis: one inset plus an explicit width, or both insets and no width at all. Setting\n // both ends is the whole mechanism — CSS then keeps the widget spanning the panel for free.\n if (stretchesInline(stretch)) {\n windowStyle.insetInlineStart = (ctx.insetInlineStart ?? 0) + DOCK_INSET;\n windowStyle.insetInlineEnd = (ctx.insetInlineEnd ?? 0) + DOCK_INSET;\n } else {\n windowStyle[currentAnchor.endsWith('-right') ? 'insetInlineEnd' : 'insetInlineStart'] = DOCK_INSET;\n windowStyle.width = size.w;\n }\n\n // Block axis: same idea. Note the block insets carry no DOCK_INSET gutter, matching how a\n // docked widget has always been positioned against a top/bottom toolbar (flush, not inset).\n if (stretchesBlock(stretch)) {\n windowStyle.top = band.top;\n windowStyle.bottom = band.bottom;\n } else if (currentAnchor.startsWith('top-')) {\n windowStyle.top = band.top + stackOffset;\n windowStyle.height = size.h;\n } else {\n windowStyle.bottom = band.bottom + stackOffset;\n windowStyle.height = size.h;\n }\n } else {\n windowStyle = {\n left: freePos?.x ?? 0,\n top: freePos?.y ?? 0,\n width: size.w,\n height: size.h,\n zIndex: zOrder,\n };\n }\n\n // ── Which resize handles this window offers ────────────────────────────────\n // Free-floating: all eight, nothing is pinned.\n //\n // Docked: only the edges that can actually move. A docked window has one edge pinned per axis\n // (see the positioning block above — `top-*` pins `top`, `bottom-*` pins `bottom`, `*-left`\n // pins `insetInlineStart`, `*-right` pins `insetInlineEnd`), so dragging a handle on a pinned\n // side moves the *opposite* edge instead of the one under the cursor, and can't move it further\n // than that side's own inset before `computeResizedRect`'s bounds stop it — an inert stub with a\n // resize cursor on it. The handle set used to be hardcoded to the five non-northern directions\n // regardless of anchor, which made that harmless-looking for top anchors but left every\n // bottom-anchored window with no working vertical resize at all: `n` wasn't rendered, and `s`\n // was the stub.\n //\n // Restricting docked mode to free edges also means the existing resize bounds are already\n // correct for every direction that remains: `maxW`/`maxH` apply only to eastward/southward\n // growth (where the top-left origin genuinely is pinned), while `minX`/`minY` bound the moving\n // edge for westward/northward growth — so no change to the resize math is needed.\n const handleDirs: ResizeDir[] = React.useMemo(() => {\n if (mode === 'free') return ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'];\n\n // Block axis is direction-agnostic; the inline axis is not. The pin is a logical property\n // (`insetInlineEnd`) but the handle classes are physical (`.rdd-resize-e { right: -4px }`), so\n // which *physical* side is pinned depends on the window's own `dir`.\n const freeBlock: ResizeDir = currentAnchor.startsWith('top-') ? 's' : 'n';\n const pinsPhysicalRight = currentAnchor.endsWith('-right') !== isRtl;\n const freeInline: ResizeDir = pinsPhysicalRight ? 'w' : 'e';\n\n const inlineStretched = stretchesInline(stretch);\n const blockStretched = stretchesBlock(stretch);\n\n // A stretched axis has both ends pinned, but both are *releasable*: dragging either end moves\n // that edge and pins the opposite one, so the widget leaves stretch at the width the drag\n // produced. Hence handles on both ends — which is also what keeps the fully-stretched state\n // from being a dead end with nothing to grab.\n const dirs: ResizeDir[] = [];\n dirs.push(...(inlineStretched ? (['e', 'w'] as ResizeDir[]) : [freeInline]));\n dirs.push(...(blockStretched ? (['n', 's'] as ResizeDir[]) : [freeBlock]));\n // The corner belongs only to the all-pinned state; in a stretched state it would mix a resize\n // and a release into one gesture.\n if (!inlineStretched && !blockStretched) dirs.push(`${freeBlock}${freeInline}` as ResizeDir);\n return dirs;\n }, [mode, currentAnchor, isRtl, stretch]);\n\n const CloseIcon = (\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\">\n <line x1=\"1\" y1=\"1\" x2=\"9\" y2=\"9\" />\n <line x1=\"9\" y1=\"1\" x2=\"1\" y2=\"9\" />\n </svg>\n );\n\n return (\n <div\n ref={windowRef}\n dir={isRtl ? 'rtl' : 'ltr'}\n className={[\n 'rdd-panel-float',\n isActive ? 'rdd-panel-float--active' : '',\n snapArmed.inline || snapArmed.block ? 'rdd-panel-float--snapping' : '',\n ].filter(Boolean).join(' ')}\n style={windowStyle}\n onPointerDown={handleWindowPointerDown}\n onPointerMove={handleWindowPointerMove}\n onPointerUp={handleWindowPointerUp}\n onPointerCancel={handleWindowPointerCancel}\n >\n <div className=\"rdd-panel-float__header\" onPointerDown={handleHeaderPointerDown}>\n {icon && <span className=\"rdd-panel-float__icon\">{icon}</span>}\n <span className=\"rdd-panel-float__title\">{title}</span>\n <button\n type=\"button\"\n className=\"rdd-panel-float__close\"\n onClick={onClose}\n onPointerDown={e => e.stopPropagation()}\n title=\"Close\"\n aria-label=\"Close\"\n >\n {CloseIcon}\n </button>\n </div>\n <div className=\"rdd-panel-float__body\">{children}</div>\n {handleDirs.map(dir => (\n <div\n key={dir}\n className={`rdd-resize-handle rdd-resize-${dir}`}\n onPointerDown={handleResizePointerDown(dir)}\n />\n ))}\n </div>\n );\n}\n\n// ─── usePanelFloatingWindow ───────────────────────────────────────────────────\n\n/** Return type of `usePanelFloatingWindow`. @see usePanelFloatingWindow */\nexport interface UsePanelFloatingWindowReturn {\n /** Whether the floating window is currently open. */\n isOpen: boolean;\n /** Open the floating window. */\n open(): void;\n /** Close the floating window. */\n close(): void;\n}\n\n/**\n * Manages the open/close boolean state for a single `PanelFloatingWindow`.\n * Pass `isOpen` to `open`, `close` to `onClose` on the component directly.\n * @returns A stable `UsePanelFloatingWindowReturn` object.\n * @example\n * const info = usePanelFloatingWindow();\n * <PanelFloatingWindow id=\"info\" open={info.isOpen} onClose={info.close} ... />\n */\nexport function usePanelFloatingWindow(): UsePanelFloatingWindowReturn {\n const [isOpen, setIsOpen] = useState(false);\n const open = useCallback((): void => { setIsOpen(true); }, []);\n const close = useCallback((): void => { setIsOpen(false); }, []);\n return { isOpen, open, close };\n}\n\n// ─── usePanelFloatingWindowManager ───────────────────────────────────────────\n\nconst EMPTY_IDS: string[] = [];\n\n/**\n * Imperative handle returned by `usePanelFloatingWindowManager`.\n * @see usePanelFloatingWindowManager\n */\nexport interface PanelFloatingWindowManagerHandle {\n /** Spawn or reconfigure a named window. Safe to call with an already-open ID to update config. */\n open(id: string, config: ManagedWindowConfig): void;\n /** Close a named window by ID. No-op if the window is not open. */\n close(id: string): void;\n /** Close all managed windows. */\n closeAll(): void;\n /** Returns `true` if the named window is currently open. */\n isOpen(id: string): boolean;\n /** IDs of all currently open managed windows. Changes to this array trigger re-renders. */\n openIds: string[];\n}\n\n/**\n * Imperative hook for spawning N named floating windows at runtime from data or event handlers.\n * All windows share z-ordering, drag, and corner-docking infrastructure of the `PanelOverlayRoot`,\n * and accept the same placement options — including {@link ManagedWindowConfig.stretch} to span an\n * axis of the panel.\n *\n * Must be called inside a **descendant** of `PanelOverlayRoot`, not in the component that renders the root.\n * @returns A stable `PanelFloatingWindowManagerHandle`.\n * @example\n * const manager = usePanelFloatingWindowManager();\n * manager.open('feature-42', { title: 'Feature 42', content: <FeatureDetail id={42} />, anchor: 'top-right' });\n *\n * // A full-width strip along the bottom edge:\n * manager.open('timeline', { title: 'Timeline', content: <Timeline />, anchor: 'bottom-left', stretch: 'width', height: 120 });\n */\nexport function usePanelFloatingWindowManager(): PanelFloatingWindowManagerHandle {\n const ctx = useContext(PanelManagerContext);\n const ids = ctx?.managedWindowIds ?? EMPTY_IDS;\n\n return useMemo(() => ({\n open: (id: string, config: ManagedWindowConfig) => ctx?.openManaged(id, config),\n close: (id: string) => ctx?.closeManaged(id),\n closeAll: () => ctx?.closeAllManaged(),\n isOpen: (id: string) => ids.includes(id),\n openIds: ids,\n }), [ctx, ids]);\n}\n"],"mappings":"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","names":["React","useState","useRef","useEffect","useCallback","useContext","createPortal","createContext","useContext","useState","useRef","useMemo","useCallback","useEffect","useSyncExternalStore","createContext","useContext","useSyncExternalStore","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","usePanelSize","onResize","getDimensions","onStoreChange","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","isValidElement","isSerializable","value","type","proto","jsx","WindowStateContext","createContext","WindowActionsContext","WindowI18nContext","WindowStoreSyncContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","useContext","RegistryContext","PanelRegistry","useRegistry","PanelEventBus","event","callback","cb","data","EMPTY_LEAF","isVisibleActiveTarget","id","scope","info","w","isLeafSelection","node","deriveActivePanelId","isCandidate","fromLeaves","child","found","selected","frontmost","parseLayoutPayload","parsed","floating","fw","anchor","_sr","_sb","rest","persisted","activePanelId","parseInitialState","json","payload","WindowManagerProvider","children","client","formatMessage","predefinedMessages","dirProp","modalClass","modalBodyClass","sidePanelClass","sidePanelBodyClass","windowClass","windowBodyClass","zIndexBaseProp","registry","useRef","effectiveFormatMessage","effectivePredefinedMessages","effectiveDir","effectiveZIndexBase","state","setState","useState","stateRef","stateSubscribersRef","useEffect","getSnapshot","useCallback","subscribeToState","closeGuardsRef","stateProvidersRef","mergedMessages","useMemo","eventBusRef","maxZRef","subscribe","publish","getCascadedPosition","fav","currentFloating","x","y","width","height","isOverlapping","pos","wx","wy","attempts","viewW","viewH","focusPanel","prev","panel","win","alreadyTop","selectActiveInTree","removePanelFromTree","idx","panels","p","updatedLeaf","c","sizes","sum","a","b","s","addPanelToLeaf","leafId","panelId","findFirstLeafId","openPanel","component","options","resolvedId","match","isNew","isRedirect","shouldFocus","serializable","isSerializable","exists","entry","title","target","favPos","nextMinimized","m","cascaded","firstLeaf","newPanelInfo","nextPanels","closePanel","nextRoot","nextFloating","nextActivePanelId","registerCloseGuard","guard","unregisterCloseGuard","registerStateProvider","provider","unregisterStateProvider","setPanelDirty","dirty","updatePanelTitle","requestClosePanel","minimizePanel","wasActive","lastFloatingRect","lastLeafId","findLeafForPanel","res","restorePanel","wasMinimized","leafExists","targetId","parentLeafExists","canDrag","targetLeafId","floatPanel","rect","cleanRoot","dockPanel","splitLeafInTree","position","splitRatio","newLeaf","orientation","setDraggedPanelId","dockPanelToGroup","newRoot","dockPanelToWorkspaceEdge","r","movePanelOrder","targetIndex","insertInLeaf","remaining","index","newPanels","closeLeafGroup","removeLeafFromTree","maximizePanel","updateSplitSizes","path","updateInTree","depth","i","updateFloatingPosition","updates","saveLayout","currentPanels","excludedIds","includedPanels","dynamicValue","hasDynamicValue","effectiveProps","effectiveSerializable","gridRoot","minimized","liveActive","loadLayout","layoutJson","e","setActivePanel","setDirection","dir","isOpen","getOpenPanelIds","findPanelId","dedupeKey","customMenuGettersRef","showContextMenuFnRef","registerContextMenuFn","fn","showContextMenu","registerPanelContextMenu","getItems","getPanelContextMenuItems","actions","defaultFormatMessage","msg","text","key","value","styleClasses","syncContextValue","noopSubscribe","_cb","useWindowManagerState","selector","stateCtx","syncCtx","selectorRef","syncResult","useSyncExternalStore","snap","useWindowManagerActions","ctx","useWindowManagerActionsInternal","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","usePanelId","useFormContainer","usePanelContextMenu","items","itemsRef","React","forwardRef","useImperativeHandle","useState","useRef","useEffect","useLayoutEffect","createPortal","Fragment","jsx","jsxs","getCoords","event","resolveLabel","label","fmt","isSeparator","item","isSubMenu","SubMenuPanel","items","x","y","theme","onClose","onMouseEnter","onMouseLeave","ref","el","r","PAD","i","simple","showChk","isChecked","isDisabled","CLOSED","ContextMenu","formatMessageProvider","onShow","onHide","onOpenChange","className","style","menuState","setMenuState","submenuIndex","setSubmenuIndex","menuRef","submenuPanelRef","itemRefs","timers","close","coords","dismiss","e","onKey","submenuX","submenuY","itemEl","ir","cancelOpenTimer","cancelCloseTimer","handleItemMouseEnter","index","handleItemMouseLeave","sub","DefaultContextMenuAdapter","ContextMenuContext","ContextMenuProvider","adapter","children","componentProps","isOpen","setIsOpen","show","opts","useShowContextMenu","ctx","createContext","useContext","useState","useCallback","useMemo","useRef","jsx","idCounter","generateId","closeHandlers","initialState","PanelStateContext","PanelActionsContext","PanelProvider","children","state","setState","stateRef","registerCloseHandler","id","handler","unregisterCloseHandler","openLeftPanel","Component","props","options","currentPanel","instance","s","openRightPanel","openModal","formTitle","modalOptions","close","m","closeAll","closeAllModals","getInstance","updateInstance","updates","setDirty","dirty","actions","usePanelState","ctx","usePanelActions","useEffect","useRef","jsx","jsxs","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","useRef","useEffect","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","flipZoneHorizontal","zone","startPointerDrag","config","element","pointerId","startClientX","startClientY","captureStart","onMove","onEnd","activeClasses","el","classes","start","handleMove","e","handleEnd","computeResizedRect","dir","dx","dy","constraints","minW","minH","maxW","maxH","minX","minY","x","y","w","h","maxDx","minDx","clampedDx","maxDy","minDy","clampedDy","useEffect","useState","useColorScheme","scheme","setScheme","updateScheme","observer","Fragment","jsx","jsxs","findLeaf","node","leafId","child","found","domCache","hiddenContainerId","DefaultGridIcon","ContextMenuIcons","getOrCreateDomCacheElement","id","el","renderPanelContent","panel","registry","componentKey","registryEntry","Component","activePanelDimensions","panelLifecycleRegistry","getOrCreateLifecycleRegistry","panelId","entry","PreservedDOMWrapper","hostRef","useRef","useEffect","host","cachedEl","resizeObserver","entries","width","height","lifecycle","h","hiddenContainer","PreviewDOMWrapper","state","useWindowManagerState","useRegistry","formatMessage","useFormatMessage","regEntry","disableLivePreview","lastSize","origW","origH","scale","displayW","displayH","rawTitle","title","formatLabel","initialChar","FormContainerProviderWrapper","children","requestClosePanel","setPanelDirty","registerCloseGuard","unregisterCloseGuard","registerStateProvider","unregisterStateProvider","updatePanelTitle","minimizePanel","useWindowManagerActions","isMin","prevMinRef","isActive","prevActiveRef","wasActive","rawPanelState","derivedContainerType","prevContainerTypeRef","prevType","initialContainerTypeRef","contract","React","options","dirty","handler","getState","reg","FormContainerProvider","WorkspaceGrid","path","onTabRightClick","activeDropZone","onHoverDropZone","onTabDragStart","hoveredTab","onTabHover","defaultPanelIcon","onRequestClosePanel","updateSplitSizes","LeafGroup","isRow","handleResizerPointerDown","idx","e","resizerEl","parentEl","parentSize","startPointerDrag","dx","dy","startSizes","deltaPercentage","newSizes","size","leaf","openPanel","closeLeafGroup","setActivePanel","useWindowManagerActionsInternal","messages","usePredefinedMessages","windowClass","windowBodyClass","useStyleClasses","tabContainerRef","tabScroll","setTabScroll","useState","updateTabScroll","useCallback","ro","scrollTabs","dir","selectTab","isSelected","isGloballyActive","isHovered","isLast","isHoveredEmpty","sideClass","tabFocusClass","rect","side","pos","pct","rem","WindowManager","skin","taskbarVisibility","contextMenuAdapter","DefaultContextMenuAdapter","animations","restorePanel","maximizePanel","updateFloatingPosition","focusPanel","floatPanel","setDraggedPanelId","dockPanelToGroup","movePanelOrder","dockPanelToWorkspaceEdge","getPanelContextMenuItems","showContextMenu","registerContextMenuFn","openModal","usePanelActions","handleRequestClose","customOpts","resolve","opts","baseTitle","ConfirmationForm_default","ctxMenu","useContext","ContextMenuContext","contextMenuRef","taskbarRef","taskbarExpanded","setTaskbarExpanded","taskbarCollapseTimerRef","prevMinimizedLengthRef","hoveredMinimized","setHoveredMinimized","minimizedTooltipTimeoutRef","lastTaskbarPointerTypeRef","internalContextMenuOpen","setInternalContextMenuOpen","isContextMenuOpen","m","setActiveDropZone","activeDropZoneRef","dragPos","setDragPos","activeEdgeDrop","setActiveEdgeDropState","activeEdgeDropRef","setActiveEdgeDrop","val","activeCornerAnchor","setActiveCornerAnchorState","activeCornerAnchorRef","setActiveCornerAnchor","isRtl","WindowStateContext","setHoveredTab","hoveredTabRef","handleTabHover","index","handleHoverDropZone","position","updateHoverFromPoint","x","elements","foundDropZone","foundEdge","foundTab","tabIdx","LONG_PRESS_MS","CANCEL_MOVE_PX","clearDragState","flipRtl","executeDrop","me","dropZone","targetTab","edgeDrop","cornerAnchor","targetIndex","targetLeaf","currentIdx","flipZoneHorizontal","handleTabDragStart","startX","startY","pointerId","cancelled","cancel","timer","onPreMove","dragStarted","onMove","onEnd","onCancel","handleTabRightClick","items","custom","finalItems","handleMinimizedRightClick","keys","cachedId","handleWindowBlur","workspaceRef","workspaceSize","setWorkspaceSize","heightWarnShown","observer","culprit","cursor","tag","cls","who","viewW","viewH","w","winW","winH","winX","winY","newWidth","newHeight","newX","newY","changed","maxX","maxY","handlePointerDownGlobal","target","windowEl","winId","panelEl","startDrag","floatingWin","startPosX","startPosY","executeFWDrop","startResize","startRect","parsedX","parsedY","parsedW","parsedH","isRightSnapped","isBottomSnapped","start","resized","computeResizedRect","newW","newH","scrollTaskbar","direction","amount","expandTaskbar","scheduleCollapseTaskbar","currentColorScheme","useColorScheme","corner","isMaximized","isDragged","isFocused","w_","h_","stack","fw","stackOffset","i","sh","isTop","customItems","icon","onShortTap","createPortal","tooltipId","targetEl","WindowManager_default","WorkspaceClient","config","PanelRegistryClass","id","def","actions","entry","pending","fn","event","cb","idx","args","a","component","dedupeKey","json","dir","path","sizes","updates","targetLeafId","position","panelId","targetIndex","leafId","guard","provider","dirty","options","title","data","callback","d","useContext","createContext","useContext","useMemo","useState","jsx","ToolbarContext","ToolbarProvider","children","radioGroups","setRadioGroups","modifiers","setModifiers","value","group","id","prev","active","useToolbar","ctx","createContext","useCallback","useContext","useLayoutEffect","useMemo","useRef","useSyncExternalStore","jsx","createPanelContributionStore","contributions","listeners","notify","l","panelId","contribution","listener","PanelContributionContext","createContext","PanelContributionProvider","children","store","useMemo","usePanelContribution","usePanelId","useContext","cleanupRef","useRef","useLayoutEffect","useActivePanelContribution","activePanelId","useWindowManagerState","s","subscribe","useCallback","onChange","getSnapshot","useSyncExternalStore","sidebarSectionToTab","section","fallbackIcon","useMergedToolbarItems","staticItems","active","useMergedSidebarTabs","staticTabs","jsx","DockableDesktopProvider","contextMenuAdapter","DefaultContextMenuAdapter","props","existingCtxMenu","useContext","ContextMenuContext","inner","ToolbarProvider","WindowManagerProvider","PanelContributionProvider","PanelProvider","ContextMenuProvider","useCallback","useRef","useEffect","useState","useMemo","Fragment","jsx","jsxs","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","sizeClass","showCloseButton","bodyPadding","bodyPaddingStyle","useEffect","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","useCallback","useRef","useEffect","useState","useMemo","useLayoutEffect","useState","useContainerRect","anchorRef","rect","setRect","container","measure","r","resizeObserver","Fragment","jsx","jsxs","SidePanelRendererItem","panel","position","defaultWidth","containerRect","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","canClose","useEffect","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","handleKeyDown","e","width","widthStyle","bodyPadding","bodyPaddingStyle","FormContainerProvider","SidePanelAnchor","children","anchorRef","useContainerRect","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","React","useState","useEffect","useRef","useCallback","useImperativeHandle","useContext","useMemo","createContext","forwardRef","memo","jsx","jsxs","isRailTab","entry","isRailCustom","toRailArray","value","SidebarContext","createContext","SidebarTabContext","SidebarTabProvider","tabId","onClose","onOpen","setActiveTabId","children","useMemo","otherId","renderRailEntry","index","activeTabId","onTabClick","React","isActive","SidebarTabStrip","memo","tabs","headerEntries","footerEntries","isVisible","position","i","tab","SidebarResizeHandle","currentWidth","minWidth","maxWidth","onWidthChange","onResizeStart","onResizeEnd","e","el","activeClasses","startPointerDrag","dx","_dy","startWidth","newW","Sidebar","forwardRef","headerAction","footerAction","defaultWidth","controlledActiveTabId","onActiveTabChange","visible","onVisibilityChange","stripVisible","onStripVisibilityChange","showCloseButton","hideDefaultHeader","renderHeader","isSecondary","ref","isControlled","width","setWidthState","useState","setWidth","useCallback","px","isResizing","setIsResizing","internalActiveTabId","setInternalActiveTabId","normalizedHeaderEntries","normalizedFooterEntries","headerTabs","footerTabs","allTabs","mountedTabIds","setMountedTabIds","effectiveMountedTabIds","result","activeTabIdRef","useRef","useEffect","widthRef","id","prev","next","changed","t","useImperativeHandle","handleTabClick","handleClose","hasHeaderOverride","closeButtonWarnedRef","sidebarContextValue","isSidebarVisible","isStripVisible","isDrawerOpen","drawer","isCurrent","resizeHandle","SecondarySidebar","props","primary","useContext","opposite","useSidebar","ctx","useSidebarTab","forwardRef","useImperativeHandle","useState","useRef","useEffect","useLayoutEffect","createPortal","Fragment","jsx","jsxs","flyoutPosition","rect","position","isRtl","gap","ToolbarGroupButton","item","toolbar","isOpen","setIsOpen","useState","btnRect","setBtnRect","btnRef","useRef","flyoutRef","isControlled","activeId","activeSubItem","e","isActive","displayIcon","displayLabel","handleClick","prev","useLayoutEffect","el","r","PAD","useEffect","onMouseDown","target","onKey","createPortal","entry","i","isSubActive","renderItem","index","controlled","Toolbar","forwardRef","items","visible","onVisibilityChange","className","style","ref","useToolbar","isVertical","useImperativeHandle","collapseStyle","useCallback","useEffect","useLayoutEffect","useRef","useState","createPortal","jsx","jsxs","ToastEmitter","fn","message","opts","id","patch","e","emitter","toast","msg","promise","messages","result","err","InfoIcon","SuccessIcon","WarningIcon","ErrorIcon","CloseIcon","DEFAULT_ICONS","ToastItem","options","exiting","isLeft","showProgress","pauseOnHover","animation","onDismiss","onExited","divRef","bodyRef","timerRef","remainRef","startRef","paused","setPaused","startEntry","entryClass","setEntryClass","el","body","applyHeight","observer","raf","scheduleDismiss","ms","handle","fallback","handleMouseEnter","handleMouseLeave","cls","icon","resolveOpts","raw","defaultDuration","defaultClosable","ToastContainer","position","maxVisible","newestOnTop","progressBar","width","adapter","toasts","setToasts","queueRef","toastsRef","handleDismiss","prev","t","handleExited","promoted","filtered","newEntry","rawEntry","q","merged","AdapterContainer","dirMod","React","useState","useContext","createContext","useRef","useLayoutEffect","useCallback","useMemo","useEffect","createPortal","Fragment","jsx","jsxs","stretchesInline","s","stretchesBlock","addAxis","axis","releaseAxis","bucketsFor","anchor","stretch","withInlineHalf","a","half","withBlockHalf","ANCHORS","PanelToolbarContext","createContext","PanelManagerContext","PanelOverlayContext","DROP_ZONE_SIZE","getHoveredZone","container","clientX","clientY","rect","x","y","PanelOverlayRoot","children","className","style","toolbarSizes","setToolbarSizes","useState","zOrders","setZOrders","stacks","setStacks","dockedSizes","setDockedSizes","draggingId","setDraggingId","hoveredZone","setHoveredZone","topId","setTopId","managedWindows","setManagedWindows","zCounterRef","useRef","containerRef","registerToolbar","useCallback","pos","size","prev","next","focusWindow","id","z","dockWindow","buckets","bucket","i","undockWindow","reportDockedSize","openManaged","config","closeManaged","closeAllManaged","managedWindowIds","useMemo","toolbarCtxValue","managerCtxValue","coreCtxValue","DropZoneOverlay","cfg","PanelFloatingWindow","zone","PanelToolbar","position","variant","buttonVariant","buttonSize","ctx","useContext","ref","cleanupRef","useLayoutEffect","el","measure","ro","posStyle","sideStyle","sizeStyle","ToolbarButton","icon","onClick","disabled","title","ToolbarToggle","active","onToggle","ToolbarSeparator","ToolbarSpacer","ToolbarItem","ToolbarCenter","ToolbarSearchInput","placeholder","onSearch","onSelect","expanded","setExpanded","query","setQuery","results","setResults","dropdownPos","setDropdownPos","inputRef","abortRef","debounceRef","openSearch","closeSearch","handleQueryChange","e","q","ctrl","res","r","dropW","left","handleSelect","result","handleBlur","handleKeyDown","grouped","map","g","SearchIcon","createPortal","group","items","React","item","props","FloatingWindowBody","MIN_W","MIN_H","DOCK_INSET","DOCK_GAP","SNAP_IN","SNAP_OUT","defaultAnchor","defaultWidth","defaultHeight","defaultStretch","stretchProp","onPlacementChange","stretchable","onClose","isRtl","WindowStateContext","mode","setMode","currentAnchor","setCurrentAnchor","internalStretch","setInternalStretch","isStretchControlled","freePos","setFreePos","setSize","windowRef","modeRef","freePosRef","sizeRef","stretchRef","currentAnchorRef","onPlacementChangeRef","snapArmed","setSnapArmed","snapArmedRef","stackOffsetRef","applyPlacement","dragState","blockStretchWarnedRef","useEffect","neighbours","other","zOrder","isActive","getContainerBounds","dockedBand","logicalStart","logicalEnd","handleWindowPointerDown","handleHeaderPointerDown","startX","startY","elRect","cRect","handleResizePointerDown","dir","er","cr","measured","startRect","dragsInline","dragsBlock","released","armed","releaseIfNeeded","st","releasingInline","releasingBlock","nextAnchor","pinsPhysicalLeft","startPointerDrag","dx","dy","start","cw","ch","band","newX","newY","newW","newH","computeResizedRect","fullInline","fullBlock","nextArmed","handleWindowPointerMove","ds","rawZone","flipZoneHorizontal","handleWindowPointerUp","handleWindowPointerCancel","windowStyle","stackOffset","registered","stack","idx","offset","handleDirs","freeBlock","freeInline","inlineStretched","blockStretched","dirs","CloseIcon","usePanelFloatingWindow","isOpen","setIsOpen","open","close","EMPTY_IDS","usePanelFloatingWindowManager","ids"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/WindowManager.tsx","../src/components/WindowManagerContext.tsx","../src/components/FormContainerContext.ts","../src/components/PanelRegistry.ts","../src/components/predefinedMessages.ts","../src/components/serializable.ts","../src/components/ContextMenu.tsx","../src/components/PanelProviderContext.tsx","../src/forms/ConfirmationForm.tsx","../src/components/anchorGeometry.ts","../src/components/dragResize.ts","../src/hooks/useColorScheme.ts","../src/WorkspaceClient.ts","../src/components/DockableDesktopProvider.tsx","../src/components/ToolbarContext.tsx","../src/components/PanelContributionContext.tsx","../src/components/ModalStackRenderer.tsx","../src/components/SidePanelRenderer.tsx","../src/hooks/useContainerRect.ts","../src/components/Sidebar.tsx","../src/components/Toolbar.tsx","../src/components/Toast.tsx","../src/components/PanelOverlay.tsx"],"sourcesContent":["/**\n * @file WindowManager.tsx\n * @description Core component for react-dockable-desktop layout engine.\n * Renders the workspace desktop containing docked splits, tabbed panels, floated windows,\n * resize handles, context menus, and taskbar docks. Exposes lifecycle event listeners.\n */\n\nimport React, { useState, useRef, useEffect, useCallback, useContext } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useWindowManagerState, useWindowManagerActions, useWindowManagerActionsInternal, useFormatMessage, formatLabel, usePredefinedMessages, useStyleClasses, useRegistry, WindowStateContext } from './WindowManagerContext';\nimport type { LayoutNode, LayoutLeafNode, SplitDirection, DropPosition, FloatAnchor, PanelInfo } from './WindowManagerContext';\nimport type { PanelRegistryClass } from './PanelRegistry';\nimport { DefaultContextMenuAdapter, ContextMenuContext } from './ContextMenu';\nimport type { ContextMenuHandle, ContextMenuAdapter } from './ContextMenu';\nimport { FormContainerProvider } from './FormContainerContext';\nimport type { FormContainerContract, ContainerType } from './FormContainerContext';\nimport { usePanelActions } from './PanelProviderContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\nimport { flipZoneHorizontal } from './anchorGeometry';\nimport { startPointerDrag, computeResizedRect } from './dragResize';\nimport type { ResizeDir } from './dragResize';\nimport { useColorScheme } from '../hooks/useColorScheme';\n\nconst findLeaf = (node: LayoutNode | null, leafId: string): LayoutLeafNode | null => {\n if (!node) return null;\n if (node.type === 'leaf') return node.id === leafId ? node : null;\n for (const child of node.children) {\n const found = findLeaf(child, leafId);\n if (found) return found;\n }\n return null;\n};\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 ContextMenuIcons = {\n // Two offset equal rects — Windows \"restore-down / new window\" language\n float: (\n <span className=\"rdd-menu-icon\">\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=\"2\" y=\"8\" width=\"14\" height=\"14\" rx=\"1\"/>\n <rect x=\"8\" y=\"2\" width=\"14\" height=\"14\" rx=\"1\"/>\n </svg>\n </span>\n ),\n // Single horizontal dash — Windows minimize language\n minimize: (\n <span className=\"rdd-menu-icon\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" style={{ display: 'block' }}>\n <line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/>\n </svg>\n </span>\n ),\n // Single inset rect — restore to normal windowed state\n restore: (\n <span className=\"rdd-menu-icon\">\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=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1\"/>\n </svg>\n </span>\n ),\n // Near-full rect — maximize / fill workspace\n maximize: (\n <span className=\"rdd-menu-icon\">\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=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"1\"/>\n </svg>\n </span>\n ),\n // × — close\n close: (\n <span className=\"rdd-menu-icon\">\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 <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </span>\n ),\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, panel: PanelInfo, registry: PanelRegistryClass) => {\n const componentKey = panel.component;\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=\"rdd-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(--rdd-text-secondary, #94a3b8)' }}>Key: {componentKey}</span>\n </div>\n );\n }\n const Component = registryEntry.Component;\n // Props spread first, panelId second — a caller-supplied prop of the same name can never\n // shadow the injected id. Matches ModalStackRenderer/SidePanelRenderer's spread order exactly.\n return <Component {...(panel.props ?? {})} panelId={id} />;\n};\n\nconst activePanelDimensions = new Map<string, { width: number; height: number }>();\n\ninterface PanelLifecycleRegistry {\n onClose: Set<() => void>;\n onMinimize: Set<() => void>;\n onRestore: Set<() => void>;\n onResize: Set<(w: number, h: number) => void>;\n onActivate: Set<() => void>;\n onDeactivate: Set<() => void>;\n onContainerTypeChange: Set<(type: ContainerType) => void>;\n}\n\nconst panelLifecycleRegistry = new Map<string, PanelLifecycleRegistry>();\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 onActivate: new Set(),\n onDeactivate: new Set(),\n onContainerTypeChange: 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=\"rdd-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(--rdd-taskbar-item-border, rgba(255, 255, 255, 0.15))'\n }}\n >\n <div\n style={{\n fontSize: '2rem',\n fontWeight: 600,\n color: 'var(--rdd-panel-title-color, var(--rdd-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=\"rdd-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=\"rdd-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 ['--rdd-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, registerStateProvider, unregisterStateProvider, updatePanelTitle, minimizePanel } = useWindowManagerActions();\n\n // ── minimize / restore ──────────────────────────────────────────────────\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 // ── activate / deactivate ───────────────────────────────────────────────\n const isActive = state.activePanelId === panelId;\n const prevActiveRef = useRef(isActive);\n\n useEffect(() => {\n const wasActive = prevActiveRef.current;\n prevActiveRef.current = isActive; // always sync the ref, even if no handler is registered yet\n const entry = panelLifecycleRegistry.get(panelId);\n if (!entry) return;\n\n if (isActive && !wasActive) {\n entry.onActivate.forEach(h => h());\n } else if (!isActive && wasActive) {\n entry.onDeactivate.forEach(h => h());\n }\n }, [isActive, panelId]);\n\n // ── container-type change ───────────────────────────────────────────────\n const rawPanelState = state.panels[panelId]?.state;\n const derivedContainerType: ContainerType =\n rawPanelState === 'floating' ? 'floating-window' : 'dockable-panel';\n const prevContainerTypeRef = useRef(derivedContainerType);\n\n useEffect(() => {\n if (rawPanelState === 'minimized') return; // minimize/restore is onMinimize's domain; intentionally skip ref update\n const prevType = prevContainerTypeRef.current;\n prevContainerTypeRef.current = derivedContainerType; // always sync, even if no handler registered yet\n const entry = panelLifecycleRegistry.get(panelId);\n if (!entry) return;\n\n if (derivedContainerType !== prevType) {\n entry.onContainerTypeChange.forEach(h => h(derivedContainerType));\n }\n }, [derivedContainerType, rawPanelState, panelId]);\n\n // ── cleanup: fire onDeactivate (if active) then onClose ─────────────────\n useEffect(() => {\n return () => {\n const entry = panelLifecycleRegistry.get(panelId);\n if (entry) {\n if (prevActiveRef.current) entry.onDeactivate.forEach(h => h());\n entry.onClose.forEach(h => h());\n panelLifecycleRegistry.delete(panelId);\n }\n };\n }, [panelId]);\n\n // Capture the container type at mount so the static `containerType` field is\n // correct ('dockable-panel' or 'floating-window') rather than the default 'standalone'.\n const initialContainerTypeRef = useRef<ContainerType>(derivedContainerType);\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 registerStateProvider: (getState) => {\n registerStateProvider(panelId, getState);\n return () => unregisterStateProvider(panelId);\n },\n setTitle: (title) => updatePanelTitle(panelId, title),\n instanceId: panelId,\n containerType: initialContainerTypeRef.current,\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 requestMinimize: () => minimizePanel(panelId),\n getDimensions: () => activePanelDimensions.get(panelId) ?? null,\n onActivate: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onActivate.add(handler);\n return () => reg.onActivate.delete(handler);\n },\n onDeactivate: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onDeactivate.add(handler);\n return () => reg.onDeactivate.delete(handler);\n },\n onContainerTypeChange: (handler) => {\n const reg = getOrCreateLifecycleRegistry(panelId);\n reg.onContainerTypeChange.add(handler);\n return () => reg.onContainerTypeChange.delete(handler);\n },\n }), [panelId, requestClosePanel, setPanelDirty, registerCloseGuard, unregisterCloseGuard, registerStateProvider, unregisterStateProvider, updatePanelTitle, minimizePanel]);\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: DropPosition } | null;\n onHoverDropZone: (leafId: string, position: DropPosition | null) => void;\n onTabDragStart: (id: string, e: React.PointerEvent) => 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 handleResizerPointerDown = (idx: number, e: React.PointerEvent) => {\n e.preventDefault();\n const resizerEl = e.currentTarget as HTMLDivElement;\n const parentEl = resizerEl.parentElement;\n const parentSize = parentEl\n ? (isRow ? parentEl.clientWidth : parentEl.clientHeight)\n : (isRow ? 1000 : 800);\n\n startPointerDrag({\n element: resizerEl,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => [...node.sizes],\n activeClasses: [\n { el: resizerEl, classes: ['rdd-active'] },\n { el: document.body, classes: ['rdd-resizing-active', isRow ? 'rdd-resizing-col-active' : 'rdd-resizing-row-active'] },\n ],\n onMove: (dx, dy, startSizes) => {\n const deltaPercentage = (isRow ? dx : dy) / parentSize;\n const newSizes = [...startSizes];\n newSizes[idx] += deltaPercentage;\n newSizes[idx + 1] -= deltaPercentage;\n if (newSizes[idx] > 0.1 && newSizes[idx + 1] > 0.1) {\n updateSplitSizes(path, newSizes);\n }\n },\n });\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', minWidth: 0, minHeight: 0 }}>\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 onPointerDown={(e) => handleResizerPointerDown(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=\"rdd-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: DropPosition } | null;\n onHoverDropZone: (leafId: string, position: DropPosition | null) => void;\n onTabDragStart: (id: string, e: React.PointerEvent) => 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 tabContainerRef = useRef<HTMLDivElement>(null);\n const [tabScroll, setTabScroll] = useState({ left: false, right: false });\n\n const updateTabScroll = useCallback(() => {\n const el = tabContainerRef.current;\n if (!el) return;\n setTabScroll({\n left: el.scrollLeft > 0,\n right: el.scrollLeft < el.scrollWidth - el.clientWidth - 1,\n });\n }, []);\n\n useEffect(() => {\n const el = tabContainerRef.current;\n if (!el) return;\n el.addEventListener('scroll', updateTabScroll, { passive: true });\n const ro = new ResizeObserver(updateTabScroll);\n ro.observe(el);\n updateTabScroll();\n return () => { el.removeEventListener('scroll', updateTabScroll); ro.disconnect(); };\n }, [updateTabScroll]);\n\n const scrollTabs = (dir: 'left' | 'right') => {\n tabContainerRef.current?.scrollBy({ left: dir === 'left' ? -120 : 120, behavior: 'smooth' });\n };\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={`rdd-workspace-panel ${windowClass ?? ''}`}\n style={{ overflow: 'hidden', position: 'relative' }}\n >\n {/* Tab Headers */}\n <div className=\"rdd-workspace-tab-bar\" style={{ minHeight: '38px' }}>\n {tabScroll.left && (\n <button\n className=\"rdd-tab-scroll-btn rdd-tab-scroll-btn-left\"\n onPointerDown={(e) => e.stopPropagation()}\n onClick={() => scrollTabs('left')}\n tabIndex={-1}\n aria-label=\"Scroll tabs left\"\n >‹</button>\n )}\n <div\n ref={tabContainerRef}\n className=\"rdd-tab-headers-container\"\n style={{ scrollbarWidth: 'none' }}\n onPointerMove={(e) => {\n if (state.draggedPanelId && e.target === e.currentTarget) {\n onTabHover(leaf.id, 'EMPTY', leaf.panels.length, 'right');\n }\n }}\n onPointerLeave={(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' ? 'rdd-drag-hover-left' : 'rdd-drag-hover-right')\n : (isHoveredEmpty ? 'rdd-drag-hover-right' : '');\n\n const tabFocusClass = isSelected\n ? (isGloballyActive ? 'rdd-active rdd-workspace-tab-active-focused' : 'rdd-active rdd-workspace-tab-active-unfocused')\n : 'rdd-workspace-tab-inactive';\n\n return (\n <div\n key={id}\n data-tab-id={id}\n data-leaf-id={leaf.id}\n data-tab-index={String(idx)}\n onClick={() => selectTab(id)}\n onPointerDown={(e) => {\n if (options?.canDrag !== false) {\n onTabDragStart(id, e);\n }\n }}\n onContextMenu={(e) => onTabRightClick(id, e)}\n onPointerMove={(e) => {\n if (state.draggedPanelId && e.pointerType !== 'touch') {\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 onPointerLeave={() => {\n if (state.draggedPanelId) {\n onTabHover(leaf.id, '', -1, null);\n }\n }}\n className={`rdd-workspace-tab ${tabFocusClass} ${sideClass}`}\n style={{ cursor: options?.canDrag === false ? 'default' : 'pointer' }}\n >\n <span className=\"rdd-text-truncate\" style={{ maxWidth: '120px', display: 'flex', alignItems: 'center' }}>\n <span className=\"rdd-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=\"rdd-tab-header-actions\"\n onClick={(e) => e.stopPropagation()}\n onPointerDown={(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=\"rdd-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 {tabScroll.right && (\n <button\n className=\"rdd-tab-scroll-btn rdd-tab-scroll-btn-right\"\n onPointerDown={(e) => e.stopPropagation()}\n onClick={() => scrollTabs('right')}\n tabIndex={-1}\n aria-label=\"Scroll tabs right\"\n >›</button>\n )}\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=\"rdd-close-tab-x rdd-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={`rdd-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=\"rdd-empty-leaf-placeholder\">\n <span>Empty Workspace Section</span>\n </div>\n )}\n\n {/* Drag overlay targets cross */}\n {state.draggedPanelId !== null && (() => {\n // State-driven, not :hover-driven — :hover never fires reliably in Safari\n // during an active drag, and doesn't exist at all on touch. activeDropZone\n // already tracks this for mouse, pen, and touch alike (see updateHoverFromPoint).\n const isActive = (pos: DropPosition) => activeDropZone?.leafId === leaf.id && activeDropZone.position === pos;\n return (\n <div className=\"rdd-dock-drop-zone-overlay\">\n <div className=\"rdd-dock-target-cross\">\n {/* Top target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"top\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'top')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-top${isActive('top') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▲\n </div>\n {/* Bottom target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"bottom\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'bottom')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-bottom${isActive('bottom') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▼\n </div>\n {/* Left target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"left\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'left')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-left${isActive('left') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ◀\n </div>\n {/* Right target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"right\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'right')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-right${isActive('right') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▶\n </div>\n {/* Center target */}\n <div\n data-leaf-id={leaf.id}\n data-drop-zone=\"center\"\n onPointerEnter={() => onHoverDropZone(leaf.id, 'center')}\n onPointerLeave={() => onHoverDropZone(leaf.id, null)}\n className={`rdd-dock-target-box rdd-dock-target-center${isActive('center') ? ' rdd-dock-target-box--active' : ''}`}\n >\n ▣\n </div>\n </div>\n </div>\n );\n })()}\n\n {/* Visual preview highlight overlay */}\n {state.draggedPanelId !== null && activeDropZone !== null && activeDropZone.leafId === leaf.id && (\n <div\n className=\"rdd-dock-preview-highlight\"\n style={(() => {\n const pos = activeDropZone.position;\n const pct = `${state.splitRatio * 100}%`;\n const rem = `${(1 - state.splitRatio) * 100}%`;\n return {\n left: pos === 'right' ? rem : '0',\n top: pos === 'bottom' ? rem : '0',\n width: (pos === 'left' || pos === 'right') ? pct : '100%',\n height: (pos === 'top' || pos === 'bottom') ? pct : '100%',\n };\n })()}\n />\n )}\n </div>\n </div>\n );\n};\n\n\n// ==========================================\n// 5. WindowManager (Main Render Component)\n// ==========================================\n\n/** Controls when the minimized-panel taskbar is visible. */\nexport type TaskbarVisibility = 'always' | 'compact' | 'autohide';\n\n/** Props for `<WindowManager>`. */\nexport interface WindowManagerProps {\n /** Built-in skin name or a custom skin key registered via CSS. @default 'vscode' */\n skin?: string;\n /** Fallback icon shown in panel tabs when no panel-specific icon is provided. */\n defaultPanelIcon?: React.ReactNode;\n /**\n * Controls taskbar visibility.\n * - `'always'` — permanent bar at the bottom (default)\n * - `'compact'` — only visible when minimized panels exist\n * - `'autohide'` — overlay bar with 8 px peek strip\n * @default 'always'\n */\n taskbarVisibility?: TaskbarVisibility;\n /** Custom context menu renderer. Defaults to the built-in `DefaultContextMenuAdapter`. */\n contextMenuAdapter?: ContextMenuAdapter;\n /** Enables the library's own transitions/animations (tab hover, dock preview, etc.). Never affects the consumer's own page. @default true */\n animations?: boolean;\n}\n\nexport const WindowManager: React.FC<WindowManagerProps> = ({ skin = 'vscode', defaultPanelIcon, taskbarVisibility = 'autohide', contextMenuAdapter = DefaultContextMenuAdapter, animations = true }) => {\n const state = useWindowManagerState();\n const registry = useRegistry();\n const { restorePanel, minimizePanel, requestClosePanel, maximizePanel, updateFloatingPosition, focusPanel, floatPanel, setDraggedPanelId, dockPanelToGroup, movePanelOrder, dockPanelToWorkspaceEdge, setActivePanel, getPanelContextMenuItems, showContextMenu, registerContextMenuFn } = 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 ctxMenu = useContext(ContextMenuContext);\n const contextMenuRef = useRef<ContextMenuHandle>(null);\n\n useEffect(() => {\n if (ctxMenu !== null) {\n return registerContextMenuFn((opts) => ctxMenu.show(opts));\n } else {\n return registerContextMenuFn((opts) => contextMenuRef.current?.show(opts));\n }\n }, [ctxMenu, registerContextMenuFn]);\n\n const taskbarRef = useRef<HTMLDivElement | null>(null);\n const [taskbarExpanded, setTaskbarExpanded] = useState(false);\n const taskbarCollapseTimerRef = useRef<ReturnType<typeof setTimeout>>(null);\n const prevMinimizedLengthRef = useRef(state.minimized.length);\n\n const [hoveredMinimized, setHoveredMinimized] = useState<{ id: string; rect: DOMRect; title: string | any; component: string; fromTouch?: boolean } | null>(null);\n const minimizedTooltipTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);\n const lastTaskbarPointerTypeRef = useRef<string>('mouse');\n const [internalContextMenuOpen, setInternalContextMenuOpen] = useState(false);\n const isContextMenuOpen = ctxMenu !== null ? ctxMenu.isOpen : internalContextMenuOpen;\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 useEffect(() => {\n if (!hoveredMinimized?.fromTouch) return;\n const handler = (e: PointerEvent) => {\n if (e.pointerType !== 'touch') return;\n const tooltip = document.querySelector('.rdd-taskbar-item-tooltip');\n if (tooltip?.contains(e.target as Node)) return;\n setHoveredMinimized(null);\n };\n document.addEventListener('pointerdown', handler, { capture: true });\n return () => document.removeEventListener('pointerdown', handler, { capture: true });\n }, [hoveredMinimized?.fromTouch]);\n\n const [activeDropZone, setActiveDropZone] = useState<{ leafId: string; position: DropPosition } | null>(null);\n const activeDropZoneRef = useRef<{ leafId: string; position: DropPosition } | null>(null);\n const [dragPos, setDragPos] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n\n const [activeEdgeDrop, setActiveEdgeDropState] = useState<SplitDirection | null>(null);\n const activeEdgeDropRef = useRef<SplitDirection | null>(null);\n const setActiveEdgeDrop = (val: SplitDirection | null) => {\n setActiveEdgeDropState(val);\n activeEdgeDropRef.current = val;\n };\n\n const [activeCornerAnchor, setActiveCornerAnchorState] = useState<FloatAnchor | null>(null);\n const activeCornerAnchorRef = useRef<FloatAnchor | null>(null);\n const setActiveCornerAnchor = (val: FloatAnchor | null) => {\n setActiveCornerAnchorState(val);\n activeCornerAnchorRef.current = val;\n };\n\n const isRtl = useContext(WindowStateContext)?.isRtl ?? false;\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: DropPosition | null) => {\n const val = position ? { leafId, position } : null;\n setActiveDropZone(val);\n activeDropZoneRef.current = val;\n // A leaf's cross commonly overlaps the workspace edge/corner zones underneath it —\n // the more specific per-leaf target wins, matching the corner zone's own handler,\n // which already clears the edge the same way.\n if (val) {\n setActiveEdgeDrop(null);\n setActiveCornerAnchor(null);\n }\n };\n\n // Used during touch drag (pointer capture suppresses hover events on other elements)\n const updateHoverFromPoint = (x: number, y: number) => {\n const elements = document.elementsFromPoint(x, y);\n let foundDropZone = false;\n let foundEdge = false;\n let foundTab = false;\n\n for (const el of elements) {\n if (!(el instanceof HTMLElement)) continue;\n\n if (!foundDropZone && el.dataset.dropZone) {\n const leafId = el.dataset.leafId;\n if (leafId) {\n const pos = el.dataset.dropZone as DropPosition;\n setActiveDropZone({ leafId, position: pos });\n activeDropZoneRef.current = { leafId, position: pos };\n foundDropZone = true;\n }\n }\n\n // Tabs checked before edge triggers — precise tab intent beats the coarse edge zone\n if (!foundTab && el.dataset.tabId) {\n const leafId = el.dataset.leafId;\n const tabIdx = parseInt(el.dataset.tabIndex || '0', 10);\n if (leafId) {\n const rect = el.getBoundingClientRect();\n const side = (x - rect.left) < rect.width / 2 ? 'left' : 'right';\n setHoveredTab({ leafId, panelId: el.dataset.tabId, index: tabIdx, side });\n hoveredTabRef.current = { leafId, panelId: el.dataset.tabId, index: tabIdx, side };\n foundTab = true;\n }\n }\n\n if (!foundEdge && el.dataset.edgeTrigger) {\n setActiveEdgeDrop(el.dataset.edgeTrigger as SplitDirection);\n foundEdge = true;\n }\n\n if (foundDropZone && foundEdge && foundTab) break;\n }\n\n if (!foundDropZone) { setActiveDropZone(null); activeDropZoneRef.current = null; }\n if (!foundEdge) setActiveEdgeDrop(null);\n if (!foundTab) { setHoveredTab(null); hoveredTabRef.current = null; }\n };\n\n const LONG_PRESS_MS = 300;\n const CANCEL_MOVE_PX = 8;\n\n const clearDragState = () => {\n setDraggedPanelId(null);\n setActiveDropZone(null);\n activeDropZoneRef.current = null;\n setHoveredTab(null);\n hoveredTabRef.current = null;\n setActiveEdgeDrop(null);\n };\n\n const flipRtl = (pos: DropPosition): DropPosition => {\n if (!state.isRtl) return pos;\n if (pos === 'left') return 'right';\n if (pos === 'right') return 'left';\n return pos;\n };\n\n const executeDrop = (id: string, me: PointerEvent) => {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n const cornerAnchor = activeCornerAnchorRef.current;\n\n if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, flipRtl(edgeDrop) as SplitDirection);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') targetIndex += 1;\n // DOM tab indices are pre-removal. movePanelOrder removes the panel before\n // inserting, shifting subsequent positions down by 1 in the same leaf.\n // Compensate when the dragged panel currently sits before the drop target.\n const targetLeaf = findLeaf(state.gridRoot, targetTab.leafId);\n if (targetLeaf) {\n const currentIdx = targetLeaf.panels.indexOf(id);\n if (currentIdx !== -1 && currentIdx < targetIndex) targetIndex -= 1;\n }\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, flipRtl(dropZone.position));\n } else if (cornerAnchor) {\n floatPanel(id, undefined, isRtl ? flipZoneHorizontal(cornerAnchor) : cornerAnchor);\n } else {\n floatPanel(id, { x: me.clientX - 150, y: me.clientY - 15, width: 450, height: 350 });\n }\n setActiveCornerAnchor(null);\n clearDragState();\n };\n\n const handleTabDragStart = (id: string, e: React.PointerEvent) => {\n if (e.pointerType === 'mouse' && e.button !== 0) return;\n e.preventDefault();\n\n const el = e.currentTarget as HTMLElement;\n const startX = e.clientX;\n const startY = e.clientY;\n\n if (e.pointerType === 'touch') {\n const pointerId = e.pointerId;\n let cancelled = false;\n\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n };\n\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n\n try { el.setPointerCapture(pointerId); } catch { return; }\n el.classList.add('rdd-long-press-active');\n document.body.classList.add('rdd-dragging-active');\n if (navigator.vibrate) navigator.vibrate(10);\n\n // Long-press captured: move → drag, release → context menu\n let dragStarted = false;\n\n const onMove = (me: PointerEvent) => {\n if (!dragStarted) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n setDragPos({ x: me.clientX, y: me.clientY });\n updateHoverFromPoint(me.clientX, me.clientY);\n };\n\n const onEnd = (me: PointerEvent) => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n\n if (dragStarted) {\n executeDrop(id, me);\n } else {\n // Release without drag → context menu\n handleTabRightClick(id, me as unknown as React.MouseEvent);\n }\n };\n\n const onCancel = () => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n if (dragStarted) clearDragState();\n };\n\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onCancel);\n }, LONG_PRESS_MS);\n\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', cancel);\n el.addEventListener('pointercancel', cancel);\n } else {\n // Mouse / pen: window-level listeners WITHOUT setPointerCapture so that\n // onPointerEnter/Leave on drop zones and edge triggers still fire normally.\n let dragStarted = false;\n\n const onMove = (me: PointerEvent) => {\n const dx = me.clientX - startX;\n const dy = me.clientY - startY;\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n if (dragStarted) setDragPos({ x: me.clientX, y: me.clientY });\n };\n\n const onEnd = (me: PointerEvent) => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) executeDrop(id, me);\n };\n\n const onCancel = () => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) clearDragState();\n };\n\n document.body.classList.add('rdd-dragging-active');\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onEnd);\n window.addEventListener('pointercancel', onCancel);\n }\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 icon: ContextMenuIcons.float,\n action: () => floatPanel(id)\n });\n }\n if (options?.canMinimize !== false) {\n items.push({\n label: formatLabel(messages.minimizePanel, formatMessage),\n icon: ContextMenuIcons.minimize,\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 icon: ContextMenuIcons.close,\n action: () => handleRequestClose(id)\n });\n }\n\n if (items.length === 0) return;\n\n const custom = getPanelContextMenuItems(id);\n const finalItems = custom.length > 0 ? [...items, { separator: true as const }, ...custom] : items;\n\n showContextMenu({\n event: e,\n items: finalItems\n });\n };\n\n const handleMinimizedRightClick = (id: string, e: React.MouseEvent) => {\n e.preventDefault();\n setHoveredMinimized(null);\n showContextMenu({\n event: e,\n items: [\n {\n label: formatLabel(messages.restorePanel, formatMessage),\n icon: ContextMenuIcons.restore,\n action: () => restorePanel(id)\n },\n {\n label: formatLabel(messages.maximizePanel, formatMessage),\n icon: ContextMenuIcons.maximize,\n action: () => maximizePanel(id)\n },\n { separator: true },\n {\n label: formatLabel(messages.closePanel, formatMessage),\n icon: ContextMenuIcons.close,\n action: () => handleRequestClose(id)\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 let heightWarnShown = false;\n\n const observer = new ResizeObserver((entries) => {\n if (!entries || entries.length === 0) return;\n const rect = entries[0].contentRect;\n\n if (process.env.NODE_ENV === 'development' && rect.height < 10 && !heightWarnShown) {\n heightWarnShown = true;\n\n // Walk up the ancestor chain to find the highest zero-height element\n let culprit: Element = el;\n let cursor = el.parentElement;\n while (cursor && cursor !== document.documentElement) {\n if (cursor.getBoundingClientRect().height < 10) {\n culprit = cursor;\n } else {\n break;\n }\n cursor = cursor.parentElement;\n }\n\n const tag = culprit.tagName.toLowerCase();\n const id = culprit.id ? ` id=\"${culprit.id}\"` : '';\n const cls = culprit.className ? ` class=\"${culprit.className}\"` : '';\n const who = culprit === el\n ? 'the WindowManager container itself'\n : `a wrapper element: <${tag}${id}${cls}>`;\n\n console.warn(\n `[react-dockable-desktop] Workspace height is 0px — the workspace will be invisible.\\n\\n` +\n `Zero height found at: ${who}\\n\\n` +\n `Root cause: in CSS, \"height: 100%\" only works when the parent has an explicit height.\\n` +\n `If any ancestor has height: auto (the default for <div>), the chain breaks and\\n` +\n `everything inside collapses to 0px.\\n\\n` +\n `Fix options:\\n` +\n ` 1. Use height: 100vh directly on the workspace wrapper:\\n` +\n ` <div style={{ height: '100vh', overflow: 'hidden' }}>\\n` +\n ` <WindowManager />\\n` +\n ` </div>\\n\\n` +\n ` 2. Use CSS Grid/Flex and let the workspace fill remaining space:\\n` +\n ` .layout { display: flex; flex-direction: column; height: 100vh; }\\n` +\n ` .workspace { flex: 1; min-height: 0; }\\n\\n` +\n ` 3. Verify styles.css is imported — it anchors html, body, #root to 100% height.`\n );\n }\n\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 // 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 (applies whether anchored or free-floating)\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 // Anchored windows are positioned entirely by `anchor` + `dir` at render time (see the\n // floating-window style callback below), so x/y don't affect their visual position —\n // only free-floating windows need off-screen bounds clamping here.\n if (!w.anchor) {\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 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/touch anywhere inside a window or grid panel focuses it)\n useEffect(() => {\n const handlePointerDownGlobal = (e: PointerEvent) => {\n // Only handle primary button (left-click or first touch point)\n if (e.button !== 0) return;\n\n const target = e.target as HTMLElement | null;\n if (!target || typeof target.closest !== 'function') return;\n\n // 1. Check if click is inside a floating window\n const windowEl = target.closest('.rdd-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('.rdd-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('pointerdown', handlePointerDownGlobal);\n return () => {\n document.removeEventListener('pointerdown', handlePointerDownGlobal);\n };\n }, [focusPanel, setActivePanel]);\n\n // Floating Window dragging handler\n const startDrag = (id: string, e: React.PointerEvent) => {\n e.preventDefault();\n const floatingWin = state.floating.find(w => w.id === id);\n if (!floatingWin || floatingWin.maximized) return;\n focusPanel(id);\n\n const el = e.currentTarget as HTMLDivElement;\n const windowEl = el.closest('.rdd-floating-window') as HTMLDivElement | null;\n const startX = e.clientX;\n const startY = e.clientY;\n const startPosX = windowEl ? windowEl.offsetLeft : 0;\n const startPosY = windowEl ? windowEl.offsetTop : 0;\n\n const executeFWDrop = () => {\n const dropZone = activeDropZoneRef.current;\n const targetTab = hoveredTabRef.current;\n const edgeDrop = activeEdgeDropRef.current;\n const cornerAnchor = activeCornerAnchorRef.current;\n if (cornerAnchor) {\n updateFloatingPosition(id, { anchor: isRtl ? flipZoneHorizontal(cornerAnchor) : cornerAnchor });\n } else if (edgeDrop) {\n dockPanelToWorkspaceEdge(id, flipRtl(edgeDrop) as SplitDirection);\n } else if (targetTab) {\n let targetIndex = targetTab.index;\n if (targetTab.side === 'right') targetIndex += 1;\n movePanelOrder(id, targetTab.leafId, targetIndex);\n } else if (dropZone) {\n dockPanelToGroup(id, dropZone.leafId, flipRtl(dropZone.position));\n }\n setActiveCornerAnchor(null);\n clearDragState();\n };\n\n if (e.pointerType === 'touch') {\n const pointerId = e.pointerId;\n let cancelled = false;\n\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n };\n\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n\n try { el.setPointerCapture(pointerId); } catch { return; }\n el.classList.add('rdd-long-press-active');\n document.body.classList.add('rdd-dragging-active');\n setDraggedPanelId(id);\n\n const onMove = (me: PointerEvent) => {\n const dx = me.clientX - startX;\n const dy = me.clientY - startY;\n updateFloatingPosition(id, { x: startPosX + dx, y: startPosY + dy, anchor: null });\n updateHoverFromPoint(me.clientX, me.clientY);\n };\n\n const onEnd = () => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n executeFWDrop();\n };\n\n const onCancel = () => {\n el.classList.remove('rdd-long-press-active');\n document.body.classList.remove('rdd-dragging-active');\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onCancel);\n clearDragState();\n };\n\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onCancel);\n }, LONG_PRESS_MS);\n\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', cancel);\n el.addEventListener('pointercancel', cancel);\n } else {\n // Mouse / pen: window-level listeners WITHOUT setPointerCapture so that\n // onPointerEnter/Leave on drop zones and edge triggers still fire normally.\n let dragStarted = false;\n\n const onMove = (me: PointerEvent) => {\n const dx = me.clientX - startX;\n const dy = me.clientY - startY;\n if (!dragStarted && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n dragStarted = true;\n setDraggedPanelId(id);\n }\n if (dragStarted) {\n updateFloatingPosition(id, { x: startPosX + dx, y: startPosY + dy, anchor: null });\n }\n };\n\n const onEnd = () => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) executeFWDrop();\n };\n\n const onCancel = () => {\n document.body.classList.remove('rdd-dragging-active');\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onCancel);\n if (dragStarted) clearDragState();\n };\n\n document.body.classList.add('rdd-dragging-active');\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onEnd);\n window.addEventListener('pointercancel', onCancel);\n }\n };\n\n // Floating Window resizing handler — supports 8 directions\n const startResize = (id: string, dir: ResizeDir, e: React.PointerEvent) => {\n e.preventDefault();\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 el = e.currentTarget as HTMLDivElement;\n const windowEl = el.closest('.rdd-floating-window') as HTMLDivElement | null;\n const startRect = {\n x: windowEl ? windowEl.offsetLeft : 0,\n y: windowEl ? windowEl.offsetTop : 0,\n w: windowEl ? windowEl.offsetWidth : 400,\n h: windowEl ? windowEl.offsetHeight : 300,\n };\n\n const viewW = workspaceSize.width;\n const viewH = workspaceSize.height;\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 const isRightSnapped = dir === 'se' && Math.abs(parsedX + parsedW - viewW) < 4;\n const isBottomSnapped = dir === 'se' && Math.abs(parsedY + parsedH - viewH) < 4;\n\n startPointerDrag({\n element: el,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => startRect,\n activeClasses: [{ el: document.body, classes: ['rdd-resizing-active'] }],\n // No maxW/maxH/minX/minY: this window is intentionally allowed to grow\n // unbounded and be dragged fully off-screen, same as before this refactor.\n onMove: (dx, dy, start) => {\n const resized = computeResizedRect(dir, dx, dy, start, { minW: 200, minH: 150 });\n let { x: newX, y: newY, w: newW, h: newH } = resized;\n\n // Snap adjustments for SE corner when previously snapped to workspace edges\n if (isRightSnapped) {\n newX = viewW - newW;\n if (newX < 0) { newX = 0; newW = viewW; }\n }\n if (isBottomSnapped) {\n newY = viewH - newH;\n if (newY < 0) { newY = 0; newH = viewH; }\n }\n\n updateFloatingPosition(id, { x: newX, y: newY, width: newW, height: newH });\n },\n });\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 const expandTaskbar = useCallback(() => {\n if (taskbarCollapseTimerRef.current) clearTimeout(taskbarCollapseTimerRef.current);\n setTaskbarExpanded(true);\n }, []);\n\n const scheduleCollapseTaskbar = useCallback(() => {\n taskbarCollapseTimerRef.current = setTimeout(() => setTaskbarExpanded(false), 400);\n }, []);\n\n useEffect(() => {\n if (taskbarVisibility === 'autohide' && state.minimized.length > prevMinimizedLengthRef.current) {\n if (taskbarCollapseTimerRef.current) clearTimeout(taskbarCollapseTimerRef.current);\n setTaskbarExpanded(true);\n taskbarCollapseTimerRef.current = setTimeout(() => setTaskbarExpanded(false), 2000);\n }\n prevMinimizedLengthRef.current = state.minimized.length;\n }, [state.minimized.length, taskbarVisibility]);\n\n // Fetch the active color-scheme from documentElement to make sure nested variables resolve correctly\n const currentColorScheme = useColorScheme();\n\n // Mirror skin onto documentElement so components rendered outside the WindowManager div\n // (Toolbar, Sidebar) also inherit per-skin CSS variable overrides — same pattern as data-color-scheme.\n useEffect(() => {\n if (skin) {\n document.documentElement.setAttribute('data-workspace-skin', skin);\n } else {\n document.documentElement.removeAttribute('data-workspace-skin');\n }\n return () => { document.documentElement.removeAttribute('data-workspace-skin'); };\n }, [skin]);\n\n // Mirror color-scheme onto documentElement too — Toolbar/Sidebar are siblings (or,\n // for Sidebar, an ancestor) of this div, not descendants, so without this they never\n // actually receive the [data-color-scheme]-scoped tokens (e.g. --sidebar-*) despite\n // the comment above claiming parity with the skin mirroring. Only mirror 'light' —\n // 'dark' is the unscoped :root default, so leaving the attribute absent for it avoids\n // writing back the exact value useColorScheme() just read from this same attribute,\n // which would otherwise re-trigger its own MutationObserver on every mount.\n useEffect(() => {\n if (currentColorScheme === 'light') {\n document.documentElement.setAttribute('data-color-scheme', 'light');\n } else {\n document.documentElement.removeAttribute('data-color-scheme');\n }\n return () => { document.documentElement.removeAttribute('data-color-scheme'); };\n }, [currentColorScheme]);\n\n // Mirror the animations opt-out the same way — covers portaled chrome (ContextMenu,\n // Toast, Toolbar's flyout) that renders outside this div via createPortal.\n useEffect(() => {\n if (!animations) {\n document.documentElement.classList.add('rdd-no-animations');\n } else {\n document.documentElement.classList.remove('rdd-no-animations');\n }\n return () => { document.documentElement.classList.remove('rdd-no-animations'); };\n }, [animations]);\n\n return (\n <div\n className={`rdd-workspace${animations ? '' : ' rdd-no-animations'}`}\n data-workspace-skin={skin}\n data-color-scheme={currentColorScheme}\n style={{ display: 'flex', flexDirection: 'column', position: 'relative', 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 ? 'rdd-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 data-edge-trigger=\"left\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-left\"\n onPointerEnter={() => setActiveEdgeDrop('left')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n data-edge-trigger=\"right\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-right\"\n onPointerEnter={() => setActiveEdgeDrop('right')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n data-edge-trigger=\"top\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-top\"\n onPointerEnter={() => setActiveEdgeDrop('top')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n <div\n data-edge-trigger=\"bottom\"\n className=\"rdd-workspace-edge-trigger rdd-edge-trigger-bottom\"\n onPointerEnter={() => setActiveEdgeDrop('bottom')}\n onPointerLeave={() => setActiveEdgeDrop(null)}\n />\n </>\n )}\n\n {/* Corner anchor drop zones — appear during floating window drag */}\n {state.draggedPanelId !== null && (['top-left', 'top-right', 'bottom-left', 'bottom-right'] as FloatAnchor[]).map(corner => (\n <div\n key={corner}\n className={`rdd-corner-zone rdd-corner-zone--${corner}${activeCornerAnchor === corner ? ' rdd-corner-zone--hovered' : ''}`}\n onPointerEnter={() => { setActiveCornerAnchor(corner); setActiveEdgeDrop(null); }}\n onPointerLeave={() => setActiveCornerAnchor(null)}\n aria-hidden=\"true\"\n />\n ))}\n\n {/* Edge drop visual preview overlay */}\n {state.draggedPanelId !== null && activeEdgeDrop !== null && (\n <div\n className=\"rdd-workspace-edge-preview\"\n style={(() => {\n const pct = `${state.edgeSplitRatio * 100}%`;\n switch (activeEdgeDrop) {\n case 'left': return { left: 0, top: 0, bottom: 0, width: pct };\n case 'right': return { right: 0, top: 0, bottom: 0, width: pct };\n case 'top': return { top: 0, left: 0, right: 0, height: pct };\n case 'bottom': return { bottom: 0, left: 0, right: 0, height: pct };\n }\n })()}\n />\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=\"rdd-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 onPointerDownCapture={() => {\n setActivePanel(w.id);\n focusPanel(w.id);\n }}\n className={`rdd-floating-window ${isMaximized ? 'rdd-maximized' : ''} ${isFocused ? 'rdd-window-focused' : ''} ${windowClass ?? ''}`}\n style={(() => {\n const CORNER_INSET = 8;\n const CORNER_GAP = 8;\n const w_ = typeof w.width === 'number' ? `${w.width}px` : w.width;\n const h_ = typeof w.height === 'number' ? `${w.height}px` : w.height;\n if (isMaximized) {\n return { position: 'absolute' as const, left: 0, top: 0, width: '100%', height: '100%', zIndex: w.z, pointerEvents: isDragged ? 'none' as const : 'auto' as const };\n }\n if (w.anchor) {\n const stack = state.floating.filter(fw => fw.anchor === w.anchor && !fw.maximized);\n const idx = stack.findIndex(fw => fw.id === w.id);\n let stackOffset = CORNER_INSET;\n for (let i = 0; i < idx; i++) {\n const sh = typeof stack[i].height === 'number' ? stack[i].height as number : parseFloat(stack[i].height as string);\n stackOffset += sh + CORNER_GAP;\n }\n const isTop = w.anchor.startsWith('top');\n const isRight = w.anchor.endsWith('-right');\n return {\n position: 'absolute' as const,\n [isRight ? 'insetInlineEnd' : 'insetInlineStart']: CORNER_INSET,\n [isTop ? 'top' : 'bottom']: stackOffset,\n width: w_,\n height: h_,\n zIndex: w.z,\n transition: isDragged ? 'none' : 'top 0.2s ease, bottom 0.2s ease',\n pointerEvents: isDragged ? 'none' as const : 'auto' as const,\n };\n }\n return {\n position: 'absolute' as const,\n left: typeof w.x === 'number' ? `${w.x}px` : w.x,\n top: typeof w.y === 'number' ? `${w.y}px` : w.y,\n width: w_,\n height: h_,\n zIndex: w.z,\n pointerEvents: isDragged ? 'none' as const : 'auto' as const,\n };\n })()}\n >\n {/* Title Bar */}\n <div\n onDoubleClick={() => maximizePanel(w.id)}\n onPointerDown={(e) => {\n if (options?.canDrag !== false) {\n startDrag(w.id, e);\n }\n }}\n className=\"rdd-floating-window-titlebar rdd-cursor-move\"\n style={{ cursor: isMaximized || options?.canDrag === false ? 'default' : 'move' }}\n >\n <span className=\"rdd-floating-window-title\">\n <span className=\"rdd-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=\"rdd-titlebar-actions\" style={{ gap: 'var(--rdd-header-button-gap, 4px)' }} onPointerDown={(e) => e.stopPropagation()}>\n {options?.renderHeaderActions && (\n <div className=\"rdd-window-header-actions\">\n {options.renderHeaderActions(w.id)}\n </div>\n )}\n {getPanelContextMenuItems(w.id).length > 0 && (\n <button\n type=\"button\"\n className=\"rdd-custom-tab-btn rdd-btn-more-actions\"\n title=\"More actions\"\n onClick={(e) => {\n e.stopPropagation();\n const customItems = getPanelContextMenuItems(w.id);\n if (customItems.length === 0) return;\n showContextMenu({\n event: e,\n items: customItems\n });\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style={{ display: 'block' }}>\n <circle cx=\"12\" cy=\"5\" r=\"2\"/>\n <circle cx=\"12\" cy=\"12\" r=\"2\"/>\n <circle cx=\"12\" cy=\"19\" r=\"2\"/>\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=\"rdd-custom-tab-btn rdd-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=\"rdd-custom-tab-btn rdd-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=\"rdd-custom-tab-btn rdd-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 {/* 8-direction resize handles */}\n {!isMaximized && (\n <>\n <div onPointerDown={(e) => startResize(w.id, 'n', e)} className=\"rdd-resize-handle rdd-resize-n\" />\n <div onPointerDown={(e) => startResize(w.id, 'ne', e)} className=\"rdd-resize-handle rdd-resize-ne\" />\n <div onPointerDown={(e) => startResize(w.id, 'e', e)} className=\"rdd-resize-handle rdd-resize-e\" />\n <div onPointerDown={(e) => startResize(w.id, 'se', e)} className=\"rdd-resize-handle rdd-resize-se\" />\n <div onPointerDown={(e) => startResize(w.id, 's', e)} className=\"rdd-resize-handle rdd-resize-s\" />\n <div onPointerDown={(e) => startResize(w.id, 'sw', e)} className=\"rdd-resize-handle rdd-resize-sw\" />\n <div onPointerDown={(e) => startResize(w.id, 'w', e)} className=\"rdd-resize-handle rdd-resize-w\" />\n <div onPointerDown={(e) => startResize(w.id, 'nw', e)} className=\"rdd-resize-handle rdd-resize-nw\" />\n </>\n )}\n </div>\n );\n });\n })()}\n </div>\n\n {/* 2. macOS / Windows 11-style Taskbar Sibling Footer (Flex-shrinked at bottom) */}\n {(taskbarVisibility === 'always' || state.minimized.length > 0) && (\n <div\n className={[\n 'rdd-taskbar-footer-container',\n `rdd-taskbar-mode-${taskbarVisibility}`,\n taskbarVisibility === 'autohide' && taskbarExpanded ? 'rdd-taskbar-expanded' : '',\n ].filter(Boolean).join(' ')}\n style={{ height: '48px', zIndex: 100 }}\n onPointerEnter={taskbarVisibility === 'autohide' ? expandTaskbar : undefined}\n onPointerLeave={taskbarVisibility === 'autohide' ? scheduleCollapseTaskbar : undefined}\n >\n {taskbarVisibility === 'autohide' && <div className=\"rdd-taskbar-peek-handle\" />}\n <button\n type=\"button\"\n onClick={() => scrollTaskbar('left')}\n className=\"rdd-taskbar-nav-btn\"\n style={{ display: state.minimized.length > 4 ? 'block' : 'none' }}\n >\n ◀\n </button>\n\n <div\n ref={taskbarRef}\n className=\"rdd-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 if (lastTaskbarPointerTypeRef.current === 'touch') return;\n setHoveredMinimized(null);\n restorePanel(m.id);\n }}\n onContextMenu={(e) => handleMinimizedRightClick(m.id, e)}\n onPointerDown={(e) => {\n lastTaskbarPointerTypeRef.current = e.pointerType;\n if (e.pointerType !== 'touch') return;\n const el = e.currentTarget as HTMLElement;\n const startX = e.clientX;\n const startY = e.clientY;\n const pointerId = e.pointerId;\n let cancelled = false;\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', onShortTap);\n el.removeEventListener('pointercancel', cancel);\n };\n const onShortTap = () => {\n cancel();\n const rect = el.getBoundingClientRect();\n if (hoveredMinimized?.id === m.id) {\n restorePanel(m.id);\n setHoveredMinimized(null);\n } else {\n setHoveredMinimized({ id: m.id, rect, title: m.title, component: m.component, fromTouch: true });\n }\n };\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', onShortTap);\n el.removeEventListener('pointercancel', cancel);\n try { el.setPointerCapture(pointerId); } catch { return; }\n if (navigator.vibrate) navigator.vibrate(10);\n const onEnd = (me: PointerEvent) => {\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onEnd);\n handleMinimizedRightClick(m.id, me as unknown as React.MouseEvent);\n };\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onEnd);\n }, LONG_PRESS_MS);\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', onShortTap);\n el.addEventListener('pointercancel', cancel);\n }}\n onPointerEnter={(e) => {\n if (e.pointerType === 'touch') return;\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 onPointerLeave={(e) => {\n if (e.pointerType === 'touch') return;\n minimizedTooltipTimeoutRef.current = setTimeout(() => {\n setHoveredMinimized(null);\n }, 150);\n }}\n className=\"rdd-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=\"rdd-taskbar-item-icon\">\n {icon}\n </span>\n </div>\n );\n })}\n </div>\n\n {hoveredMinimized && createPortal(\n <div\n className=\"rdd-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 onPointerEnter={() => {\n if (minimizedTooltipTimeoutRef.current) {\n clearTimeout(minimizedTooltipTimeoutRef.current);\n }\n }}\n onPointerLeave={(e) => {\n if (e.pointerType === 'touch') return;\n setHoveredMinimized(null);\n }}\n onClick={() => {\n restorePanel(hoveredMinimized.id);\n setHoveredMinimized(null);\n }}\n onContextMenu={(e) => handleMinimizedRightClick(hoveredMinimized.id, e)}\n onPointerDown={(e) => {\n if (e.pointerType !== 'touch') return;\n const tooltipId = hoveredMinimized.id;\n const el = e.currentTarget as HTMLElement;\n const startX = e.clientX;\n const startY = e.clientY;\n const pointerId = e.pointerId;\n let cancelled = false;\n const cancel = () => {\n cancelled = true;\n clearTimeout(timer);\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n };\n const onPreMove = (me: PointerEvent) => {\n if (Math.hypot(me.clientX - startX, me.clientY - startY) > CANCEL_MOVE_PX) cancel();\n };\n const timer = setTimeout(() => {\n if (cancelled) return;\n el.removeEventListener('pointermove', onPreMove);\n el.removeEventListener('pointerup', cancel);\n el.removeEventListener('pointercancel', cancel);\n try { el.setPointerCapture(pointerId); } catch { return; }\n if (navigator.vibrate) navigator.vibrate(10);\n const onEnd = (me: PointerEvent) => {\n el.removeEventListener('pointerup', onEnd);\n el.removeEventListener('pointercancel', onEnd);\n handleMinimizedRightClick(tooltipId, me as unknown as React.MouseEvent);\n };\n el.addEventListener('pointerup', onEnd);\n el.addEventListener('pointercancel', onEnd);\n }, LONG_PRESS_MS);\n el.addEventListener('pointermove', onPreMove);\n el.addEventListener('pointerup', cancel);\n el.addEventListener('pointercancel', cancel);\n }}\n >\n <div className=\"rdd-tooltip-header-row\">\n <span className=\"rdd-tooltip-title-text rdd-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=\"rdd-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=\"rdd-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%' }} dir={state.dir}>\n {renderPanelContent(id, panel, registry)}\n </div>\n </FormContainerProviderWrapper>,\n targetEl,\n id\n );\n })}\n\n {/* 4. Context Menu — only rendered when no parent ContextMenuProvider is in the tree */}\n {ctxMenu === null && (\n <contextMenuAdapter.Component\n ref={contextMenuRef}\n theme=\"dark\"\n formatMessageProvider={formatMessage}\n onShow={() => setInternalContextMenuOpen(true)}\n onHide={() => setInternalContextMenuOpen(false)}\n />\n )}\n\n {/* 5. Dragging Tab Ghost Representation */}\n {state.draggedPanelId !== null && !state.floating.some(w => w.id === state.draggedPanelId) && (\n <div\n className=\"rdd-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, useSyncExternalStore } from 'react';\nimport { useFormContainer } from './FormContainerContext';\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 };\nimport type { ContextMenuItem, ShowContextMenuOptions } from './ContextMenu';\nimport { isSerializable } from './serializable';\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/** The four cardinal directions a panel can be docked relative to another. */\nexport type SplitDirection = 'left' | 'right' | 'top' | 'bottom';\n\n/** All possible drop positions — cardinal directions plus center (same group). */\nexport type DropPosition = SplitDirection | 'center';\n\n/** The target leaf and position for a drag-and-drop dock operation. */\nexport interface DropTarget {\n leafId: string;\n position: DropPosition;\n}\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 * Corner of the workspace a floating window can be pinned to.\n *\n * When `anchor` is set on a `FloatingWindow`, the window is positioned\n * relative to that corner using CSS `right`/`left` + `top`/`bottom` and\n * stacks with other windows sharing the same anchor (8 px gap, uncapped).\n * Dragging a window away from its corner clears the anchor and returns it\n * to free-float mode. The value is RTL-aware — `'top-left'` always means the\n * logical start corner regardless of document direction.\n */\nexport type FloatAnchor = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\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 /** Corner of the workspace this window is pinned to, or null when free-floating. */\n anchor?: FloatAnchor | null;\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; anchor?: FloatAnchor | null };\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 /** Custom per-instance data passed via `openPanel(id, component, { props })`. Unconstrained —\n * any value is accepted, but only a value that passes {@link isSerializable} is actually\n * included in {@link WindowActions.saveLayout}'s output. See {@link PanelInfo.serializable}. */\n props?: Record<string, unknown>;\n /** Whether this panel's current `props` can round-trip through `saveLayout()`/`loadLayout()`.\n * Computed automatically — `true` when no `props` were passed, or when they were and passed\n * {@link isSerializable}. A panel with `serializable: false` still renders and works normally;\n * it's simply excluded from the next `saveLayout()` call (and pruned from `gridRoot`/\n * `floating`/`minimized` in that saved snapshot) rather than corrupting or throwing. */\n serializable: boolean;\n /** Optional dedup key. If another open panel of the same `component` already has this exact\n * key, `openPanel` focuses that existing panel instead of creating a new one — see\n * {@link WindowActions.openPanel}'s `dedupeKey` option and {@link WindowActions.findPanelId}. */\n dedupeKey?: string;\n}\n\n/**\n * Options accepted by {@link WindowActions.openPanel}.\n */\nexport interface OpenPanelOptions<P extends object = Record<string, unknown>> {\n /** Override the panel tab/window title. Accepts a plain string or an i18n message descriptor. */\n title?: string | ContextMenuPredefinedMessage;\n /** Initial placement: `'floating'`, `'docked'` (default when a grid exists), or `'tabbed'`. */\n initialTarget?: 'floating' | 'docked' | 'tabbed';\n /** Pin the new floating window to a workspace corner on creation. Has no effect when\n * `initialTarget` is `'docked'` or `'tabbed'`. */\n anchor?: FloatAnchor | null;\n /** Set `state.activePanelId` to this panel. @default true */\n focus?: boolean;\n /**\n * Custom per-instance data spread onto the panel component alongside `panelId`, matching\n * `openModal`/`openLeftPanel`/`openRightPanel`'s already-unconstrained `props` argument — no\n * type restriction here either. Whether a specific value round-trips through `saveLayout()` is\n * a runtime fact, not a type-level guarantee: see {@link PanelInfo.serializable} and the\n * `'layout:panels-excluded'` event.\n */\n props?: P;\n /**\n * If set, and another currently-open panel of the same `component` already has this exact\n * `dedupeKey`, that existing panel is focused instead of opening a new one — the `id`/`props`\n * passed to *this* call are ignored in that case, the same way re-opening an already-open exact\n * `id` already focuses it instead of duplicating it. Use this when multiple call sites might\n * not agree on the same literal `id` for what is semantically the same entity (e.g. \"the panel\n * for the document at this path\"). See also {@link WindowActions.findPanelId}.\n */\n dedupeKey?: string;\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 /**\n * The ID of the active/focused panel — the one contributions are read from\n * (see `useActivePanelContribution`) and the one drawn with focused chrome.\n *\n * Always a panel the user can actually see: the selected tab of its leaf, or a floating\n * window. Never a minimized panel, except when an app explicitly calls `focusPanel()` on\n * one. Restored layouts resolve it from the saved snapshot's own `activePanelId`, falling\n * back to the first leaf's selected tab — never to an arbitrary entry in `panels`.\n */\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 /** Split ratio for panel cross-target drops (0.1–0.9). Default 0.5. */\n splitRatio: number;\n /** Split ratio for workspace outer-edge drops (0.1–0.9). Default 0.2. */\n edgeSplitRatio: number;\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 * Becomes `state.activePanelId` by default — pass `options.focus: false` to open\n * without stealing focus from whatever is currently active.\n * @param id - Unique instance identifier for this panel.\n * @param component - Component key registered in the panel catalog.\n * @param options.title - Override the panel tab/window title. Accepts a plain string or an i18n message descriptor.\n * @param options.initialTarget - Initial placement: `'floating'`, `'docked'` (default when a grid exists), or `'tabbed'`.\n * @param options.anchor - Pin the new floating window to a workspace corner on creation. Has no effect when `initialTarget` is `'docked'` or `'tabbed'`.\n * @param options.focus - Set `state.activePanelId` to this panel. @default true\n * @param options.props - Custom per-instance data spread onto the component alongside `panelId`. Unconstrained, like `openModal`/`openLeftPanel`/`openRightPanel`'s `props` — see {@link PanelInfo.serializable} for what determines whether it survives `saveLayout()`.\n * @param options.dedupeKey - If another open panel of the same `component` already has this key, that panel is focused instead of opening a new one.\n * @example\n * ```ts\n * // Open floating and pin to the top-right corner:\n * actions.openPanel('layers', 'layertree', { initialTarget: 'floating', anchor: 'top-right' });\n *\n * // Open in the background without stealing focus:\n * actions.openPanel('prefetch', 'report', { focus: false });\n *\n * // Open with per-instance data, deduped by document path:\n * actions.openPanel(crypto.randomUUID(), 'document', {\n * props: { path: '/notes/todo.md' },\n * dedupeKey: '/notes/todo.md',\n * });\n * ```\n */\n openPanel: <P extends object = Record<string, unknown>>(id: string, component: string, options?: OpenPanelOptions<P>) => 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 * @param options.focus - Set `state.activePanelId` to the restored panel. @default true\n */\n restorePanel: (id: string, options?: { focus?: boolean }) => 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. Omit to use the last known position or a cascaded default.\n * @param anchor - Optional corner to pin the new floating window to. Omit (or pass `null`) for free-float.\n */\n floatPanel: (id: string, rect?: { x: number; y: number; width: number; height: number }, anchor?: FloatAnchor | null) => 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`, or `anchor`.\n */\n updateFloatingPosition: (id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'anchor'>>) => 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 * Finds the ID of an already-open panel of the given `component` with a matching `dedupeKey`\n * (set via `openPanel`'s `dedupeKey` option). Uses a synchronous `stateRef` read — safe to\n * call outside of render.\n * @param component - Component key registered in the panel catalog.\n * @param dedupeKey - The dedup key to search for.\n * @returns The matching panel's ID, or `null` if none is open.\n */\n findPanelId: (component: string, dedupeKey: string) => string | null;\n /**\n * Serializes the entire workspace state to a JSON string.\n * Includes grid layout, floating window positions, minimized panels, panel metadata, and the\n * globally active panel (see {@link SerializedLayout.activePanelId}).\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 *\n * `state.activePanelId` is resolved from the snapshot's own `activePanelId` when that panel is\n * still visible in it, and otherwise from the first leaf's selected tab (which is also the path\n * layouts saved before that field existed take). It is never seeded from an arbitrary entry in\n * `panels`.\n *\n * @param layoutJson - JSON string produced by {@link saveLayout}.\n * @returns `true` if the layout was successfully parsed and applied, `false` otherwise.\n */\n loadLayout: (layoutJson: string) => boolean;\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: DropPosition) => 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 * Registers a callback reporting a docked/floating panel's *current* restorable state, pulled\n * fresh every `saveLayout()` call — for panels whose props alone can't capture state they\n * accumulate after opening (scroll position, an in-progress edit, a view-mode toggle). A panel\n * that registers nothing keeps its static open-time `props` (or none). The returned value goes\n * through the same {@link isSerializable} check as static props, re-evaluated on every save —\n * a provider-backed panel's serializability can flip over its lifetime.\n * @param id - Panel instance ID.\n * @param provider - Called synchronously at each `saveLayout()`; return the current state (or\n * `undefined` to fall back to the static `props` this panel was opened with).\n */\n registerStateProvider: (id: string, provider: () => unknown) => void;\n /**\n * Removes a previously registered state provider.\n * @param id - Panel instance ID.\n */\n unregisterStateProvider: (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: SplitDirection) => void;\n /**\n * Overrides the workspace layout direction.\n * @param dir - `'ltr'` or `'rtl'`.\n */\n setDirection: (dir: 'ltr' | 'rtl') => void;\n /**\n * Imperatively shows the workspace context menu at the given position.\n * Delegates to the active {@link ContextMenuProvider}, so custom adapters\n * and externally-placed providers are respected automatically.\n */\n showContextMenu: (options: ShowContextMenuOptions) => 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 /** @internal */\n registerPanelContextMenu: (panelId: string, getItems: () => ContextMenuItem[]) => () => void;\n /** @internal */\n getPanelContextMenuItems: (panelId: string) => ContextMenuItem[];\n /** @internal */\n registerContextMenuFn: (fn: (options: ShowContextMenuOptions) => void) => () => void;\n}\n\nexport const WindowStateContext: React.Context<WindowState | null> = createContext<WindowState | null>(null);\nconst WindowActionsContext = createContext<InternalWindowActions | null>(null);\nconst WindowI18nContext = createContext<MessageFormatter | null>(null);\n\ninterface WindowStoreSyncContextValue {\n getSnapshot: () => WindowState;\n subscribeToState: (callback: () => void) => () => void;\n}\nconst WindowStoreSyncContext = createContext<WindowStoreSyncContextValue | 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 = (): StyleClasses => 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 = (): PanelRegistryClass => 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\n/** The on-disk shape produced by `saveLayout()` and accepted by `loadLayout()`/`initialState`. */\nexport interface SerializedLayout {\n /** Schema version — absent on layouts saved before this field was introduced (treated as 0). */\n version?: number;\n /**\n * The globally active panel at save time — the one the user was actually looking at.\n *\n * Omitted when nothing was active, and when the active panel didn't survive this snapshot's\n * serializability pruning (see {@link WindowActions.saveLayout}) — so it never names a panel\n * absent from this payload's own `panels`. Absent on every layout saved before this field\n * existed, in which case the restore derives it from `gridRoot`'s own per-leaf selection\n * instead; a present-but-no-longer-valid value falls back to the same derivation. `version`\n * is deliberately not bumped for this: the field is optional and its absence is a supported,\n * fully-handled case rather than a schema a migration has to branch on.\n */\n activePanelId?: string | null;\n gridRoot: LayoutNode;\n floating: FloatingWindow[];\n minimized: { id: string; title: string | ContextMenuPredefinedMessage; component: string }[];\n panels: Record<string, PanelInfo>;\n}\n\ntype ParsedLayoutPayload = Pick<SerializedLayout, 'gridRoot' | 'floating' | 'minimized' | 'panels'> & {\n /** Resolved by `parseLayoutPayload` — the persisted value when still valid, else derived. */\n activePanelId: string | null;\n};\n\n/** The subset of a layout needed to reason about which panel is visibly active. */\ntype ActiveTargetScope = Pick<SerializedLayout, 'gridRoot' | 'floating' | 'panels'>;\n\n/**\n * Whether `id` names a panel the user can actually see, and which may therefore be the globally\n * active one: the selected tab of some leaf, or a floating window. A minimized panel never\n * qualifies — it stays mounted (see the persistence port in `WindowManager.tsx`), so leaving it\n * active would keep routing `useActivePanelContribution()` to a panel that isn't on screen.\n *\n * Used both to validate a persisted `activePanelId` on load and to guard the one written by\n * `saveLayout`, so the two directions can't disagree about what \"active\" is allowed to mean.\n */\nfunction isVisibleActiveTarget(id: string, scope: ActiveTargetScope): boolean {\n const info = scope.panels[id];\n if (!info || info.state === 'minimized') return false;\n if (scope.floating.some(w => w.id === id)) return true;\n const isLeafSelection = (node: LayoutNode): boolean =>\n node.type === 'leaf'\n ? node.activePanelId === id\n : node.children.some(isLeafSelection);\n return scope.gridRoot ? isLeafSelection(scope.gridRoot) : false;\n}\n\n/**\n * Derives the globally active panel for a restored layout.\n *\n * Replaces the original `Object.keys(panels)[0]` seed, which picked the first key of a flat,\n * insertion-ordered record that knows nothing about tab order or docked/floating/minimized — so\n * unless the user happened to have the first-opened panel selected when they saved, the workspace\n * came back with one panel visible and a *different*, invisible one marked active. Every\n * `LayoutLeafNode` already persists its own `activePanelId`, so the answer was on disk all along.\n *\n * Order:\n * 1. The first leaf in document order whose own selected tab is a valid target.\n * 2. Otherwise the frontmost (highest `z`) floating window — matching `focusPanel`'s own\n * \"highest z is on top\" rule, and keeping float-only layouts from restoring with nothing\n * active at all.\n * 3. Otherwise `null`.\n *\n * Depth-first, not breadth-first: for a grid whose first child is itself a split, a level-by-level\n * walk reaches the *second* child's leaf before the first child's leaves and picks the wrong tab.\n * Mirrors `findFirstLeafId`'s traversal shape for exactly that reason.\n */\nfunction deriveActivePanelId(scope: ActiveTargetScope): string | null {\n const isCandidate = (id: string | null): boolean =>\n id !== null && !!scope.panels[id] && scope.panels[id].state !== 'minimized';\n\n const fromLeaves = (node: LayoutNode): string | null => {\n if (node.type === 'leaf') {\n return isCandidate(node.activePanelId) ? node.activePanelId : null;\n }\n for (const child of node.children) {\n const found = fromLeaves(child);\n if (found) return found;\n }\n return null;\n };\n\n const selected = scope.gridRoot ? fromLeaves(scope.gridRoot) : null;\n if (selected) return selected;\n\n let frontmost: FloatingWindow | null = null;\n for (const w of scope.floating) {\n if (!isCandidate(w.id)) continue;\n if (!frontmost || w.z > frontmost.z) frontmost = w;\n }\n return frontmost?.id ?? null;\n}\n\n/**\n * Shared shape-check + migration for a parsed (but not yet validated) layout payload,\n * used by both `parseInitialState` (the `initialState`/`WorkspaceClient.initialState`\n * entry point) and `loadLayout` — previously these duplicated the check independently\n * and only one of them ran the stickyRight/stickyBottom migration, so a layout fed\n * through `initialState` silently skipped it. `version` is read but not yet branched on\n * — it's read here so a future migration has a version to gate on without needing\n * another ad hoc field-presence sniff like this one.\n *\n * Also resolves `activePanelId`, for the same reason the shape-check lives here: both entry\n * points need it and previously seeded it themselves, identically wrongly, in two places.\n */\nfunction parseLayoutPayload(parsed: any): ParsedLayoutPayload | null {\n if (!parsed || !parsed.gridRoot || !Array.isArray(parsed.floating) || !Array.isArray(parsed.minimized) || !parsed.panels) {\n return null;\n }\n // const version = typeof parsed.version === 'number' ? parsed.version : 0; // reserved for future migrations\n const floating = (parsed.floating as any[]).map((fw: any) => {\n if ('stickyRight' in fw || 'stickyBottom' in fw) {\n const anchor: FloatAnchor | null = fw.stickyRight && fw.stickyBottom ? 'bottom-right'\n : fw.stickyRight ? 'top-right'\n : fw.stickyBottom ? 'bottom-left'\n : null;\n const { stickyRight: _sr, stickyBottom: _sb, ...rest } = fw;\n return { ...rest, anchor };\n }\n return fw;\n });\n const scope: ActiveTargetScope = { gridRoot: parsed.gridRoot, floating, panels: parsed.panels };\n\n // A persisted value wins when it still names a visible panel; anything stale (the panel was\n // closed, minimized, or pruned from this snapshot) falls back to deriving from the grid, which\n // is also the path every pre-`activePanelId` layout takes.\n const persisted = typeof parsed.activePanelId === 'string' ? parsed.activePanelId : null;\n let activePanelId: string | null = null;\n if (persisted !== null) {\n if (isVisibleActiveTarget(persisted, scope)) {\n activePanelId = persisted;\n } else if (process.env.NODE_ENV === 'development') {\n console.warn(\n `[react-dockable-desktop] Ignoring the saved layout's activePanelId (\"${persisted}\") — ` +\n `it doesn't name a currently visible panel (it may have been closed, minimized, or ` +\n `excluded from the snapshot as non-serializable). Falling back to the selected tab of ` +\n `the first leaf in the grid.`\n );\n }\n }\n if (activePanelId === null) activePanelId = deriveActivePanelId(scope);\n\n return { gridRoot: parsed.gridRoot, floating, minimized: parsed.minimized, panels: parsed.panels, activePanelId };\n}\n\nfunction parseInitialState(json: string | null): Pick<WindowState, 'gridRoot' | 'floating' | 'minimized' | 'panels' | 'activePanelId'> {\n if (json) {\n try {\n const payload = parseLayoutPayload(JSON.parse(json));\n if (payload) return payload;\n } catch {\n // fall through to empty canvas\n }\n }\n return { gridRoot: EMPTY_LEAF, floating: [], minimized: [], panels: {}, activePanelId: null };\n}\n\n/**\n * Props for `<DockableDesktopProvider>` and `<WindowManagerProvider>`.\n * Also exported as `DockableDesktopProviderProps` for consumers who use\n * the composite provider.\n * @see DockableDesktopProviderProps\n */\nexport interface WindowManagerProviderProps {\n children: React.ReactNode;\n /** `WorkspaceClient` instance created outside the React tree. When provided, its panel\n * registry and config take precedence over the individual props below. */\n client?: WorkspaceClient;\n /** Custom i18n formatter. Receives a `{ id, defaultMessage }` descriptor and returns\n * the translated string. When omitted, `defaultMessage` is used as-is. */\n formatMessage?: MessageFormatter;\n /** Override the built-in predefined UI strings (confirm button labels, close tooltips, etc.).\n * Merge with or replace `defaultPredefinedMessages` to localise system strings. */\n predefinedMessages?: Record<string, ContextMenuPredefinedMessage>;\n /** Layout direction. `'rtl'` mirrors all controls, tab order, and drop zones.\n * Can also be changed at runtime via `WorkspaceClient.setDirection()`. @default 'ltr' */\n dir?: 'ltr' | 'rtl';\n /** CSS class applied to the outer wrapper element of every modal overlay. */\n modalClass?: string;\n /** CSS class applied to the inner content area of every modal overlay. */\n modalBodyClass?: string;\n /** CSS class applied to the outer wrapper of left/right side-panel drawers. */\n sidePanelClass?: string;\n /** CSS class applied to the inner content area of side-panel drawers. */\n sidePanelBodyClass?: string;\n /** CSS class applied to the outer wrapper of floating panel windows. */\n windowClass?: string;\n /** CSS class applied to the inner content area of floating panel windows. */\n windowBodyClass?: string;\n /**\n * Starting z-index for floating windows and the library's own chrome overlays\n * (context menu, toolbar flyout, modal stack, toast, workspace edge zones),\n * all of which shift together via `--rdd-z-base`. Set this above/below a host\n * app's own modal z-index range to control stacking against it. @default 1000\n */\n zIndexBase?: number;\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 zIndexBase: zIndexBaseProp\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 const effectiveZIndexBase = client?.config.zIndexBase ?? zIndexBaseProp ?? 1000;\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 splitRatio: Math.min(0.9, Math.max(0.1, client?.config.defaultSplitRatio ?? 0.5)),\n edgeSplitRatio: Math.min(0.9, Math.max(0.1, client?.config.defaultEdgeSplitRatio ?? 0.2)),\n };\n });\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const stateSubscribersRef = useRef<Set<() => void>>(new Set());\n\n useEffect(() => {\n stateSubscribersRef.current.forEach(cb => cb());\n }, [state]);\n\n const getSnapshot = useCallback((): WindowState => stateRef.current, []);\n const subscribeToState = useCallback((cb: () => void): (() => void) => {\n stateSubscribersRef.current.add(cb);\n return () => stateSubscribersRef.current.delete(cb);\n }, []);\n\n const closeGuardsRef = useRef<Record<string, () => boolean | Promise<boolean>>>({});\n const stateProvidersRef = useRef<Record<string, () => unknown>>({});\n\n const mergedMessages = useMemo(() => ({\n ...defaultPredefinedMessages,\n ...effectivePredefinedMessages\n }), [effectivePredefinedMessages]);\n\n const eventBusRef = useRef(new PanelEventBus());\n const maxZRef = useRef(effectiveZIndexBase);\n\n // Mirror the z-index base onto document.documentElement as a CSS variable so the\n // library's portaled chrome (ContextMenu, Toast, Toolbar's flyout, ModalStackRenderer),\n // which renders outside this provider's own DOM subtree, shifts in lockstep with\n // maxZRef — same rationale as the data-workspace-skin mirroring in WindowManager.tsx.\n useEffect(() => {\n document.documentElement.style.setProperty('--rdd-z-base', String(effectiveZIndexBase));\n return () => { document.documentElement.style.removeProperty('--rdd-z-base'); };\n }, [effectiveZIndexBase]);\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 setState(prev => {\n const panel = prev.panels[id];\n if (!panel) return prev;\n\n if (panel.state === 'floating') {\n const win = prev.floating.find(w => w.id === id);\n if (!win) return prev;\n const alreadyTop = !prev.floating.some(w => w.z > win.z);\n if (alreadyTop && prev.activePanelId === id) return prev; // no-op — StrictMode safe\n if (!alreadyTop) maxZRef.current += 1;\n return {\n ...prev,\n floating: prev.floating.map(w =>\n w.id === id ? { ...w, z: alreadyTop ? win.z : maxZRef.current } : w\n ),\n activePanelId: id\n };\n } else if (panel.state === 'docked') {\n if (prev.activePanelId === id) return prev; // no-op\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 if (prev.activePanelId === id) return prev; // no-op for minimized\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(<P extends object = Record<string, unknown>>(id: string, component: string, options?: OpenPanelOptions<P>) => {\n // Dedup redirect: resolve to an already-open panel of the same component/dedupeKey, if any,\n // before anything else runs — the caller's own `id`/`props` are ignored for this call in\n // that case, the same way re-opening an already-open exact `id` already focuses it instead\n // of duplicating it.\n let resolvedId = id;\n if (options?.dedupeKey !== undefined) {\n const match = Object.values(stateRef.current.panels).find(\n p => p.component === component && p.dedupeKey === options.dedupeKey\n );\n if (match) resolvedId = match.id;\n }\n const isNew = !(resolvedId in stateRef.current.panels);\n const isRedirect = resolvedId !== id;\n const shouldFocus = options?.focus !== false;\n const propsProvided = options?.props !== undefined;\n const serializable = propsProvided ? isSerializable(options.props) : true;\n setState(prev => {\n const exists = prev.panels[resolvedId];\n const entry = registry.get(component);\n const title = options?.title || options?.title || entry?.defaultOptions?.title || resolvedId;\n const target = options?.initialTarget || entry?.defaultOptions?.initialTarget || 'docked';\n const favPos = entry?.defaultOptions?.favoritePosition || { x: 300, y: 150, width: 450, height: 350 };\n const activePanelId = shouldFocus ? resolvedId : prev.activePanelId;\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 !== resolvedId);\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: resolvedId, z: maxZRef.current }],\n panels: { ...prev.panels, [resolvedId]: { ...exists, state: 'floating' } },\n activePanelId\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-default';\n return {\n ...prev,\n minimized: nextMinimized,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, resolvedId),\n panels: { ...prev.panels, [resolvedId]: { ...exists, state: 'docked' } },\n activePanelId\n };\n }\n } else if (exists.state === 'floating') {\n if (shouldFocus) focusPanel(resolvedId);\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(resolvedId)) {\n return { ...node, activePanelId: resolvedId };\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\n };\n }\n }\n\n // Case 2: New panel\n const targetState = target === 'tabbed' ? 'docked' : target;\n const newPanelInfo: PanelInfo = {\n id: resolvedId,\n title,\n component,\n state: targetState,\n props: options?.props as Record<string, unknown> | undefined,\n serializable,\n dedupeKey: options?.dedupeKey,\n };\n const nextPanels = { ...prev.panels, [resolvedId]: newPanelInfo };\n\n if (target === 'floating') {\n maxZRef.current += 1;\n const cascaded = getCascadedPosition(favPos, prev.floating);\n\n const anchor = options?.anchor ?? entry?.defaultOptions?.defaultAnchor ?? null;\n\n return {\n ...prev,\n floating: [...prev.floating, { ...cascaded, id: resolvedId, z: maxZRef.current, anchor }],\n panels: nextPanels,\n activePanelId\n };\n } else {\n const firstLeaf = findFirstLeafId(prev.gridRoot) || 'group-default';\n return {\n ...prev,\n gridRoot: addPanelToLeaf(prev.gridRoot, firstLeaf, resolvedId),\n panels: nextPanels,\n activePanelId\n };\n }\n });\n if (isNew) eventBusRef.current.publish('panel:opened', { id: resolvedId, component });\n if (isNew || isRedirect) eventBusRef.current.publish('layout:changed', {});\n }, [getCascadedPosition, focusPanel]);\n\n const closePanel = useCallback((id: string) => {\n const exists = id in stateRef.current.panels;\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 delete stateProvidersRef.current[id];\n\n const nextPanels = { ...prev.panels };\n delete nextPanels[id];\n\n const nextRoot = removePanelFromTree(prev.gridRoot, id)\n || { type: 'leaf' as const, id: 'group-default', panels: [], activePanelId: null };\n const nextFloating = prev.floating.filter(w => w.id !== id);\n\n // Closing the active panel used to leave `activePanelId` pointing at the panel just deleted.\n // `removePanelFromTree` has already promoted the next tab in its leaf, so re-deriving picks\n // whatever the user can now actually see.\n const nextActivePanelId = prev.activePanelId === id\n ? deriveActivePanelId({ gridRoot: nextRoot, floating: nextFloating, panels: nextPanels })\n : prev.activePanelId;\n\n return {\n ...prev,\n gridRoot: nextRoot,\n floating: nextFloating,\n minimized: prev.minimized.filter(m => m.id !== id),\n panels: nextPanels,\n activePanelId: nextActivePanelId\n };\n });\n if (exists) {\n eventBusRef.current.publish('panel:closed', { id });\n eventBusRef.current.publish('layout:changed', {});\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 registerStateProvider = useCallback((id: string, provider: () => unknown) => {\n stateProvidersRef.current[id] = provider;\n }, []);\n\n const unregisterStateProvider = useCallback((id: string) => {\n delete stateProvidersRef.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 const wasActive = stateRef.current.panels[id]?.state !== 'minimized' && id in stateRef.current.panels;\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: PanelInfo['lastFloatingRect'] = undefined;\n let lastLeafId: string | undefined = undefined;\n\n if (panel.state === 'floating') {\n const win = prev.floating.find(w => w.id === id);\n if (win) {\n lastFloatingRect = {\n x: Number(win.x),\n y: Number(win.y),\n width: Number(win.width),\n height: Number(win.height),\n anchor: win.anchor ?? null\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) ?? undefined;\n }\n\n const nextRoot = removePanelFromTree(prev.gridRoot, id)\n || { type: 'leaf' as const, id: 'group-default', panels: [], activePanelId: null };\n const nextFloating = prev.floating.filter(w => w.id !== id);\n const nextPanels: Record<string, PanelInfo> = {\n ...prev.panels,\n [id]: {\n ...panel,\n state: 'minimized',\n previousState: panel.state,\n lastFloatingRect,\n lastLeafId\n }\n };\n\n // A minimized panel is off screen but still mounted (see the persistence port in\n // WindowManager.tsx), so leaving it active kept `useActivePanelContribution()` — and every\n // contributed control — wired to a panel the user can't see. `deriveActivePanelId` skips\n // minimized panels, so this lands on whatever became visible in its place.\n const nextActivePanelId = prev.activePanelId === id\n ? deriveActivePanelId({ gridRoot: nextRoot, floating: nextFloating, panels: nextPanels })\n : prev.activePanelId;\n\n return {\n ...prev,\n gridRoot: nextRoot,\n floating: nextFloating,\n minimized: [...prev.minimized, { id, title: panel.title, component: panel.component }],\n panels: nextPanels,\n activePanelId: nextActivePanelId\n };\n });\n if (wasActive) {\n eventBusRef.current.publish('panel:minimized', { id });\n eventBusRef.current.publish('layout:changed', {});\n }\n }, []);\n\n const restorePanel = useCallback((id: string, options?: { focus?: boolean }) => {\n const wasMinimized = stateRef.current.panels[id]?.state === 'minimized';\n const shouldFocus = options?.focus !== false;\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 // A restored panel is, by definition, visible again — so unlike the minimize path there is\n // nothing to derive: it is itself the only correct candidate. Leaving activePanelId behind\n // reproduced the 6de3381 defect class in reverse (visible tab rendered unfocused, and every\n // contributed control stayed bound to whatever replaced this panel while it was minimized).\n const nextActive = shouldFocus ? id : prev.activePanelId;\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 anchor: panel.lastFloatingRect?.anchor ?? null\n }\n ],\n panels: { ...prev.panels, [id]: { ...panel, state: 'floating' } },\n activePanelId: nextActive\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 activePanelId: nextActive\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 anchor: panel.lastFloatingRect?.anchor ?? null\n }\n ],\n panels: { ...prev.panels, [id]: { ...panel, state: 'floating' } },\n activePanelId: nextActive\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 activePanelId: nextActive\n };\n }\n }\n });\n if (wasMinimized) {\n eventBusRef.current.publish('panel:restored', { id });\n eventBusRef.current.publish('layout:changed', {});\n }\n }, [getCascadedPosition]);\n\n const floatPanel = useCallback((id: string, rect?: { x: number; y: number; width: number; height: number }, anchor?: FloatAnchor | null) => {\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, anchor: anchor ?? null }],\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: SplitDirection,\n splitRatio: number\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 const sizes = (position === 'left' || position === 'top')\n ? [splitRatio, 1 - splitRatio]\n : [1 - splitRatio, splitRatio];\n return {\n type: 'branch',\n orientation,\n sizes,\n children\n };\n }\n return node;\n } else {\n return {\n ...node,\n children: node.children.map(c => splitLeafInTree(c, leafId, panelId, position, splitRatio))\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: DropPosition) => {\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, prev.splitRatio);\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: SplitDirection) => {\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 r = prev.edgeSplitRatio;\n const newRoot: LayoutNode = {\n type: 'branch',\n orientation,\n sizes: (position === 'left' || position === 'top') ? [r, 1 - r] : [1 - r, r],\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' | 'anchor'>>) => {\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 const currentPanels = stateRef.current.panels;\n const excludedIds: string[] = [];\n const includedPanels: Record<string, PanelInfo> = {};\n\n // A registered state provider (see registerStateProvider) is pulled fresh on every save —\n // a panel's serializability can flip over its lifetime, so this is never cached from open\n // time for provider-backed panels. Panels with no provider keep their static open-time\n // props/serializable classification unchanged.\n for (const [id, info] of Object.entries(currentPanels)) {\n const provider = stateProvidersRef.current[id];\n const dynamicValue = provider?.();\n const hasDynamicValue = provider !== undefined && dynamicValue !== undefined;\n const effectiveProps = hasDynamicValue ? (dynamicValue as Record<string, unknown>) : info.props;\n const effectiveSerializable = hasDynamicValue ? isSerializable(dynamicValue) : info.serializable;\n\n if (effectiveSerializable) {\n includedPanels[id] = hasDynamicValue ? { ...info, props: effectiveProps, serializable: effectiveSerializable } : info;\n } else {\n excludedIds.push(id);\n }\n }\n\n // Non-serializable panels are excluded from this saved snapshot — pruned from gridRoot/\n // floating/minimized too, so a restore never references a panel with no data to recreate it\n // meaningfully. This computes a derived copy for the JSON string only; none of this touches\n // stateRef/setState, so the live, on-screen workspace is completely unaffected — an excluded\n // panel keeps existing and working normally on screen, it simply won't be there after the\n // *next* loadLayout().\n let gridRoot = stateRef.current.gridRoot;\n let floating = stateRef.current.floating;\n let minimized = stateRef.current.minimized;\n for (const id of excludedIds) {\n gridRoot = removePanelFromTree(gridRoot, id) || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null };\n floating = floating.filter(w => w.id !== id);\n minimized = minimized.filter(m => m.id !== id);\n }\n\n if (excludedIds.length > 0) {\n eventBusRef.current.publish('layout:panels-excluded', {\n panels: excludedIds.map(id => ({ id, component: currentPanels[id].component }))\n });\n }\n\n // Validated against the *pruned* snapshot, not the live state: if the active panel was itself\n // excluded above, or is minimized, the field is omitted entirely rather than persisted as an id\n // this payload's own `panels` doesn't contain. A restore then derives it — see\n // `deriveActivePanelId`.\n const liveActive = stateRef.current.activePanelId;\n const activePanelId = liveActive !== null && isVisibleActiveTarget(liveActive, { gridRoot, floating, panels: includedPanels })\n ? liveActive\n : null;\n\n const payload: SerializedLayout = {\n version: 2, // v2: panels may carry `props`/`dedupeKey`; the payload may omit panels the\n // live workspace still has open (see the exclusion pass above).\n ...(activePanelId !== null ? { activePanelId } : {}),\n gridRoot,\n floating,\n minimized,\n panels: includedPanels\n };\n return JSON.stringify(payload);\n }, []);\n\n const loadLayout = useCallback((layoutJson: string): boolean => {\n try {\n const payload = parseLayoutPayload(JSON.parse(layoutJson));\n if (!payload) return false;\n setState(prev => ({\n ...prev,\n gridRoot: payload.gridRoot,\n floating: payload.floating,\n minimized: payload.minimized,\n panels: payload.panels,\n draggedPanelId: null,\n activePanelId: payload.activePanelId\n }));\n return true;\n } catch (e) {\n console.error('Failed to parse layout configuration:', e);\n return false;\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 const findPanelId = useCallback((component: string, dedupeKey: string): string | null => {\n const match = Object.values(stateRef.current.panels).find(\n p => p.component === component && p.dedupeKey === dedupeKey\n );\n return match?.id ?? null;\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 customMenuGettersRef = useRef<Map<string, () => ContextMenuItem[]>>(new Map());\n\n const showContextMenuFnRef = useRef<((options: ShowContextMenuOptions) => void) | null>(null);\n const registerContextMenuFn = useCallback(\n (fn: (options: ShowContextMenuOptions) => void) => {\n showContextMenuFnRef.current = fn;\n return () => { showContextMenuFnRef.current = null; };\n }, []\n );\n const showContextMenu = useCallback((options: ShowContextMenuOptions) => {\n showContextMenuFnRef.current?.(options);\n }, []);\n\n const registerPanelContextMenu = useCallback(\n (panelId: string, getItems: () => ContextMenuItem[]) => {\n customMenuGettersRef.current.set(panelId, getItems);\n return () => { customMenuGettersRef.current.delete(panelId); };\n }, []\n );\n\n const getPanelContextMenuItems = useCallback(\n (panelId: string): ContextMenuItem[] =>\n customMenuGettersRef.current.get(panelId)?.() ?? [],\n []\n );\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 findPanelId,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n registerStateProvider,\n unregisterStateProvider,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection,\n registerPanelContextMenu,\n getPanelContextMenuItems,\n showContextMenu,\n registerContextMenuFn,\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 findPanelId,\n saveLayout,\n loadLayout,\n publish,\n subscribe,\n setDraggedPanelId,\n dockPanelToGroup,\n movePanelOrder,\n closeLeafGroup,\n registerCloseGuard,\n unregisterCloseGuard,\n registerStateProvider,\n unregisterStateProvider,\n setPanelDirty,\n updatePanelTitle,\n requestClosePanel,\n dockPanelToWorkspaceEdge,\n setActivePanel,\n setDirection,\n registerPanelContextMenu,\n getPanelContextMenuItems,\n showContextMenu,\n registerContextMenuFn,\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\n // Check 1: styles.css sentinel — catches the \"forgot to import\" case precisely\n try {\n const sentinel = getComputedStyle(document.documentElement)\n .getPropertyValue('--rdd-styles-loaded').trim();\n if (sentinel !== '1') {\n console.error(\n \"[react-dockable-desktop] styles.css is not imported.\\n\" +\n \"Add this to your entry file (main.tsx / index.tsx):\\n\" +\n \" import 'react-dockable-desktop/styles.css'\\n\" +\n \"Without it the workspace renders as a black screen with no console errors.\"\n );\n }\n } catch { /* getComputedStyle unavailable (SSR) */ }\n\n }, []);\n\n useEffect(() => {\n if (client) {\n client._connect(actions);\n return () => { client._disconnect(); };\n }\n }, [client, actions]);\n\n const syncContextValue = useMemo<WindowStoreSyncContextValue>(\n () => ({ getSnapshot, subscribeToState }),\n [getSnapshot, subscribeToState]\n );\n\n return (\n <StyleClassContext.Provider value={styleClasses}>\n <RegistryContext.Provider value={registry}>\n <WindowStoreSyncContext.Provider value={syncContextValue}>\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 </WindowStoreSyncContext.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 */\nconst noopSubscribe = (_cb: () => void): (() => void) => () => {};\n\nexport function useWindowManagerState(): WindowState;\nexport function useWindowManagerState<T>(selector: (state: WindowState) => T): T;\nexport function useWindowManagerState<T>(selector?: (state: WindowState) => T): WindowState | T {\n const stateCtx = useContext(WindowStateContext);\n const syncCtx = useContext(WindowStoreSyncContext);\n const selectorRef = useRef<((state: WindowState) => T) | undefined>(selector);\n selectorRef.current = selector;\n\n const syncResult = useSyncExternalStore(\n selector ? (syncCtx?.subscribeToState ?? noopSubscribe) : noopSubscribe,\n (): T => {\n const snap = syncCtx?.getSnapshot() ?? stateCtx!;\n return (selectorRef.current ? selectorRef.current(snap) : snap) as T;\n },\n (): T => {\n const snap = syncCtx?.getSnapshot() ?? stateCtx!;\n return (selectorRef.current ? selectorRef.current(snap) : snap) as T;\n }\n );\n\n if (!stateCtx) throw new Error('useWindowManagerState must be used within WindowManagerProvider');\n if (!selector) return stateCtx;\n return syncResult;\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 = (): MessageFormatter => {\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 = (): Pick<WindowActions, 'publish' | 'subscribe'> => {\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 = (): Record<PredefinedMessageKey, ContextMenuPredefinedMessage> => {\n return useContext(WindowPredefinedMessagesContext);\n};\n\n/**\n * React hook to retrieve the panel instance ID for the component currently rendered inside\n * the dockable desktop. Works for docked, floating, modal, and side-panel containers.\n * Opt-in — components that don't need the ID require no changes.\n *\n * @group Hooks\n * @returns The unique panel instance ID string.\n * @example\n * ```tsx\n * function MyPanel() {\n * const panelId = usePanelId();\n * const { closePanel } = useWindowManagerActions();\n * return <button onClick={() => closePanel(panelId)}>Close</button>;\n * }\n * ```\n */\nexport const usePanelId = (): string => useFormContainer().instanceId;\n\n/**\n * React hook for injecting custom context menu items into a panel's context menu from inside the panel component.\n * Items are dynamic — the array is re-read each time the menu opens, so state-driven changes (enable/disable, add/remove) work automatically.\n * The hook reads the panel ID internally via {@link usePanelId} — no prop needed.\n *\n * @param items - Array of `ContextMenuItem` entries (simple items, separators, submenus).\n * @example\n * ```tsx\n * import { usePanelContextMenu } from 'dockable-windows';\n *\n * function MyPanel() {\n * const [dirty, setDirty] = useState(false);\n * usePanelContextMenu([\n * { label: 'Save', action: () => save() },\n * { label: 'Revert', action: () => revert() },\n * ]);\n * return <Editor onChange={() => setDirty(true)} />;\n * }\n * ```\n */\nexport function usePanelContextMenu(items: ContextMenuItem[]): void {\n const ctx = useContext(WindowActionsContext);\n const panelId = usePanelId();\n const itemsRef = useRef(items);\n itemsRef.current = items;\n\n useEffect(() => {\n if (!ctx?.registerPanelContextMenu || !panelId) return;\n return ctx.registerPanelContextMenu(panelId, () => itemsRef.current);\n }, [panelId, ctx?.registerPanelContextMenu]);\n}\n","import { createContext, useContext, useSyncExternalStore, type Context, type Provider } 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 =\n | 'left-panel'\n | 'right-panel'\n | 'modal'\n | 'dockable-panel' // panel currently docked in the grid\n | 'floating-window' // panel currently in a detached floating window\n | '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 /**\n * Registers a callback reporting this panel's *current* restorable state, pulled fresh by\n * `WorkspaceClient.saveLayout()` every time it's called — for panels whose static open-time\n * props can't capture state accumulated after opening (scroll position, an in-progress edit, a\n * view-mode toggle). Only meaningful for docked/floating panels — left/right side panels and\n * modals already have a complete answer to this via `openLeftPanel`/`openRightPanel`/\n * `openModal`'s own `props` argument plus `updateInstance`, so this is `undefined` there.\n * The returned value must be synchronous — `saveLayout()` itself never returns a `Promise`.\n * Return `undefined` to fall back to the static `props` this panel was opened with.\n */\n registerStateProvider?: (getState: () => unknown) => (() => 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. Reflects the state at mount time; subscribe to {@link onContainerTypeChange} for live updates. */\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. Returns an unsubscribe function. */\n onResize?: (handler: (width: number, height: number) => void) => () => void;\n /** Request the container to minimize itself to the taskbar. No-op if the container type does not support minimize. */\n requestMinimize?: () => void;\n /** Returns the current rendered dimensions of this panel, or `null` if the panel has not been laid out yet. */\n getDimensions?: () => { width: number; height: number } | null;\n /**\n * Subscribe to this panel becoming the globally active panel.\n * Fires when `activePanelId` transitions to this panel's id.\n * Returns an unsubscribe function.\n */\n onActivate?: (handler: () => void) => () => void;\n /**\n * Subscribe to this panel losing active status.\n * Fires when `activePanelId` transitions away from this panel's id,\n * and also fires if the panel is destroyed while it is active.\n * Returns an unsubscribe function.\n */\n onDeactivate?: (handler: () => void) => () => void;\n /**\n * Subscribe to changes in the panel's container type (e.g. docked ↔ floating).\n * Does not fire for minimize/restore cycles — use {@link onMinimize} / {@link onRestore} for those.\n * Returns an unsubscribe function.\n */\n onContainerTypeChange?: (handler: (type: ContainerType) => 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 registerStateProvider: () => () => {},\n setTitle: () => {},\n setIcon: () => {},\n containerType: 'standalone',\n instanceId: 'standalone',\n onClose: () => () => {},\n onMinimize: () => () => {},\n onRestore: () => () => {},\n onResize: () => () => {},\n requestMinimize: () => {},\n getDimensions: () => null,\n onActivate: () => () => {},\n onDeactivate: () => () => {},\n onContainerTypeChange: () => () => {},\n};\n\n/**\n * Context that supplies the {@link FormContainerContract} to panels inside the Window Manager.\n */\nexport const FormContainerContext: Context<FormContainerContract> = createContext<FormContainerContract>(defaultContract);\nexport const FormContainerProvider: Provider<FormContainerContract> = FormContainerContext.Provider;\n\n/**\n * React hook to retrieve the current {@link FormContainerContract} from context.\n * Enables sub-forms to trigger close/minimize requests, mark themselves dirty,\n * rename their tabs, query dimensions, or subscribe to lifecycle events\n * (resize, close, minimize, restore, activate, deactivate, container-type changes).\n */\nexport const useFormContainer = (): FormContainerContract => {\n return useContext(FormContainerContext);\n};\n\n/**\n * Reactive alternative to calling {@link FormContainerContract.getDimensions} yourself.\n * Returns the panel's current `{ width, height }`, or `null` before it has been laid\n * out, and re-renders whenever the panel's rendered box changes — including resizes\n * caused by the workspace itself (a grid split being dragged, docking, floating, or\n * tab activation), not just resizes of an element the panel created.\n */\nexport const usePanelSize = (): { width: number; height: number } | null => {\n const { onResize, getDimensions } = useFormContainer();\n return useSyncExternalStore(\n (onStoreChange) => (onResize ? onResize(() => onStoreChange()) : () => {}),\n () => (getDimensions ? getDimensions() : null)\n );\n};\n","import type { ComponentType } from 'react';\nimport type { FloatAnchor } from './WindowManagerContext';\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 /** Corner of the workspace to anchor newly-opened floating windows to. */\n defaultAnchor?: FloatAnchor;\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: PanelRegistryClass = 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 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","import { isValidElement } from 'react';\n\n/**\n * Recursively checks whether a value can round-trip through `JSON.stringify`/`JSON.parse`\n * without silently losing information.\n *\n * Deliberately **not** a `JSON.stringify` try/catch — that call doesn't throw for the actual\n * failure case this guards against: a function-valued property is simply dropped by\n * `JSON.stringify`, not rejected. This walks the value tree instead, returning `false` as soon as\n * it finds a function, symbol, `undefined`, React element, or any non-plain object (a class\n * instance, `Map`, `Set`, `RegExp`, etc.).\n *\n * `Date` is treated as an explicit exception — serializable-enough, matching `JSON.stringify`'s\n * own behavior — even though it doesn't round-trip back to a `Date` instance on parse. That's a\n * smaller, more tolerable gotcha than a silently-vanishing function, so it's documented rather\n * than treated as a disqualifying case.\n *\n * Used to decide whether a docked/floating panel's `props` can be included in\n * `WorkspaceClient.saveLayout()`'s output — see {@link PanelInfo.serializable}.\n */\nexport function isSerializable(value: unknown): boolean {\n if (value === null) return true;\n if (value === undefined) return false;\n\n const type = typeof value;\n if (type === 'string' || type === 'number' || type === 'boolean') return true;\n if (type === 'function' || type === 'symbol' || type === 'bigint') return false;\n\n // type === 'object' from here on.\n if (value instanceof Date) return true;\n if (isValidElement(value)) return false;\n if (Array.isArray(value)) return value.every(isSerializable);\n\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return false; // class instance, Map, Set, RegExp, Error, etc.\n\n return Object.values(value as Record<string, unknown>).every(isSerializable);\n}\n","import React, {\n forwardRef,\n useImperativeHandle,\n useState,\n useRef,\n useEffect,\n useLayoutEffect,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport type { ContextMenuLabel, MessageFormatter, MenuItemAction } from './contextMenuTypes';\n\n// ─── Re-export shared primitives so callers don't need contextMenuTypes.ts ───\nexport type { ContextMenuLabel, MessageFormatter, MenuItemAction };\n\n// ─── Item type shapes (identical surface to former replace-react-contexify) ───\n\nexport interface ContextMenuCheckbox {\n /** Whether the checkbox column renders at all (default: true). */\n active?: boolean;\n /** Whether the item is interactive (default: true). Prefer top-level `disabled` on the item instead. */\n enabled?: boolean;\n /** Current checked state. */\n value: boolean;\n}\n\nexport interface ContextMenuSimpleItem {\n label: ContextMenuLabel;\n icon?: React.ReactNode;\n title?: ContextMenuLabel;\n checkbox?: ContextMenuCheckbox;\n action?: MenuItemAction;\n cyAction?: string;\n disabled?: boolean;\n}\n\nexport interface ContextMenuSeparator {\n separator: true;\n}\n\nexport interface ContextMenuSubMenu {\n label: ContextMenuLabel;\n title?: ContextMenuLabel;\n items?: ContextMenuItem[];\n}\n\nexport type ContextMenuItem = ContextMenuSimpleItem | ContextMenuSeparator | ContextMenuSubMenu;\n\n// ─── Imperative API ───────────────────────────────────────────────────────────\n\nexport interface ShowContextMenuOptions {\n event?: React.MouseEvent | React.TouchEvent | MouseEvent | TouchEvent;\n x?: number;\n y?: number;\n items: ContextMenuItem[];\n}\n\nexport interface ContextMenuHandle {\n show(options: ShowContextMenuOptions): void;\n}\n\n// ─── Component props ──────────────────────────────────────────────────────────\n\nexport interface ContextMenuProps {\n theme?: string;\n animation?: string;\n formatMessageProvider?: MessageFormatter;\n onShow?: () => void;\n onHide?: () => void;\n onOpenChange?: (open: boolean) => void;\n className?: string;\n style?: React.CSSProperties;\n}\n\n// ─── Adapter interface (strategy pattern) ────────────────────────────────────\n\nexport interface ContextMenuAdapter {\n Component: React.ForwardRefExoticComponent<\n ContextMenuProps & React.RefAttributes<ContextMenuHandle>\n >;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nfunction getCoords(\n event: ShowContextMenuOptions['event'],\n): { x: number; y: number } {\n if (!event) return { x: 0, y: 0 };\n if ('touches' in event && event.touches.length > 0) {\n return { x: event.touches[0].clientX, y: event.touches[0].clientY };\n }\n return { x: (event as MouseEvent).clientX, y: (event as MouseEvent).clientY };\n}\n\nfunction resolveLabel(label: ContextMenuLabel, fmt?: MessageFormatter): string {\n if (typeof label === 'string') return label;\n if (fmt) return fmt(label);\n return label.defaultMessage ?? label.id;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is ContextMenuSeparator {\n return 'separator' in item;\n}\n\nfunction isSubMenu(item: ContextMenuItem): item is ContextMenuSubMenu {\n return !isSeparator(item) && 'items' in item;\n}\n\n// ─── Sub-menu panel (one-level deep) ─────────────────────────────────────────\n\ninterface SubMenuPanelProps {\n items: ContextMenuItem[];\n x: number;\n y: number;\n theme: string;\n fmt?: MessageFormatter;\n onClose: () => void;\n onMouseEnter: () => void;\n onMouseLeave: () => void;\n}\n\nconst SubMenuPanel = forwardRef<HTMLDivElement, SubMenuPanelProps>(\n ({ items, x, y, theme, fmt, onClose, onMouseEnter, onMouseLeave }, ref) => {\n useLayoutEffect(() => {\n const el = (ref as React.RefObject<HTMLDivElement>)?.current;\n if (!el) return;\n const r = el.getBoundingClientRect();\n const PAD = 8;\n if (r.right > window.innerWidth - PAD) {\n el.style.left = `${Math.max(PAD, window.innerWidth - r.width - PAD)}px`;\n el.style.right = 'auto';\n }\n if (r.bottom > window.innerHeight - PAD) {\n el.style.top = `${Math.max(PAD, window.innerHeight - r.height - PAD)}px`;\n }\n if (r.left < PAD) { el.style.left = `${PAD}px`; el.style.right = 'auto'; }\n if (r.top < PAD) el.style.top = `${PAD}px`;\n });\n\n return createPortal(\n <div\n ref={ref}\n className={`rdd-context-menu rdd-context-menu--${theme} rdd-context-menu--submenu`}\n // z-index from .rdd-context-menu--submenu (+8501) — see the main menu's note below.\n style={{ position: 'fixed', left: x, top: y }}\n role=\"menu\"\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n >\n {items.map((item, i) => {\n if (isSeparator(item)) {\n return <hr key={i} className=\"rdd-context-menu__separator\" role=\"separator\" />;\n }\n const simple = item as ContextMenuSimpleItem;\n const showChk = simple.checkbox && simple.checkbox.active !== false;\n const isChecked = showChk && simple.checkbox!.value;\n const isDisabled = simple.disabled === true || (showChk ? simple.checkbox!.enabled === false : false);\n return (\n <button\n key={i}\n type=\"button\"\n className={`rdd-context-menu__item${isDisabled ? ' rdd-context-menu__item--disabled' : ''}`}\n title={simple.title ? resolveLabel(simple.title, fmt) : undefined}\n disabled={isDisabled}\n data-cy-action={simple.cyAction}\n onClick={() => { if (!isDisabled) { simple.action?.(); onClose(); } }}\n role=\"menuitem\"\n aria-checked={showChk ? isChecked : undefined}\n >\n {simple.icon\n ? <span className=\"rdd-context-menu__icon\">{simple.icon}</span>\n : <span className=\"rdd-context-menu__icon\" aria-hidden=\"true\" />}\n <span className=\"rdd-context-menu__label\">{resolveLabel(simple.label, fmt)}</span>\n {showChk && (\n <span className={`rdd-context-menu__checkbox${isChecked ? ' rdd-context-menu__checkbox--checked' : ''}`} aria-hidden=\"true\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"0.75\" y=\"0.75\" width=\"10.5\" height=\"10.5\" rx=\"2\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n {isChecked && (\n <path d=\"M2.5 6 L4.5 8.5 L9.5 3.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n )}\n </svg>\n </span>\n )}\n </button>\n );\n })}\n </div>,\n document.body,\n );\n },\n);\n\nSubMenuPanel.displayName = 'ContextMenuSubMenuPanel';\n\n// ─── Main component ───────────────────────────────────────────────────────────\n\ninterface MenuState {\n visible: boolean;\n x: number;\n y: number;\n items: ContextMenuItem[];\n}\n\nconst CLOSED: MenuState = { visible: false, x: 0, y: 0, items: [] };\n\nexport const ContextMenu: React.ForwardRefExoticComponent<ContextMenuProps & React.RefAttributes<ContextMenuHandle>> = forwardRef<ContextMenuHandle, ContextMenuProps>(\n ({ theme = 'dark', formatMessageProvider, onShow, onHide, onOpenChange, className, style }, ref) => {\n const [menuState, setMenuState] = useState<MenuState>(CLOSED);\n const [submenuIndex, setSubmenuIndex] = useState<number | null>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const submenuPanelRef = useRef<HTMLDivElement>(null);\n const itemRefs = useRef<Map<number, HTMLButtonElement | null>>(new Map());\n const timers = useRef<{\n open: ReturnType<typeof setTimeout> | null;\n close: ReturnType<typeof setTimeout> | null;\n }>({ open: null, close: null });\n\n const close = React.useCallback(() => {\n setMenuState(CLOSED);\n setSubmenuIndex(null);\n timers.current.open && clearTimeout(timers.current.open);\n timers.current.close && clearTimeout(timers.current.close);\n timers.current.open = null;\n timers.current.close = null;\n onHide?.();\n onOpenChange?.(false);\n }, [onHide, onOpenChange]);\n\n useImperativeHandle(ref, () => ({\n show({ event, x, y, items }) {\n const coords = event ? getCoords(event) : { x: x ?? 0, y: y ?? 0 };\n itemRefs.current.clear();\n setMenuState({ visible: true, x: coords.x, y: coords.y, items });\n setSubmenuIndex(null);\n onShow?.();\n onOpenChange?.(true);\n },\n }), [onShow, onOpenChange]);\n\n // Click-outside dismiss\n // Two listeners for full coverage:\n // pointerdown (capture) — fires before any canvas gesture handler; catches touch/stylus\n // click (bubble, window) — synthetic click survives stopPropagation on mousedown/pointerdown;\n // this is the reliable fallback for WebGL canvases (LuciadRIA, MapLibre, Three.js, etc.)\n useEffect(() => {\n if (!menuState.visible) return;\n const dismiss = (e: Event) => {\n if (menuRef.current?.contains(e.target as Node)) return;\n if (submenuPanelRef.current?.contains(e.target as Node)) return;\n close();\n };\n document.addEventListener('pointerdown', dismiss, { capture: true });\n window.addEventListener('click', dismiss);\n return () => {\n document.removeEventListener('pointerdown', dismiss, { capture: true });\n window.removeEventListener('click', dismiss);\n };\n }, [menuState.visible, close]);\n\n // Escape dismiss\n useEffect(() => {\n if (!menuState.visible) return;\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') close(); };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [menuState.visible, close]);\n\n // Viewport clamping for main menu\n useLayoutEffect(() => {\n if (!menuState.visible || !menuRef.current) return;\n const el = menuRef.current;\n const r = el.getBoundingClientRect();\n const PAD = 8;\n if (r.right > window.innerWidth - PAD) {\n el.style.left = `${Math.max(PAD, window.innerWidth - r.width - PAD)}px`;\n }\n if (r.bottom > window.innerHeight - PAD) {\n el.style.top = `${Math.max(PAD, window.innerHeight - r.height - PAD)}px`;\n }\n if (r.left < PAD) el.style.left = `${PAD}px`;\n if (r.top < PAD) el.style.top = `${PAD}px`;\n }, [menuState.visible]);\n\n if (!menuState.visible) return null;\n\n const fmt = formatMessageProvider;\n\n // Compute sub-menu anchor position\n let submenuX = 0;\n let submenuY = 0;\n if (submenuIndex !== null) {\n const itemEl = itemRefs.current.get(submenuIndex);\n if (itemEl) {\n const ir = itemEl.getBoundingClientRect();\n const rtl = document.documentElement.dir === 'rtl';\n submenuX = rtl ? window.innerWidth - ir.left + 2 : ir.right + 2;\n submenuY = ir.top;\n }\n }\n\n function cancelOpenTimer() {\n if (timers.current.open) {\n clearTimeout(timers.current.open);\n timers.current.open = null;\n }\n }\n function cancelCloseTimer() {\n if (timers.current.close) {\n clearTimeout(timers.current.close);\n timers.current.close = null;\n }\n }\n\n function handleItemMouseEnter(index: number, item: ContextMenuItem) {\n cancelCloseTimer();\n // Switching away from a different open sub-menu\n if (submenuIndex !== null && submenuIndex !== index) {\n cancelOpenTimer();\n setSubmenuIndex(null);\n }\n if (isSubMenu(item) && item.items?.length) {\n cancelOpenTimer();\n timers.current.open = setTimeout(() => {\n setSubmenuIndex(index);\n }, 150);\n } else if (!isSubMenu(item)) {\n // Non-sub-menu item: close any open sub-menu after grace period\n cancelOpenTimer();\n if (submenuIndex !== null) {\n timers.current.close = setTimeout(() => setSubmenuIndex(null), 200);\n }\n }\n }\n\n function handleItemMouseLeave(item: ContextMenuItem) {\n cancelOpenTimer();\n if (isSubMenu(item) && item.items?.length) {\n timers.current.close = setTimeout(() => setSubmenuIndex(null), 200);\n }\n }\n\n return createPortal(\n <>\n <div\n ref={menuRef}\n className={`rdd-context-menu rdd-context-menu--${theme}${className ? ` ${className}` : ''}`}\n // No inline z-index: .rdd-context-menu's own `calc(var(--rdd-z-base, 1000) + 8500)`\n // owns it, so a WindowManagerProvider's zIndexBase actually shifts this menu (an\n // inline value here silently overrode it). Resolves to the same 9500 by default.\n style={{ position: 'fixed', left: menuState.x, top: menuState.y, ...style }}\n role=\"menu\"\n aria-orientation=\"vertical\"\n >\n {menuState.items.map((item, i) => {\n if (isSeparator(item)) {\n return <hr key={i} className=\"rdd-context-menu__separator\" role=\"separator\" />;\n }\n\n if (isSubMenu(item)) {\n return (\n <button\n key={i}\n ref={el => { itemRefs.current.set(i, el); }}\n type=\"button\"\n className={`rdd-context-menu__item rdd-context-menu__item--has-submenu${submenuIndex === i ? ' rdd-context-menu__item--submenu-open' : ''}`}\n title={item.title ? resolveLabel(item.title, fmt) : undefined}\n onMouseEnter={() => handleItemMouseEnter(i, item)}\n onMouseLeave={() => handleItemMouseLeave(item)}\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={submenuIndex === i}\n >\n <span className=\"rdd-context-menu__icon\" aria-hidden=\"true\" />\n <span className=\"rdd-context-menu__label\">{resolveLabel(item.label, fmt)}</span>\n <span className=\"rdd-context-menu__chevron\" aria-hidden=\"true\">›</span>\n </button>\n );\n }\n\n const simple = item as ContextMenuSimpleItem;\n const showChk = simple.checkbox && simple.checkbox.active !== false;\n const isChecked = showChk && simple.checkbox!.value;\n const isDisabled = simple.disabled === true || (showChk ? simple.checkbox!.enabled === false : false);\n\n return (\n <button\n key={i}\n ref={el => { itemRefs.current.set(i, el); }}\n type=\"button\"\n className={`rdd-context-menu__item${isDisabled ? ' rdd-context-menu__item--disabled' : ''}`}\n title={simple.title ? resolveLabel(simple.title, fmt) : undefined}\n disabled={isDisabled}\n data-cy-action={simple.cyAction}\n onClick={() => { if (!isDisabled) { simple.action?.(); close(); } }}\n onMouseEnter={() => handleItemMouseEnter(i, item)}\n onMouseLeave={() => handleItemMouseLeave(item)}\n role=\"menuitem\"\n aria-checked={showChk ? isChecked : undefined}\n >\n {simple.icon\n ? <span className=\"rdd-context-menu__icon\">{simple.icon}</span>\n : <span className=\"rdd-context-menu__icon\" aria-hidden=\"true\" />}\n <span className=\"rdd-context-menu__label\">{resolveLabel(simple.label, fmt)}</span>\n {showChk && (\n <span className={`rdd-context-menu__checkbox${isChecked ? ' rdd-context-menu__checkbox--checked' : ''}`} aria-hidden=\"true\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"0.75\" y=\"0.75\" width=\"10.5\" height=\"10.5\" rx=\"2\"\n fill={isChecked ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n {isChecked && (\n <path d=\"M2.5 6 L4.5 8.5 L9.5 3.5\" stroke=\"white\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n )}\n </svg>\n </span>\n )}\n </button>\n );\n })}\n </div>\n\n {submenuIndex !== null && (() => {\n const sub = menuState.items[submenuIndex] as ContextMenuSubMenu;\n return (\n <SubMenuPanel\n ref={submenuPanelRef}\n items={sub.items ?? []}\n x={submenuX}\n y={submenuY}\n theme={theme}\n fmt={fmt}\n onClose={close}\n onMouseEnter={() => cancelCloseTimer()}\n onMouseLeave={() => {\n timers.current.close = setTimeout(() => setSubmenuIndex(null), 200);\n }}\n />\n );\n })()}\n </>,\n document.body,\n );\n },\n);\n\nContextMenu.displayName = 'ContextMenu';\n\n// ─── Default adapter ──────────────────────────────────────────────────────────\n\nexport const DefaultContextMenuAdapter: ContextMenuAdapter = {\n Component: ContextMenu,\n};\n\n// ─── ContextMenuContext ────────────────────────────────────────────────────────\n// Decouples menu placement from WindowManager. Any component that renders\n// <ContextMenuProvider> makes showContextMenu available to all descendants,\n// regardless of where it sits relative to WindowManager in the tree.\n\ninterface ContextMenuContextValue {\n show: (options: ShowContextMenuOptions) => void;\n isOpen: boolean;\n}\n\nconst ContextMenuContext: React.Context<ContextMenuContextValue | null> = React.createContext<ContextMenuContextValue | null>(null);\n\nexport const ContextMenuProvider: React.FC<{\n adapter?: ContextMenuAdapter;\n children: React.ReactNode;\n} & ContextMenuProps> = ({ adapter = DefaultContextMenuAdapter, children, ...componentProps }) => {\n const menuRef = useRef<ContextMenuHandle>(null);\n const [isOpen, setIsOpen] = React.useState(false);\n const show = React.useCallback((opts: ShowContextMenuOptions) => {\n menuRef.current?.show(opts);\n }, []);\n return (\n <ContextMenuContext.Provider value={{ show, isOpen }}>\n {children}\n <adapter.Component\n ref={menuRef}\n {...componentProps}\n onShow={() => { setIsOpen(true); componentProps.onShow?.(); }}\n onHide={() => { setIsOpen(false); componentProps.onHide?.(); }}\n />\n </ContextMenuContext.Provider>\n );\n};\n\nexport function useShowContextMenu(): (options: ShowContextMenuOptions) => void {\n const ctx = React.useContext(ContextMenuContext);\n if (!ctx) throw new Error('useShowContextMenu must be used within a ContextMenuProvider');\n return ctx.show;\n}\n\n// Exported for the WindowManager.tsx bridge only — not re-exported from src/index.ts\nexport { ContextMenuContext };\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 * CSS padding for the panel body content — a number (px) or any CSS value/shorthand\n * (e.g. `'10px 16px'`). Default: `0` (edge-to-edge) — pass `10` to restore the pre-v6.0.0\n * default, or any value your content needs.\n */\n bodyPadding?: 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 * CSS padding for the modal body content — a number (px) or any CSS value/shorthand\n * (e.g. `'10px 16px'`). Default: `0` (edge-to-edge) — pass `10` to restore the pre-v6.0.0\n * default, or any value your content needs.\n */\n bodyPadding?: number | string;\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({ preventScroll: true });\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=\"rdd-confirmation-form-body\">\n {alert && (\n <div className={`rdd-confirmation-alert rdd-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=\"rdd-confirmation-actions\">\n <button\n type=\"button\"\n className=\"rdd-btn rdd-btn-sm rdd-btn-outline\"\n onClick={handleCancel}\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n className=\"rdd-btn rdd-btn-sm rdd-btn-primary\"\n ref={confirmButtonRef}\n >\n {confirmLabel}\n </button>\n </div>\n </form>\n );\n};\n\nexport default ConfirmationForm;\n","import type { FloatAnchor } from './WindowManagerContext';\n\n/**\n * Mirrors a physical workspace corner to its horizontal opposite.\n *\n * Used only to translate a physically-hovered corner (raw pointer/screen\n * position, which CSS cannot reason about) into the logical `FloatAnchor`\n * value stored on a `FloatingWindow` under RTL. Render-time positioning\n * should use CSS logical properties (`insetInlineStart`/`insetInlineEnd`)\n * driven by the element's `dir` attribute instead of calling this.\n */\nexport function flipZoneHorizontal(zone: FloatAnchor): FloatAnchor {\n if (zone === 'top-left') return 'top-right';\n if (zone === 'top-right') return 'top-left';\n if (zone === 'bottom-left') return 'bottom-right';\n return 'bottom-left';\n}\n","/**\n * Shared pointer-drag-resize primitives.\n *\n * Extracted from four previously-independent implementations (the workspace grid\n * split resizer, the sidebar drawer resizer, and two floating-window resize-handle\n * implementations) that had quietly drifted apart in exactly the kind of detail\n * (an inline-style property present in one and missing in the other) that once\n * caused a real, user-visible bug. This file is the single place that mechanic now\n * lives, so it can't drift again.\n */\n\n// ── Pointer-capture drag mechanics ──────────────────────────────────────────\n\nexport interface PointerDragConfig<TStart> {\n /** The element to capture the pointer on — normally the handle the user grabbed. */\n element: HTMLElement;\n pointerId: number;\n /** The pointerdown event's clientX/clientY, used as the delta origin. */\n startClientX: number;\n startClientY: number;\n /** Snapshot whatever state the caller needs at drag start (sizes, positions, ...). */\n captureStart: () => TStart;\n /** Called on every pointermove with the delta from the drag's start position. */\n onMove: (dx: number, dy: number, start: TStart) => void;\n /** Called once when the drag ends (pointerup or pointercancel). */\n onEnd?: (start: TStart) => void;\n /** Classes toggled on the given elements for the duration of the drag. */\n activeClasses?: Array<{ el: HTMLElement; classes: string[] }>;\n}\n\n/**\n * Starts a pointer-capture-based drag: captures the pointer on `element`, tracks\n * movement via listeners scoped to that element's own lifetime (not `window`), and\n * cleans up automatically on release or cancel.\n */\nexport function startPointerDrag<TStart>(config: PointerDragConfig<TStart>): void {\n const { element, pointerId, startClientX, startClientY, captureStart, onMove, onEnd, activeClasses } = config;\n\n element.setPointerCapture(pointerId);\n activeClasses?.forEach(({ el, classes }) => el.classList.add(...classes));\n const start = captureStart();\n\n const handleMove = (e: PointerEvent) => {\n onMove(e.clientX - startClientX, e.clientY - startClientY, start);\n };\n\n const handleEnd = () => {\n activeClasses?.forEach(({ el, classes }) => el.classList.remove(...classes));\n element.removeEventListener('pointermove', handleMove);\n element.removeEventListener('pointerup', handleEnd);\n element.removeEventListener('pointercancel', handleEnd);\n onEnd?.(start);\n };\n\n element.addEventListener('pointermove', handleMove);\n element.addEventListener('pointerup', handleEnd);\n element.addEventListener('pointercancel', handleEnd);\n}\n\n// ── 8-directional resize math ────────────────────────────────────────────────\n\nexport type ResizeDir = 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw';\n\nexport interface ResizeRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface ResizeConstraints {\n minW: number;\n minH: number;\n /** Upper bound on width — only applies to eastward growth (dir includes 'e'). */\n maxW?: number;\n /** Upper bound on height — only applies to southward growth (dir includes 's'). */\n maxH?: number;\n /** Lower bound on the resulting x — only applies to westward growth (dir includes 'w'). */\n minX?: number;\n /** Lower bound on the resulting y — only applies to northward growth (dir includes 'n'). */\n minY?: number;\n}\n\n/**\n * Pure function computing the new rect for an 8-directional resize handle drag.\n *\n * `maxW`/`maxH` and `minX`/`minY` are independent, direction-scoped constraints\n * rather than one \"container bound\" — a resize toward the fixed edge (e/s) is\n * naturally bounded by a maximum dimension, while a resize toward the moving edge\n * (w/n) is naturally bounded by a minimum position, and the two calling sites this\n * was extracted from need different subsets of these (see WindowManager.tsx's\n * `startResize`, which omits all four and lets a window grow unbounded and be\n * dragged fully off-screen, vs. PanelOverlay.tsx's `handleResizePointerDown`, which\n * supplies all four to keep windows within their container).\n */\nexport function computeResizedRect(dir: ResizeDir, dx: number, dy: number, start: ResizeRect, constraints: ResizeConstraints): ResizeRect {\n const { minW, minH, maxW, maxH, minX, minY } = constraints;\n let { x, y, w, h } = start;\n\n if (dir.includes('e')) {\n w = Math.max(minW, Math.min(start.w + dx, maxW ?? Infinity));\n }\n if (dir.includes('w')) {\n const maxDx = start.w - minW; // largest rightward (shrinking) delta before hitting minW\n const minDx = minX != null ? -(start.x - minX) : -Infinity; // most negative (growing) delta before x hits minX\n const clampedDx = Math.max(minDx, Math.min(dx, maxDx));\n w = start.w - clampedDx;\n x = start.x + clampedDx;\n }\n if (dir.includes('s')) {\n h = Math.max(minH, Math.min(start.h + dy, maxH ?? Infinity));\n }\n if (dir.includes('n')) {\n const maxDy = start.h - minH;\n const minDy = minY != null ? -(start.y - minY) : -Infinity;\n const clampedDy = Math.max(minDy, Math.min(dy, maxDy));\n h = start.h - clampedDy;\n y = start.y + clampedDy;\n }\n\n return { x, y, w, h };\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * Reactively reads the workspace's current `data-color-scheme` attribute\n * (set on `document.documentElement` by `<WindowManager />`), returning\n * `'dark'` or `'light'` and re-rendering whenever it changes.\n *\n * Useful for panel content that needs to react to the same scheme the\n * workspace itself is using — e.g. swapping a map's tile layer or an\n * embedded editor's theme to match.\n */\nexport function useColorScheme(): 'dark' | 'light' {\n const [scheme, setScheme] = useState<'dark' | 'light'>(() =>\n document.documentElement.getAttribute('data-color-scheme') === 'light' ? 'light' : 'dark'\n );\n\n useEffect(() => {\n const updateScheme = () => {\n setScheme(document.documentElement.getAttribute('data-color-scheme') === 'light' ? 'light' : 'dark');\n };\n updateScheme();\n const observer = new MutationObserver(updateScheme);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-color-scheme'] });\n return () => observer.disconnect();\n }, []);\n\n return scheme;\n}\n","import type { ComponentType } from 'react';\nimport { PanelRegistryClass } from './components/PanelRegistry';\nimport type { PanelRegistryEntry } from './components/PanelRegistry';\nimport type {\n WindowActions,\n MessageFormatter,\n ContextMenuPredefinedMessage,\n DropPosition,\n SplitDirection,\n DirtyStateOptions,\n FloatingWindow,\n} from './components/WindowManagerContext';\nimport type { ShowContextMenuOptions } from './components/ContextMenu';\n\n/** Built-in lifecycle events always available on the WorkspaceClient event bus. */\nexport interface BuiltInPanelEvents {\n 'panel:opened': { id: string; component: string };\n 'panel:closed': { id: string };\n 'panel:minimized': { id: string };\n 'panel:restored': { id: string };\n /**\n * Fires whenever something `saveLayout()` would capture changes — open/close/minimize/restore,\n * and an `openPanel` `dedupeKey` redirect. Coalesces those into one signal for autosave-style\n * consumers, so they don't need to subscribe to four separate events. Does **not** cover a\n * `registerStateProvider` callback's return value changing on its own — that's a pull, there's\n * no way to observe it changing without the panel separately notifying — nor resize/split-ratio\n * drag/dock-rearrange, which have no hooks yet.\n */\n 'layout:changed': Record<string, never>;\n /**\n * Fires from inside `saveLayout()` itself, only when that specific call excluded at least one\n * panel (a panel whose current `props` — static or from a `registerStateProvider` — failed\n * {@link isSerializable}). A passive `PanelInfo.serializable` flag alone isn't enough for this:\n * nobody may be polling it at the exact moment a save happens and something silently drops out\n * (e.g. a floating window rendering data from a live class instance). This is deliberately just\n * a signal, not a UI opinion — decide for yourself whether that becomes a toast, a console\n * warning, or nothing.\n */\n 'layout:panels-excluded': { panels: { id: string; component: string }[] };\n}\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 * Parsed synchronously before the first render. The restored `activePanelId` is the one the\n * snapshot recorded, or — for layouts saved before that was persisted — the selected tab of\n * the first leaf in the grid.\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 * Fraction of the target panel the new panel takes when dropped on a panel's\n * top/bottom/left/right cross target. Range 0.1–0.9. Default: 0.5.\n */\n defaultSplitRatio?: number;\n /**\n * Fraction of the workspace the new panel takes when dropped on the workspace\n * outer edge. Range 0.1–0.9. Default: 0.2.\n */\n defaultEdgeSplitRatio?: number;\n /**\n * Starting z-index for floating windows and the library's own chrome overlays\n * (context menu, toolbar flyout, modal stack, toast, workspace edge zones),\n * all of which shift together via `--rdd-z-base`. Set this above/below a host\n * app's own modal z-index range to control stacking against it. Default: 1000.\n */\n zIndexBase?: number;\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. Duplicate `openPanel` calls for the same\n * ID are deduplicated while queued. Subscriptions made before mount are\n * buffered and re-registered on each connect/reconnect.\n *\n * @example\n * const workspace = new WorkspaceClient<MyEvents>({\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<TUserEvents extends Record<string, unknown> = Record<string, unknown>> {\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' | 'defaultSplitRatio' | 'defaultEdgeSplitRatio' | 'zIndexBase'>;\n\n private _actions: WindowActions | null = null;\n private _initialized = false;\n\n /** Calls queued before _connect() fires — replayed in order on first connect. */\n private _pendingCalls: Array<(actions: WindowActions) => void> = [];\n\n /** Tracks openPanel IDs in the pending queue to prevent duplicates before mount. */\n private _pendingOpenPanelIds = new Set<string>();\n\n /** Subscriptions buffered before connect — re-registered on every connect/reconnect. */\n private _pendingSubscriptions: Array<{\n event: string;\n callback: (data: unknown) => void;\n unsub: (() => void) | null;\n }> = [];\n\n /** Timer that emits an error if _connect() is never called with pending work. */\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 defaultSplitRatio: config.defaultSplitRatio,\n defaultEdgeSplitRatio: config.defaultEdgeSplitRatio,\n zIndexBase: config.zIndexBase,\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 if (!this._initialized) {\n this._initialized = true;\n }\n for (const entry of this._pendingSubscriptions) {\n entry.unsub = actions.subscribe(entry.event, entry.callback);\n }\n const pending = this._pendingCalls.splice(0);\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 for (const entry of this._pendingSubscriptions) {\n entry.unsub?.();\n entry.unsub = null;\n }\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 helpers ──────────────────────────────────────────────────────\n\n private _startWarnTimer(): void {\n if (this._disconnectedWarnTimer === null) {\n this._disconnectedWarnTimer = setTimeout(() => {\n if (!this.isConnected && this._pendingCalls.length > 0) {\n console.error(\n '[react-dockable-desktop] WorkspaceClient has ' + this._pendingCalls.length +\n ' queued call(s) but was never connected to a WindowManagerProvider. ' +\n 'Did you forget client={workspace} on <WindowManagerProvider>?'\n );\n }\n }, process.env.NODE_ENV === 'production' ? 5000 : 1000);\n }\n }\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 this._startWarnTimer();\n }\n }\n\n private _subscribeRaw(event: string, cb: (data: unknown) => void): () => void {\n if (this._actions) return this._actions.subscribe(event, cb);\n const entry = { event, callback: cb, unsub: null as (() => void) | null };\n this._pendingSubscriptions.push(entry);\n return () => {\n entry.unsub?.();\n entry.unsub = null;\n const idx = this._pendingSubscriptions.indexOf(entry);\n if (idx !== -1) this._pendingSubscriptions.splice(idx, 1);\n };\n }\n\n // ── Forwarding methods — mirrors the WindowActions public interface ────────\n\n openPanel(...args: Parameters<WindowActions['openPanel']>): void {\n if (this._actions) {\n this._actions.openPanel(...args);\n return;\n }\n const id = args[0];\n if (!this._pendingOpenPanelIds.has(id)) {\n this._pendingOpenPanelIds.add(id);\n this._pendingCalls.push(a => {\n this._pendingOpenPanelIds.delete(id);\n a.openPanel(...args);\n });\n this._startWarnTimer();\n }\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(...args: Parameters<WindowActions['restorePanel']>): void {\n this._dispatch(a => a.restorePanel(...args));\n }\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 /** Finds an already-open panel of the given component with a matching `dedupeKey` (set via\n * `openPanel`'s `dedupeKey` option). Returns `null` if none is open. */\n findPanelId(component: string, dedupeKey: string): string | null {\n return this._actions?.findPanelId(component, dedupeKey) ?? null;\n }\n\n saveLayout(): string { return this._actions?.saveLayout() ?? ''; }\n\n loadLayout(json: string): boolean {\n if (this._actions) return this._actions.loadLayout(json);\n this._pendingCalls.push(a => { a.loadLayout(json); });\n return false;\n }\n\n setDirection(dir: 'ltr' | 'rtl'): void { this._dispatch(a => a.setDirection(dir)); }\n\n /** Updates the split-size fractions at the given grid path. */\n updateSplitSizes(path: number[], sizes: number[]): void {\n this._dispatch(a => a.updateSplitSizes(path, sizes));\n }\n\n /** Updates position/size/anchor of a floating panel. */\n updateFloatingPosition(id: string, updates: Partial<Pick<FloatingWindow, 'x' | 'y' | 'width' | 'height' | 'anchor'>>): void {\n this._dispatch(a => a.updateFloatingPosition(id, updates));\n }\n\n /** @internal Drives the drag-in-progress visual state; normally only the library's own drag UI calls this. */\n setDraggedPanelId(id: string | null): void { this._dispatch(a => a.setDraggedPanelId(id)); }\n\n /** Docks a panel into an existing leaf group at the given drop position. */\n dockPanelToGroup(id: string, targetLeafId: string, position: DropPosition): void {\n this._dispatch(a => a.dockPanelToGroup(id, targetLeafId, position));\n }\n\n /** Reorders a panel's tab within its leaf group. */\n movePanelOrder(panelId: string, targetLeafId: string, targetIndex: number): void {\n this._dispatch(a => a.movePanelOrder(panelId, targetLeafId, targetIndex));\n }\n\n /** Closes an entire leaf group (all of its tabs) at once. */\n closeLeafGroup(leafId: string): void { this._dispatch(a => a.closeLeafGroup(leafId)); }\n\n /** Registers a guard that can veto closing the given panel. */\n registerCloseGuard(id: string, guard: () => boolean | Promise<boolean>): void {\n this._dispatch(a => a.registerCloseGuard(id, guard));\n }\n\n /** Removes a previously registered close guard. */\n unregisterCloseGuard(id: string): void { this._dispatch(a => a.unregisterCloseGuard(id)); }\n\n /** Registers a callback reporting a panel's current restorable state, pulled fresh on every\n * `saveLayout()` call — see {@link BuiltInPanelEvents}'s `'layout:panels-excluded'` doc and\n * `FormContainerContract.registerStateProvider`. */\n registerStateProvider(id: string, provider: () => unknown): void {\n this._dispatch(a => a.registerStateProvider(id, provider));\n }\n\n /** Removes a previously registered state provider. */\n unregisterStateProvider(id: string): void { this._dispatch(a => a.unregisterStateProvider(id)); }\n\n /** Sets/clears a panel's dirty (unsaved changes) flag. */\n setPanelDirty(id: string, dirty: boolean, options?: DirtyStateOptions): void {\n this._dispatch(a => a.setPanelDirty(id, dirty, options));\n }\n\n /** Updates a panel's displayed title. */\n updatePanelTitle(id: string, title: string | ContextMenuPredefinedMessage): void {\n this._dispatch(a => a.updatePanelTitle(id, title));\n }\n\n /**\n * Requests that a panel close, honoring its dirty flag and any registered close guard.\n * Resolves once the close (or user cancellation) has been resolved.\n *\n * @remarks If called before the provider mounts, the request is queued and this\n * returns an already-resolved promise immediately — the caller can't observe the\n * eventual outcome of a queued call, only that the request was accepted.\n */\n requestClosePanel(id: string, options?: { force?: boolean; onConfirm?: (opts?: DirtyStateOptions) => Promise<boolean> }): Promise<void> {\n if (this._actions) return this._actions.requestClosePanel(id, options);\n this._pendingCalls.push(a => { a.requestClosePanel(id, options); });\n return Promise.resolve();\n }\n\n /** Docks a panel to one of the workspace's outer edges. */\n dockPanelToWorkspaceEdge(id: string, position: SplitDirection): void {\n this._dispatch(a => a.dockPanelToWorkspaceEdge(id, position));\n }\n\n /** Shows a context menu using the app's configured ContextMenuAdapter. */\n showContextMenu(options: ShowContextMenuOptions): void { this._dispatch(a => a.showContextMenu(options)); }\n\n // ── Typed event bus ───────────────────────────────────────────────────────\n\n publish<K extends keyof (TUserEvents & BuiltInPanelEvents)>(\n event: K,\n data: (TUserEvents & BuiltInPanelEvents)[K]\n ): void {\n this._dispatch(a => a.publish(event as string, data));\n }\n\n subscribe<K extends keyof (TUserEvents & BuiltInPanelEvents)>(\n event: K,\n callback: (data: (TUserEvents & BuiltInPanelEvents)[K]) => void\n ): () => void {\n return this._subscribeRaw(event as string, callback as (data: unknown) => void);\n }\n\n // ── Lifecycle callbacks ───────────────────────────────────────────────────\n\n /** Subscribe to panel open events. Fires only for newly created panels. */\n onPanelOpen(callback: (id: string, component: string) => void): () => void {\n return this._subscribeRaw('panel:opened', data => {\n const d = data as BuiltInPanelEvents['panel:opened'];\n callback(d.id, d.component);\n });\n }\n\n /** Subscribe to panel close events. */\n onPanelClose(callback: (id: string) => void): () => void {\n return this._subscribeRaw('panel:closed', data => {\n callback((data as BuiltInPanelEvents['panel:closed']).id);\n });\n }\n\n /** Subscribe to panel minimize events. */\n onPanelMinimize(callback: (id: string) => void): () => void {\n return this._subscribeRaw('panel:minimized', data => {\n callback((data as BuiltInPanelEvents['panel:minimized']).id);\n });\n }\n\n /** Subscribe to panel restore events. */\n onPanelRestore(callback: (id: string) => void): () => void {\n return this._subscribeRaw('panel:restored', data => {\n callback((data as BuiltInPanelEvents['panel:restored']).id);\n });\n }\n\n /** Subscribe to the coalesced layout-change signal — see {@link BuiltInPanelEvents}'s\n * `'layout:changed'` doc for exactly what it covers (and doesn't). */\n onLayoutChanged(callback: () => void): () => void {\n return this._subscribeRaw('layout:changed', () => callback());\n }\n\n /** Subscribe to notification that a `saveLayout()` call excluded one or more panels because\n * their current props weren't serializable — see {@link BuiltInPanelEvents}'s\n * `'layout:panels-excluded'` doc. */\n onPanelsExcluded(callback: (panels: { id: string; component: string }[]) => void): () => void {\n return this._subscribeRaw('layout:panels-excluded', data => {\n callback((data as BuiltInPanelEvents['layout:panels-excluded']).panels);\n });\n }\n}\n","import React, { useContext } from 'react';\nimport { WindowManagerProvider } from './WindowManagerContext';\nimport type { WindowManagerProviderProps } from './WindowManagerContext';\nimport { PanelProvider } from './PanelProviderContext';\nimport { ToolbarProvider } from './ToolbarContext';\nimport { PanelContributionProvider } from './PanelContributionContext';\nimport { ContextMenuContext, ContextMenuProvider, DefaultContextMenuAdapter } from './ContextMenu';\nimport type { ContextMenuAdapter } from './ContextMenu';\n\n/**\n * Props for `<DockableDesktopProvider>`.\n * Extends `WindowManagerProviderProps` with workspace-level context menu configuration.\n */\nexport interface DockableDesktopProviderProps extends WindowManagerProviderProps {\n /**\n * Context menu adapter for the workspace-level `ContextMenuProvider`.\n * Defaults to `DefaultContextMenuAdapter`. Ignored if a `<ContextMenuProvider>`\n * already exists above `<DockableDesktopProvider>` in the tree.\n */\n contextMenuAdapter?: ContextMenuAdapter;\n}\n\n/**\n * Composite provider that wraps `WindowManagerProvider`, `PanelProvider`, `ToolbarProvider`,\n * and `PanelContributionProvider` in the correct order, and mounts the workspace-level\n * `ContextMenuProvider` so that\n * `showContextMenu()` and `useShowContextMenu()` work from any component in the tree —\n * including siblings of `<WindowManager>` such as `<Sidebar>`, `<SidePanelRenderer>`,\n * and `<ModalStackRenderer>`.\n *\n * Drop-in replacement for manually nesting both providers.\n *\n * `WindowManagerProvider` and `PanelProvider` remain independently exported\n * for cases that require custom nesting or separate configuration.\n *\n * @example\n * ```tsx\n * <DockableDesktopProvider client={workspace}>\n * <Sidebar>\n * <WindowManager />\n * </Sidebar>\n * <SidePanelRenderer />\n * <ModalStackRenderer />\n * </DockableDesktopProvider>\n * ```\n */\nexport const DockableDesktopProvider: React.FC<DockableDesktopProviderProps> = (\n { contextMenuAdapter = DefaultContextMenuAdapter, ...props }\n): React.ReactElement => {\n const existingCtxMenu = useContext(ContextMenuContext);\n\n const inner = (\n <ToolbarProvider>\n <WindowManagerProvider {...props}>\n <PanelContributionProvider>\n <PanelProvider>\n {props.children}\n </PanelProvider>\n </PanelContributionProvider>\n </WindowManagerProvider>\n </ToolbarProvider>\n );\n\n if (existingCtxMenu !== null) return inner;\n\n return (\n <ContextMenuProvider\n adapter={contextMenuAdapter}\n formatMessageProvider={props.formatMessage}\n >\n {inner}\n </ContextMenuProvider>\n );\n};\n\nexport default DockableDesktopProvider;\n","/**\n * @file ToolbarContext.tsx\n * @description Toolbar state context — radio group selection and toggle modifier state.\n * Provided by DockableDesktopProvider; consumed via useToolbar() from anywhere in the tree.\n */\n\nimport React, { createContext, useContext, useMemo, useState } from 'react';\n\nexport interface ToolbarContextValue {\n /** Returns the active item id in a radio group, or null if none. */\n getActiveInGroup: (group: string) => string | null;\n /** Set the active item in a radio group (pass null to deselect all). */\n setActiveInGroup: (group: string, id: string | null) => void;\n /** Returns whether a toggle modifier is currently active. */\n isModifierActive: (id: string) => boolean;\n /** Explicitly set a toggle modifier's active state. */\n setModifierActive: (id: string, active: boolean) => void;\n /** Flip a toggle modifier between active and inactive. */\n toggleModifier: (id: string) => void;\n}\n\nconst ToolbarContext = createContext<ToolbarContextValue | null>(null);\n\nexport const ToolbarProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const [radioGroups, setRadioGroups] = useState<Record<string, string | null>>({});\n const [modifiers, setModifiers] = useState<Record<string, boolean>>({});\n\n const value = useMemo<ToolbarContextValue>(() => ({\n getActiveInGroup: (group) => radioGroups[group] ?? null,\n setActiveInGroup: (group, id) => setRadioGroups(prev => ({ ...prev, [group]: id })),\n isModifierActive: (id) => modifiers[id] ?? false,\n setModifierActive: (id, active) => setModifiers(prev => ({ ...prev, [id]: active })),\n toggleModifier: (id) => setModifiers(prev => ({ ...prev, [id]: !prev[id] })),\n }), [radioGroups, modifiers]);\n\n return <ToolbarContext.Provider value={value}>{children}</ToolbarContext.Provider>;\n};\n\n/**\n * Returns toolbar state and control functions from anywhere inside\n * a `<DockableDesktopProvider>` tree.\n *\n * @throws Error if used outside of a {@link DockableDesktopProvider}.\n */\nexport function useToolbar(): ToolbarContextValue {\n const ctx = useContext(ToolbarContext);\n if (!ctx) throw new Error('useToolbar must be used within DockableDesktopProvider');\n return ctx;\n}\n","/**\n * @file PanelContributionContext.tsx\n * @description Lets any panel publish toolbar items and/or sidebar sections that\n * should only be surfaced while it is the globally active panel (`state.activePanelId`).\n * Optional, additive module — `DockableDesktopProvider` wires it up automatically.\n * Neither `<Toolbar>` nor `<Sidebar>` reads from this automatically; the app shell\n * merges `useActivePanelContribution()`'s result into its own `items`/`tabs` calls.\n */\n\nimport React, { createContext, useCallback, useContext, useLayoutEffect, useMemo, useRef, useSyncExternalStore } from 'react';\nimport type { ToolbarItem } from './Toolbar';\nimport type { SidebarTab } from './Sidebar';\nimport { usePanelId, useWindowManagerState } from './WindowManagerContext';\n\n/** A single named, labeled slot of content a panel contributes to the app's Sidebar while active. */\nexport interface PanelSidebarSection {\n id: string;\n label: string;\n icon?: React.ReactNode;\n content: React.ReactNode;\n}\n\n/**\n * What a panel publishes via `usePanelContribution()`. Both fields are optional and\n * independent — a panel may contribute only toolbar items, only sidebar sections,\n * both, or neither. The app decides what \"toolbar items\" and \"sidebar sections\" mean\n * for its own domain (map controls, document formatting, anything else).\n */\nexport interface PanelContribution {\n toolbarItems?: ToolbarItem[];\n sidebarSections?: PanelSidebarSection[];\n}\n\ntype Listener = () => void;\n\ninterface PanelContributionStore {\n publish(panelId: string, contribution: PanelContribution): () => void;\n get(panelId: string): PanelContribution | null;\n subscribe(listener: Listener): () => void;\n}\n\nfunction createPanelContributionStore(): PanelContributionStore {\n const contributions = new Map<string, PanelContribution>();\n const listeners = new Set<Listener>();\n const notify = () => listeners.forEach(l => l());\n\n return {\n publish(panelId, contribution) {\n contributions.set(panelId, contribution);\n notify();\n return () => {\n // Only clear if nothing else re-published for this id in the meantime.\n if (contributions.get(panelId) === contribution) {\n contributions.delete(panelId);\n notify();\n }\n };\n },\n get(panelId) {\n return contributions.get(panelId) ?? null;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\nconst PanelContributionContext = createContext<PanelContributionStore | null>(null);\n\n/**\n * Provider enabling `usePanelContribution()` / `useActivePanelContribution()`.\n * Mounted automatically by `DockableDesktopProvider` — only needed manually when\n * composing `WindowManagerProvider` directly without it.\n */\nexport const PanelContributionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const store = useMemo(() => createPanelContributionStore(), []);\n return <PanelContributionContext.Provider value={store}>{children}</PanelContributionContext.Provider>;\n};\n\n/**\n * Publish this panel's toolbar items and/or sidebar sections. Call on every render —\n * republishes automatically whenever `contribution` changes, and is cleared when the\n * panel unmounts. Memoize the object (and its array/callback contents, e.g. with\n * `useMemo`/`useCallback`) to avoid republishing on every unrelated re-render.\n *\n * Contributions are only ever surfaced while this panel is `state.activePanelId` —\n * see `useActivePanelContribution()`.\n *\n * @throws Error if used outside of a {@link PanelContributionProvider}.\n * @example\n * function MapPanel() {\n * const [controller, setController] = useState<'pan' | 'draw' | 'measure'>('pan');\n * usePanelContribution({\n * toolbarItems: (['pan', 'draw', 'measure'] as const).map(id => ({\n * type: 'toggle', id, label: id, icon: icons[id],\n * active: controller === id, onToggle: () => setController(id),\n * })),\n * sidebarSections: [{ id: 'layers', label: 'Layers', content: <LayerList /> }],\n * });\n * // ...\n * }\n */\nexport function usePanelContribution(contribution: PanelContribution): void {\n const panelId = usePanelId();\n const store = useContext(PanelContributionContext);\n const cleanupRef = useRef<(() => void) | null>(null);\n\n if (!store) throw new Error('usePanelContribution must be used within PanelContributionProvider');\n\n useLayoutEffect(() => {\n if (!store) return;\n cleanupRef.current?.();\n cleanupRef.current = store.publish(panelId, contribution);\n return () => {\n cleanupRef.current?.();\n cleanupRef.current = null;\n };\n }, [store, panelId, contribution]);\n}\n\n/**\n * Returns whatever the currently active panel (`state.activePanelId`) has published\n * via `usePanelContribution()`, or `null` if no panel is active or the active panel\n * hasn't contributed anything. Intended for the app shell to merge into its own\n * `<Toolbar items={...}>` / `<Sidebar tabs={...}>` calls.\n *\n * @throws Error if used outside of a {@link PanelContributionProvider}.\n */\nexport function useActivePanelContribution(): PanelContribution | null {\n const activePanelId = useWindowManagerState(s => s.activePanelId);\n const store = useContext(PanelContributionContext);\n\n if (!store) throw new Error('useActivePanelContribution must be used within PanelContributionProvider');\n\n const subscribe = useCallback(\n (onChange: Listener) => (store ? store.subscribe(onChange) : () => {}),\n [store]\n );\n const getSnapshot = () => (store && activePanelId ? store.get(activePanelId) : null);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Converts a contributed sidebar section into a `SidebarTab` for `<Sidebar tabs={...}>`.\n * `SidebarTab.icon` is optional but recommended unless the tab is `hidden`; supply\n * `fallbackIcon` for sections that omit one.\n * `eagerMount`/`preserveState` have no contribution-side equivalent — a contribution\n * only exists while its owning panel is mounted and active, so both are left unset.\n */\nexport function sidebarSectionToTab(section: PanelSidebarSection, fallbackIcon: React.ReactNode = null): SidebarTab {\n return {\n id: section.id,\n label: section.label,\n icon: section.icon ?? fallbackIcon,\n renderContent: () => section.content,\n };\n}\n\n/**\n * Convenience wrapper around `useActivePanelContribution()` for the common case:\n * append the active panel's contributed toolbar items (behind a separator) to a\n * static list. Returns `staticItems` unchanged when there's nothing to add.\n * For manual control (a different merge position, no separator, etc.), call\n * `useActivePanelContribution()` directly instead.\n */\nexport function useMergedToolbarItems(staticItems: ToolbarItem[]): ToolbarItem[] {\n const active = useActivePanelContribution();\n return active?.toolbarItems?.length\n ? [...staticItems, { type: 'separator' }, ...active.toolbarItems]\n : staticItems;\n}\n\n/**\n * Convenience wrapper around `useActivePanelContribution()` for the common case:\n * append the active panel's contributed sidebar sections (via `sidebarSectionToTab`)\n * to a static tab list, as dynamic tabs that appear only while their panel is active.\n * Returns `staticTabs` unchanged when there's nothing to add.\n */\nexport function useMergedSidebarTabs(staticTabs: SidebarTab[], fallbackIcon: React.ReactNode = null): SidebarTab[] {\n const active = useActivePanelContribution();\n return active?.sidebarSections?.length\n ? [...staticTabs, ...active.sidebarSections.map(section => sidebarSectionToTab(section, fallbackIcon))]\n : staticTabs;\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 type { DirtyStateOptions } from './dirtyOptions';\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?: DirtyStateOptions) => 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 ? `rdd-modal-size-${modalOptions.size}` : 'rdd-modal-size-auto';\n const showCloseButton = modalOptions.closable !== false;\n\n const bodyPadding = modalOptions.bodyPadding;\n const bodyPaddingStyle = bodyPadding != null\n ? (typeof bodyPadding === 'number' ? `${bodyPadding}px` : bodyPadding)\n : undefined;\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 // Reads the same --rdd-z-base a WindowManagerProvider's zIndexBase config mirrors\n // onto documentElement (falls back to 1000 so this also works standalone, with\n // no WindowManager mounted, matching the :root default in index.css).\n const modalZIndex = `calc(var(--rdd-z-base, 1000) + 9000 + ${index * 10})`;\n\n return (\n <div className=\"rdd-modal-overlay\" style={{ zIndex: modalZIndex }} dir={dir}>\n <div className=\"rdd-modal-curtain\" onClick={showCloseButton ? () => handleClose() : undefined} />\n <div className={`rdd-modal-window ${sizeClass} ${modalClass ?? ''}`}>\n <div className=\"rdd-modal-header\">\n {icon && <div className=\"rdd-modal-icon\">{icon}</div>}\n <h4 className=\"rdd-modal-title\">{displayTitle}</h4>\n {showCloseButton && (\n <button\n className=\"rdd-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\n className={`rdd-modal-body ${modalBodyClass ?? ''}`}\n style={bodyPaddingStyle != null ? { padding: bodyPaddingStyle } : undefined}\n >\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 type { DirtyStateOptions } from './dirtyOptions';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\nimport { useContainerRect, type ContainerRect } from '../hooks/useContainerRect';\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 /** On-screen rect of the app's own container, or null to default to the full viewport. */\n containerRect: ContainerRect | null;\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, containerRect }) => {\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?: DirtyStateOptions) => 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 const bodyPadding = panelOptions.bodyPadding;\n const bodyPaddingStyle = bodyPadding != null\n ? (typeof bodyPadding === 'number' ? `${bodyPadding}px` : bodyPadding)\n : undefined;\n\n return (\n <div\n className={`rdd-side-panel rdd-side-panel-${position} rdd-side-panel-visible ${sidePanelClass ?? ''}`}\n style={{\n width: widthStyle,\n ...(containerRect ? {\n top: containerRect.top,\n height: containerRect.height,\n bottom: 'auto',\n ...(position === 'right' ? { right: containerRect.right } : { left: containerRect.left }),\n } : {}),\n }}\n dir={dir}\n >\n <div className=\"rdd-side-panel-window\">\n <div className=\"rdd-side-panel-header\">\n {icon && <div className=\"rdd-side-panel-icon\">{icon}</div>}\n <h4 className=\"rdd-side-panel-title\">{displayTitle}</h4>\n <button\n className=\"rdd-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\n className={`rdd-side-panel-body ${sidePanelBodyClass ?? ''}`}\n style={bodyPaddingStyle != null ? { padding: bodyPaddingStyle } : undefined}\n >\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 * Renders an always-present, zero-footprint anchor (`display: contents` — no box\n * of its own, no layout/visual effect) so its parent element — the container the\n * consuming app actually placed the workspace into — can be measured via\n * {@link useContainerRect}, independent of whether any panel is currently open.\n */\nconst SidePanelAnchor: React.FC<{ children: (containerRect: ContainerRect | null) => React.ReactNode }> = ({ children }) => {\n const anchorRef = useRef<HTMLDivElement>(null);\n const containerRect = useContainerRect(anchorRef);\n return <div ref={anchorRef} style={{ display: 'contents' }}>{children(containerRect)}</div>;\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 <SidePanelAnchor>\n {(containerRect) => (\n <>\n {leftPanel && <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} containerRect={containerRect} />}\n {rightPanel && <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} containerRect={containerRect} />}\n </>\n )}\n </SidePanelAnchor>\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 return (\n <SidePanelAnchor>\n {(containerRect) => leftPanel ? <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} containerRect={containerRect} /> : null}\n </SidePanelAnchor>\n );\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 return (\n <SidePanelAnchor>\n {(containerRect) => rightPanel ? <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} containerRect={containerRect} /> : null}\n </SidePanelAnchor>\n );\n};\n\nexport default SidePanelRenderer;\n","import { useLayoutEffect, useState, type RefObject } from 'react';\n\n/** On-screen rect of a container, in the coordinate system `position: fixed` uses. */\nexport interface ContainerRect {\n top: number;\n left: number;\n /** Distance from the viewport's right edge — what CSS `right` expects for `position: fixed`. */\n right: number;\n height: number;\n}\n\n/**\n * Tracks the live on-screen rect of `anchorRef.current`'s parent element.\n *\n * Used to keep a `position: fixed` overlay (side panel) visually confined to\n * whatever container the consuming app actually placed the workspace into,\n * instead of defaulting to the full browser viewport. `position: fixed` is\n * required so the overlay never contributes scrollable overflow to any\n * ancestor (see the side-panel autofocus scroll-jump fix), but that means it\n * no longer inherits containment from a `position: relative` ancestor the way\n * `position: absolute` did — this hook restores that containment by measuring\n * it directly. For a full-viewport app the measured rect equals the viewport,\n * so this is a no-op change from the app's perspective.\n */\nexport function useContainerRect(anchorRef: RefObject<HTMLElement | null>): ContainerRect | null {\n const [rect, setRect] = useState<ContainerRect | null>(null);\n\n useLayoutEffect(() => {\n const container = anchorRef.current?.parentElement;\n if (!container) return;\n\n const measure = () => {\n const r = container.getBoundingClientRect();\n setRect({ top: r.top, left: r.left, right: window.innerWidth - r.right, height: r.height });\n };\n measure();\n\n const resizeObserver = new ResizeObserver(measure);\n resizeObserver.observe(container);\n window.addEventListener('resize', measure);\n\n return () => {\n resizeObserver.disconnect();\n window.removeEventListener('resize', measure);\n };\n }, [anchorRef]);\n\n return rect;\n}\n","/**\n * @file Sidebar.tsx\n * @description Sidebar activity bar (strip) and resizable content drawer.\n * The strip and drawer are independently controllable via `visible` and\n * `stripVisible`. Drawer width is pixel-based and user-draggable using the\n * same pointer-capture interaction as the panel grid resizer.\n */\n\nimport React, {\n useState,\n useEffect,\n useRef,\n useCallback,\n useImperativeHandle,\n useContext,\n useMemo,\n createContext,\n forwardRef,\n memo,\n} from 'react';\nimport { startPointerDrag } from './dragResize';\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 /** Required unless `hidden` is true — a hidden tab never renders a rail button, so it has no icon to show. */\n icon?: React.ReactNode;\n /**\n * Omit this tab's rail button entirely — no icon, no click target — while it\n * remains fully openable via `openTab()` / `useSidebar().openTab()` / a controlled\n * `activeTabId`. Use for menu-driven panels with no persistent icon (e.g. a\n * Google-Maps-style hamburger that opens content not otherwise pinned to the rail).\n * Default: false\n */\n hidden?: boolean;\n /**\n * Mount immediately when the Sidebar first renders, not on first user click.\n * Implies `preserveState: true`.\n * Default: false\n */\n eagerMount?: boolean;\n /**\n * Keep the component alive behind `display: none` when closed instead of\n * unmounting it. Use for panels with expensive local state.\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\n */\n renderContent: (tabId: string, onClose: () => void, onOpen: () => void) => React.ReactNode;\n}\n\n/**\n * Simple case for `SidebarProps.headerAction`/`footerAction`: the library renders a\n * default-styled icon button (visually consistent with the regular tab buttons) and forwards\n * the click.\n */\nexport interface SidebarHeaderActionButton {\n /** Only needed when used inside a `SidebarRailEntry[]` array, for the React key. */\n id?: string;\n icon: React.ReactNode;\n /** Tooltip and aria-label — same convention as `SidebarTab.label`. */\n label: string;\n onClick: () => void;\n disabled?: boolean;\n}\n\n/**\n * Full-control case for `SidebarProps.headerAction`/`footerAction`: the consumer supplies their\n * own markup (a Material UI `IconButton`, a Bootstrap `Button`, a Tailwind-styled `<button>`, or\n * anything else) wholesale. The library renders exactly what this returns, unwrapped, so the\n * consumer's own hover/active/focus/ripple behavior and click handling are untouched.\n */\nexport interface SidebarHeaderActionCustom {\n /** Only needed when used inside a `SidebarRailEntry[]` array, for the React key. */\n id?: string;\n render: () => React.ReactNode;\n}\n\n/**\n * A single, non-toggling action button shown above the tab strip (e.g. a hamburger menu).\n * Unlike `SidebarTab`, it never affects `activeTabId` or the drawer — the library only renders\n * it and forwards the click; what happens next (opening a side panel, a modal, anything else)\n * is entirely up to the consumer.\n */\nexport type SidebarHeaderAction = SidebarHeaderActionButton | SidebarHeaderActionCustom;\n\n/**\n * A single entry inside `SidebarProps.headerAction`/`footerAction` when used as an array: either\n * a non-toggling action button/custom render (see `SidebarHeaderAction`), or a real `SidebarTab`\n * that behaves exactly like a main-list tab — it mounts, activates, and closes through the same\n * lifecycle, so e.g. a \"Settings\" entry pinned to the footer can expand like any other tab.\n */\nexport type SidebarRailEntry = SidebarTab | SidebarHeaderActionButton | SidebarHeaderActionCustom;\n\nfunction isRailTab(entry: SidebarRailEntry): entry is SidebarTab {\n return 'renderContent' in entry;\n}\n\nfunction isRailCustom(entry: SidebarRailEntry): entry is SidebarHeaderActionCustom {\n return 'render' in entry;\n}\n\nfunction toRailArray(value: SidebarRailEntry | SidebarRailEntry[] | undefined): SidebarRailEntry[] {\n if (value == null) return [];\n return Array.isArray(value) ? value : [value];\n}\n\nexport interface SidebarProps {\n /** Which side the activity bar and drawer appear on. Default: 'right' */\n position?: 'left' | 'right';\n tabs: SidebarTab[];\n /**\n * One or more non-toggling action buttons and/or real tabs shown above the tabs, in their\n * own `.rdd-sidebar-header-area` — independent of the tabs' own inter-item gap. Pass a single\n * `{ icon, label, onClick }`/`{ render }` object (the common case), or an array mixing action\n * buttons, custom renders, and `SidebarTab` entries — a tab entry here behaves exactly like a\n * main-list tab (mounts, activates, closes through the same lifecycle). Override\n * `--rdd-sidebar-header-area-padding-top`/`--rdd-sidebar-header-area-padding-bottom`\n * (both default `8px`) to control its spacing/effective height.\n */\n headerAction?: SidebarRailEntry | SidebarRailEntry[];\n /**\n * Mirror of `headerAction`, pinned to the bottom of the tab strip via its own\n * `.rdd-sidebar-footer-area` — e.g. a \"Settings\" tab that should always sit at the bottom\n * regardless of tab count. Override `--rdd-sidebar-footer-area-padding-top`/\n * `--rdd-sidebar-footer-area-padding-bottom` (both default `8px`) to control its spacing.\n */\n footerAction?: SidebarRailEntry | SidebarRailEntry[];\n /** Initial drawer width in pixels. Default: 280 */\n defaultWidth?: number;\n /** Minimum drawer width in pixels during drag-resize. Default: 150 */\n minWidth?: number;\n /** Maximum drawer width in pixels during drag-resize. Default: 600 */\n maxWidth?: number;\n /** Called during drag resize and on setWidth() with the new pixel width. */\n onWidthChange?: (px: number) => void;\n /** Controlled active tab id. Omit to use internal state. */\n activeTabId?: string | null;\n /** Called when the active tab changes. */\n onActiveTabChange?: (tabId: string | null) => void;\n /** Collapse the entire sidebar (strip + drawer). Default: true */\n visible?: boolean;\n /** Called when show/hide/toggle is invoked on the imperative handle. */\n onVisibilityChange?: (visible: boolean) => void;\n /** Collapse only the activity bar strip, leaving the drawer unaffected. Default: true */\n stripVisible?: boolean;\n /** Called when showStrip/hideStrip is invoked on the imperative handle. */\n onStripVisibilityChange?: (visible: boolean) => void;\n /**\n * Show an \"X\" close button in the expanded drawer's header, as an additional way to collapse\n * the sidebar (equivalent to clicking the active tab's own icon again). Opt-in. Default: false.\n * Has no effect once the default header is suppressed — via `hideDefaultHeader`, or simply by\n * passing `renderHeader` (either one is sufficient) — since the entire default header, this\n * button included, is skipped for every tab in that case.\n */\n showCloseButton?: boolean;\n /**\n * Suppress the library's own drawer header (title + `showCloseButton`'s close\n * button) for every tab, so `renderHeader` (or each tab's own `renderContent`)\n * can supply a header, border, and styling instead. Applies uniformly across\n * all tabs — there's no per-tab override. Passing `renderHeader` by itself has\n * the same suppressing effect even if this is left unset — the two conditions\n * are combined with OR, precisely so that supplying `renderHeader` alone is\n * never a silent no-op. The close mechanism is unaffected either way: the\n * `onClose` parameter passed to `renderContent`/`renderHeader`, or\n * `useSidebarTab().onClose` from anywhere in a tab's content tree.\n * Default: false\n */\n hideDefaultHeader?: boolean;\n /**\n * Custom header renderer used in place of the library's own drawer header.\n * Passing `renderHeader` is by itself sufficient to suppress the default\n * header, whether or not `hideDefaultHeader` is also set — the two props are\n * combined with OR. Called once for whichever tab is currently active, so\n * the same header markup (e.g. a hamburger icon, a search field, a close\n * button) is shared uniformly across every tab instead of being repeated\n * inside each tab's own `renderContent`. Omit `renderHeader` and set\n * `hideDefaultHeader: true` to render no header at all and let each tab's\n * `renderContent` supply its own instead.\n * @param tab - the currently active tab\n * @param onClose - call to collapse the sidebar drawer\n * @param onOpen - call to (re-)select this tab\n */\n renderHeader?: (tab: SidebarTab, onClose: () => void, onOpen: () => void) => React.ReactNode;\n /**\n * @internal Marks this instance as a secondary sidebar for context-broadcasting\n * purposes. Set automatically by `<SecondarySidebar>` — do not pass this directly.\n * Default: false\n */\n isSecondary?: boolean;\n /** Main workspace content rendered alongside the sidebar. */\n children?: React.ReactNode;\n}\n\n/**\n * Imperative handle exposed by `<Sidebar ref={...}>`.\n */\nexport interface SidebarHandle {\n openTab: (tabId: string) => void;\n closeDrawer: () => void;\n getActiveTab: () => string | null;\n show: () => void;\n hide: () => void;\n toggle: () => void;\n showStrip: () => void;\n hideStrip: () => void;\n setWidth: (px: number) => void;\n getWidth: () => number;\n}\n\n/**\n * Value provided by `useSidebar()`. Available to any component inside the\n * `<Sidebar>` React tree, including panels rendered via `{children}`.\n */\nexport interface SidebarContextValue {\n openTab: (tabId: string) => void;\n closeDrawer: () => void;\n getActiveTab: () => string | null;\n /** Which side this Sidebar instance is rendering on. */\n position: 'left' | 'right';\n /** True if this instance is a `<SecondarySidebar>`, false for a primary `<Sidebar>`. */\n isSecondary: boolean;\n}\n\n/**\n * Value provided by `useSidebarTab()`. Available only to components rendered\n * inside a sidebar tab's `renderContent` tree.\n */\nexport interface SidebarTabContextValue {\n tabId: string;\n onOpen: () => void;\n onClose: () => void;\n openTab: (tabId: string) => void;\n}\n\n// ==========================================\n// Contexts\n// ==========================================\n\nconst SidebarContext = createContext<SidebarContextValue | null>(null);\nconst SidebarTabContext = createContext<SidebarTabContextValue | null>(null);\n\n// ==========================================\n// SidebarTabProvider (internal)\n// ==========================================\n\ninterface SidebarTabProviderProps {\n tabId: string;\n onClose: () => void;\n onOpen: () => void;\n setActiveTabId: (id: string | null) => void;\n children: React.ReactNode;\n}\n\nfunction SidebarTabProvider({ tabId, onClose, onOpen, setActiveTabId, children }: SidebarTabProviderProps) {\n const value = useMemo<SidebarTabContextValue>(() => ({\n tabId,\n onClose,\n onOpen,\n openTab: (otherId: string) => setActiveTabId(otherId),\n }), [tabId, onClose, onOpen, setActiveTabId]);\n\n return <SidebarTabContext.Provider value={value}>{children}</SidebarTabContext.Provider>;\n}\n\n// ==========================================\n// renderRailEntry (internal helper)\n// Shared by the header/footer areas only — dispatches a SidebarRailEntry to a tab button,\n// a default-styled action button, or a fully custom render. The main tabs-list keeps its own\n// inline JSX below since it only ever renders SidebarTab entries.\n// ==========================================\n\nfunction renderRailEntry(\n entry: SidebarRailEntry,\n index: number,\n activeTabId: string | null | undefined,\n onTabClick: (tabId: string) => void\n): React.ReactNode {\n if (isRailCustom(entry)) {\n return <React.Fragment key={entry.id ?? index}>{entry.render()}</React.Fragment>;\n }\n if (isRailTab(entry)) {\n if (entry.hidden) return null;\n const isActive = activeTabId === entry.id;\n return (\n <button\n key={entry.id}\n type=\"button\"\n onClick={() => onTabClick(entry.id)}\n className={`rdd-sidebar-tab-btn${isActive ? ' rdd-active' : ''}`}\n title={entry.label}\n aria-pressed={isActive}\n >\n {entry.icon}\n </button>\n );\n }\n return (\n <button\n key={entry.id ?? index}\n type=\"button\"\n onClick={entry.onClick}\n disabled={entry.disabled}\n className=\"rdd-sidebar-tab-btn rdd-sidebar-header-action-btn\"\n title={entry.label}\n aria-label={entry.label}\n >\n {entry.icon}\n </button>\n );\n}\n\n// ==========================================\n// SidebarTabStrip (internal sub-component)\n// Re-renders only when tabs, selection, or strip visibility changes —\n// not on drawer width changes during drag.\n// ==========================================\n\ninterface SidebarTabStripProps {\n tabs: SidebarTab[];\n headerEntries: SidebarRailEntry[];\n footerEntries: SidebarRailEntry[];\n activeTabId: string | null | undefined;\n isVisible: boolean;\n position: 'left' | 'right';\n onTabClick: (tabId: string) => void;\n}\n\nconst SidebarTabStrip = memo(function SidebarTabStrip({\n tabs,\n headerEntries,\n footerEntries,\n activeTabId,\n isVisible,\n position,\n onTabClick,\n}: SidebarTabStripProps) {\n return (\n // Outer div drives the collapse transition via overflow:hidden.\n // The inner rdd-sidebar-tabs-strip must NOT have overflow:hidden so the active\n // tab's negative margin can extend into the drawer border without clipping.\n <div\n style={{\n width: isVisible ? '56px' : '0px',\n height: '100%',\n overflow: 'hidden',\n transition: 'width 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n flexShrink: 0,\n }}\n >\n <div\n className={`rdd-sidebar-tabs-strip rdd-${position}${headerEntries.length ? ' rdd-sidebar-tabs-strip--has-header-action' : ''}${footerEntries.length ? ' rdd-sidebar-tabs-strip--has-footer-action' : ''}`}\n style={{ width: '56px', height: '100%' }}\n >\n {headerEntries.length > 0 && (\n <div className=\"rdd-sidebar-header-area\">\n {headerEntries.map((entry, i) => renderRailEntry(entry, i, activeTabId, onTabClick))}\n </div>\n )}\n <div className=\"rdd-sidebar-tabs-list\">\n {tabs.map(tab => {\n if (tab.hidden) return null;\n const isActive = activeTabId === tab.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => onTabClick(tab.id)}\n className={`rdd-sidebar-tab-btn${isActive ? ' rdd-active' : ''}`}\n title={tab.label}\n aria-pressed={isActive}\n >\n {tab.icon}\n </button>\n );\n })}\n </div>\n {footerEntries.length > 0 && (\n <div className=\"rdd-sidebar-footer-area\">\n {footerEntries.map((entry, i) => renderRailEntry(entry, i, activeTabId, onTabClick))}\n </div>\n )}\n </div>\n </div>\n );\n});\n\n// ==========================================\n// SidebarResizeHandle (internal sub-component)\n// Encapsulates all pointer-capture drag logic.\n// Identical interaction pattern to the panel grid resizer in WindowManager.tsx.\n// ==========================================\n\ninterface SidebarResizeHandleProps {\n position: 'left' | 'right';\n currentWidth: number;\n minWidth: number;\n maxWidth: number;\n onWidthChange: (newWidth: number) => void;\n onResizeStart: () => void;\n onResizeEnd: () => void;\n}\n\nfunction SidebarResizeHandle({\n position,\n currentWidth,\n minWidth,\n maxWidth,\n onWidthChange,\n onResizeStart,\n onResizeEnd,\n}: SidebarResizeHandleProps) {\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault();\n const el = e.currentTarget;\n const activeClasses: Array<{ el: HTMLElement; classes: string[] }> = [\n { el, classes: ['rdd-active'] },\n { el: document.body, classes: ['rdd-resizing-active', 'rdd-resizing-col-active'] },\n ];\n // Suppress the drawer's CSS transition so drag feels instant — driven by this\n // instance's own isResizing state (see the drawer's style below), not a DOM\n // class + descendant selector, which would leak across a nested secondary\n // Sidebar's subtree since it's a literal DOM descendant of this one.\n onResizeStart();\n\n startPointerDrag({\n element: el,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => currentWidth,\n activeClasses,\n onMove: (dx, _dy, startWidth) => {\n // Right sidebar: dragging left (negative dx) widens the drawer\n const newW = position === 'right' ? startWidth - dx : startWidth + dx;\n onWidthChange(Math.max(minWidth, Math.min(maxWidth, newW)));\n },\n onEnd: () => onResizeEnd(),\n });\n };\n\n return (\n <div\n className=\"rdd-resizer-bar\"\n style={{\n cursor: 'col-resize',\n width: '1px',\n height: '100%',\n flexShrink: 0,\n zIndex: 20,\n }}\n onPointerDown={handlePointerDown}\n />\n );\n}\n\n// ==========================================\n// Sidebar (main component)\n// ==========================================\n\nexport const Sidebar: React.ForwardRefExoticComponent<SidebarProps & React.RefAttributes<SidebarHandle>> =\n forwardRef<SidebarHandle, SidebarProps>(function Sidebar(\n {\n position = 'right',\n tabs,\n headerAction,\n footerAction,\n defaultWidth,\n minWidth = 150,\n maxWidth = 600,\n onWidthChange,\n activeTabId: controlledActiveTabId,\n onActiveTabChange,\n visible,\n onVisibilityChange,\n stripVisible,\n onStripVisibilityChange,\n showCloseButton = false,\n hideDefaultHeader = false,\n renderHeader,\n isSecondary = false,\n children,\n },\n ref\n ) {\n const isControlled = controlledActiveTabId !== undefined;\n\n const [width, setWidthState] = useState<number>(() => defaultWidth ?? 280);\n\n const setWidth = useCallback((px: number) => {\n setWidthState(px);\n onWidthChange?.(px);\n }, [onWidthChange]);\n\n // Suppresses the drawer's CSS transition during a resize drag — own state,\n // not a DOM class, so it can never leak into a nested secondary Sidebar's\n // drawer (see SidebarResizeHandle's onResizeStart/onResizeEnd below).\n const [isResizing, setIsResizing] = useState(false);\n\n // Internal active tab state (uncontrolled mode)\n const [internalActiveTabId, setInternalActiveTabId] = useState<string | null>(null);\n const activeTabId = isControlled ? controlledActiveTabId : internalActiveTabId;\n\n // Normalized header/footer rail entries, and the SidebarTab-shaped subset of each — a\n // header/footer tab (e.g. \"Settings\") must share the exact same lifecycle as a main tab.\n const normalizedHeaderEntries = useMemo(() => toRailArray(headerAction), [headerAction]);\n const normalizedFooterEntries = useMemo(() => toRailArray(footerAction), [footerAction]);\n const headerTabs = useMemo(() => normalizedHeaderEntries.filter(isRailTab), [normalizedHeaderEntries]);\n const footerTabs = useMemo(() => normalizedFooterEntries.filter(isRailTab), [normalizedFooterEntries]);\n const allTabs = useMemo(() => [...headerTabs, ...tabs, ...footerTabs], [headerTabs, tabs, footerTabs]);\n\n // Tracks which non-eager tabs have been mounted at least once (for lazy-mount / preserveState).\n // eagerMount tabs are folded in via effectiveMountedTabIds below, so no effect needed for them.\n const [mountedTabIds, setMountedTabIds] = useState<Set<string>>(() => new Set<string>());\n\n // Derives the full mounted set during render — no effect needed.\n // Includes: accumulated mountedTabIds + the currently active tab (handles controlled\n // prop changes where setActiveTabId is never called) + all eagerMount tabs.\n const effectiveMountedTabIds = useMemo(() => {\n const result = new Set(mountedTabIds);\n if (activeTabId) result.add(activeTabId);\n for (const tab of allTabs) {\n if (tab.eagerMount) result.add(tab.id);\n }\n return result;\n }, [mountedTabIds, activeTabId, allTabs]);\n\n // Stable refs for imperative handle\n const activeTabIdRef = useRef<string | null>(activeTabId ?? null);\n useEffect(() => { activeTabIdRef.current = activeTabId ?? null; }, [activeTabId]);\n\n const widthRef = useRef<number>(width);\n useEffect(() => { widthRef.current = width; }, [width]);\n\n const setActiveTabId = useCallback(\n (id: string | null) => {\n // Update mounted set in the same render batch as the tab switch — avoids setState-in-effect.\n if (id !== null) {\n setMountedTabIds(prev => {\n if (prev.has(id)) return prev;\n const next = new Set(prev);\n next.add(id);\n return next;\n });\n } else {\n // Drawer closing: evict transient tabs (non-eager, non-preserveState).\n setMountedTabIds(prev => {\n let changed = false;\n const next = new Set(prev);\n for (const tabId of prev) {\n const tab = allTabs.find(t => t.id === tabId);\n if (tab && !tab.eagerMount && !tab.preserveState) {\n next.delete(tabId);\n changed = true;\n }\n }\n return changed ? next : prev;\n });\n }\n if (isControlled) {\n onActiveTabChange?.(id);\n } else {\n setInternalActiveTabId(id);\n onActiveTabChange?.(id);\n }\n },\n [isControlled, onActiveTabChange, allTabs]\n );\n\n // If the active tab stops existing in `tabs`/`headerAction`/`footerAction` (its contributing\n // panel changed/closed, or the tab was otherwise removed), close the drawer rather than\n // leaving it open and empty with no tab button left to click closed — never silently fall\n // back to a different tab the user didn't choose.\n useEffect(() => {\n if (activeTabId != null && !allTabs.some(t => t.id === activeTabId)) {\n setActiveTabId(null);\n }\n }, [activeTabId, allTabs, setActiveTabId]);\n\n useImperativeHandle(ref, () => ({\n openTab: (tabId: string) => setActiveTabId(tabId),\n closeDrawer: () => setActiveTabId(null),\n getActiveTab: () => activeTabIdRef.current,\n show: () => onVisibilityChange?.(true),\n hide: () => onVisibilityChange?.(false),\n toggle: () => onVisibilityChange?.(visible === false ? true : false),\n showStrip: () => onStripVisibilityChange?.(true),\n hideStrip: () => onStripVisibilityChange?.(false),\n setWidth: (px: number) => setWidth(Math.max(minWidth, Math.min(maxWidth, px))),\n getWidth: () => widthRef.current,\n }), [setActiveTabId, visible, onVisibilityChange, onStripVisibilityChange, setWidth, minWidth, maxWidth]);\n\n const handleTabClick = useCallback((tabId: string) => {\n setActiveTabId(activeTabId === tabId ? null : tabId);\n }, [activeTabId, setActiveTabId]);\n\n const handleClose = useCallback(() => setActiveTabId(null), [setActiveTabId]);\n\n // `renderHeader` alone (no `hideDefaultHeader`) also suppresses the default\n // header — see the render condition below. Derived once here so both that\n // condition and the dev-warning effect stay in sync.\n const hasHeaderOverride = hideDefaultHeader || renderHeader != null;\n\n // Dev-only: showCloseButton renders nothing once the default header is\n // suppressed, since its close button is part of that (now-skipped) header.\n // Warns once per mounted Sidebar — closeButtonWarnedRef lives in component\n // scope (not inside the effect) so it survives re-renders; depending on the\n // derived boolean rather than `renderHeader` itself avoids re-running this\n // on every render, since `renderHeader` is typically passed as a fresh\n // inline arrow function each time.\n const closeButtonWarnedRef = useRef(false);\n useEffect(() => {\n if (process.env.NODE_ENV !== 'development') return;\n if (!showCloseButton || !hasHeaderOverride) return;\n if (closeButtonWarnedRef.current) return;\n closeButtonWarnedRef.current = true;\n console.warn(\n '[react-dockable-desktop] `showCloseButton` has no effect because the default header is ' +\n 'suppressed (`hideDefaultHeader` is set, or `renderHeader` was passed). The \"X\" close button ' +\n 'only renders as part of the library\\'s own default header, which is skipped in this case. ' +\n 'Add your own close control inside `renderHeader` (or `renderContent`), wired to its `onClose` ' +\n 'parameter or `useSidebarTab().onClose`.'\n );\n }, [showCloseButton, hasHeaderOverride]);\n\n // Stable context value for useSidebar() consumers\n const sidebarContextValue = useMemo<SidebarContextValue>(() => ({\n openTab: (tabId: string) => setActiveTabId(tabId),\n closeDrawer: () => setActiveTabId(null),\n getActiveTab: () => activeTabIdRef.current,\n position,\n isSecondary,\n }), [setActiveTabId, position, isSecondary]);\n\n // ---- Derived visibility flags ----\n const isSidebarVisible = visible !== false;\n const isStripVisible = isSidebarVisible && stripVisible !== false;\n const isDrawerOpen = isSidebarVisible && activeTabId != null;\n\n // ---- Drawer element (shared between left and right) ----\n const drawer = (\n <div\n className={`rdd-sidebar-content-drawer rdd-${position}`}\n style={{\n // flex-basis drives the visible width; width: 0px has no effect in flex context\n // when flex-basis is set — so we animate flex-basis, not width.\n flexBasis: isDrawerOpen ? `${width}px` : '0px',\n flexShrink: 1,\n flexGrow: 0,\n minWidth: isDrawerOpen ? `${minWidth}px` : '0px',\n maxWidth: isDrawerOpen ? `${maxWidth}px` : '0px',\n overflow: 'hidden',\n // Suppressed during a resize drag via this instance's own isResizing state.\n transition: isResizing\n ? 'none'\n : 'flex-basis 0.2s cubic-bezier(0.4, 0, 0.2, 1), min-width 0.2s cubic-bezier(0.4, 0, 0.2, 1), max-width 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n }}\n >\n {allTabs.map(tab => {\n const isMounted = effectiveMountedTabIds.has(tab.id);\n if (!isMounted) return null;\n\n const isCurrent = activeTabId === 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 — tab label, plus an optional close button (showCloseButton) as\n an extra way to collapse the sidebar; clicking the active tab icon still works too.\n Suppressed for every tab when hideDefaultHeader is set, OR simply when renderHeader\n is passed (either alone is sufficient — see hasHeaderOverride above, which keeps\n this in sync with the dev-warning effect) — onClose/onOpen still flow to either\n one regardless. */}\n {hasHeaderOverride ? (\n renderHeader?.(tab, handleClose, onOpen)\n ) : (\n <div className=\"rdd-sidebar-drawer-header\">\n <span className=\"rdd-sidebar-header-title\">{tab.label}</span>\n {showCloseButton && (\n <button\n type=\"button\"\n className=\"rdd-sidebar-drawer-close-button\"\n onClick={handleClose}\n title=\"Close\"\n aria-label=\"Close\"\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 )}\n\n {/* Drawer body — consumer-supplied content */}\n <div className=\"rdd-sidebar-drawer-body\">\n <SidebarTabProvider\n tabId={tab.id}\n onClose={handleClose}\n onOpen={onOpen}\n setActiveTabId={setActiveTabId}\n >\n {tab.renderContent(tab.id, handleClose, onOpen)}\n </SidebarTabProvider>\n </div>\n </div>\n );\n })}\n </div>\n );\n\n // ---- Resize handle (only interactive when drawer is open) ----\n const resizeHandle = isDrawerOpen ? (\n <SidebarResizeHandle\n position={position}\n currentWidth={width}\n minWidth={minWidth}\n maxWidth={maxWidth}\n onWidthChange={setWidth}\n onResizeStart={() => setIsResizing(true)}\n onResizeEnd={() => setIsResizing(false)}\n />\n ) : null;\n\n return (\n <SidebarContext.Provider value={sidebarContextValue}>\n <div\n style={{\n display: 'flex',\n flexDirection: 'row',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {position === 'left' && (\n <SidebarTabStrip\n tabs={tabs}\n headerEntries={normalizedHeaderEntries}\n footerEntries={normalizedFooterEntries}\n activeTabId={activeTabId}\n isVisible={isStripVisible}\n position={position}\n onTabClick={handleTabClick}\n />\n )}\n {position === 'left' && drawer}\n {position === 'left' && resizeHandle}\n\n {/* Workspace content — fills all remaining space */}\n <div style={{ flex: '1 1 0%', minWidth: 0, overflow: 'hidden' }}>\n {children}\n </div>\n\n {position === 'right' && resizeHandle}\n {position === 'right' && drawer}\n {position === 'right' && (\n <SidebarTabStrip\n tabs={tabs}\n headerEntries={normalizedHeaderEntries}\n footerEntries={normalizedFooterEntries}\n activeTabId={activeTabId}\n isVisible={isStripVisible}\n position={position}\n onTabClick={handleTabClick}\n />\n )}\n </div>\n </SidebarContext.Provider>\n );\n });\n\n// ==========================================\n// SecondarySidebar\n// ==========================================\n\n/**\n * Props for {@link SecondarySidebar} — identical to {@link SidebarProps} except\n * `position` (always the opposite of whatever primary `Sidebar` it's nested inside)\n * and `isSecondary` (always `true`) are not settable.\n */\nexport type SecondarySidebarProps = Omit<SidebarProps, 'position' | 'isSecondary'>;\n\n/**\n * A second, independent `Sidebar` instance for the opposite edge of the screen —\n * same component, same behavior, zero forked code. Must be rendered inside a\n * primary `Sidebar`'s `children`; automatically takes whichever side that primary\n * isn't using, so the side is never specified directly.\n *\n * @throws Error if rendered without an ancestor `Sidebar`, or nested inside another\n * `SecondarySidebar` — this library supports exactly one primary and one secondary,\n * nothing deeper.\n */\nexport const SecondarySidebar: React.ForwardRefExoticComponent<SecondarySidebarProps & React.RefAttributes<SidebarHandle>> =\n forwardRef<SidebarHandle, SecondarySidebarProps>(function SecondarySidebar(props, ref) {\n const primary = useContext(SidebarContext);\n if (!primary) {\n throw new Error('SecondarySidebar must be rendered inside a primary Sidebar\\'s children');\n }\n if (primary.isSecondary) {\n throw new Error('SecondarySidebar cannot be nested inside another SecondarySidebar');\n }\n const opposite = primary.position === 'left' ? 'right' : 'left';\n return <Sidebar ref={ref} {...props} position={opposite} isSecondary />;\n });\n\n// ==========================================\n// Hooks\n// ==========================================\n\n/**\n * Returns sidebar control functions from anywhere inside a `<Sidebar>` tree,\n * including floating panels rendered via `{children}`.\n *\n * @throws Error if used outside of a {@link Sidebar}.\n */\nexport function useSidebar(): SidebarContextValue {\n const ctx = useContext(SidebarContext);\n if (!ctx) throw new Error('useSidebar must be used within Sidebar');\n return ctx;\n}\n\n/**\n * Returns tab-specific control functions for components rendered inside a\n * sidebar tab's `renderContent` tree.\n *\n * @throws Error if used outside of a {@link Sidebar} tab's `renderContent` tree.\n */\nexport function useSidebarTab(): SidebarTabContextValue {\n const ctx = useContext(SidebarTabContext);\n if (!ctx) throw new Error('useSidebarTab must be used within a Sidebar tab renderContent tree');\n return ctx;\n}\n\nexport default Sidebar;\n","/**\n * @file Toolbar.tsx\n * @description Vertical or horizontal toolbar strip hosting action buttons,\n * mutually-exclusive radio tool groups, independent toggle modifiers,\n * and collapsible sub-tool group flyouts.\n * State is library-wide via DockableDesktopProvider / ToolbarContext.\n */\n\nimport React, { forwardRef, useImperativeHandle, useState, useRef, useEffect, useLayoutEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useToolbar } from './ToolbarContext';\nimport type { ToolbarContextValue } from './ToolbarContext';\n\n// ==========================================\n// Item type definitions\n// ==========================================\n\n/** A one-shot action button. */\nexport interface ToolbarActionItem {\n type: 'action';\n id: string;\n label: string;\n icon: React.ReactNode;\n onClick: () => void;\n disabled?: boolean;\n}\n\n/** A mutually-exclusive radio button within a named group. */\nexport interface ToolbarRadioItem {\n type: 'radio';\n id: string;\n group: string;\n label: string;\n icon: React.ReactNode;\n /** Keyboard shortcut hint — displayed in the group flyout; reserved for future custom tooltip. */\n shortcut?: string;\n /** Called when this item becomes active. */\n onActivate?: (id: string) => void;\n disabled?: boolean;\n}\n\n/**\n * An independent on/off toggle modifier (e.g. snap-to-grid).\n *\n * Supports both uncontrolled mode (omit `rdd-active` — state lives in\n * ToolbarContext, keyed by `id`) and controlled mode (provide `rdd-active` —\n * the caller is the single source of truth and must update the prop in\n * response to `onToggle`). Controlled mode is what lets independent\n * instances of the same panel type report independent active state\n * instead of colliding on a shared id.\n */\nexport interface ToolbarToggleItem {\n type: 'toggle';\n id: string;\n label: string;\n icon: React.ReactNode;\n /** Keyboard shortcut hint — reserved for future custom tooltip. */\n shortcut?: string;\n /**\n * Controlled active state. When provided (even as false), the component\n * reads this prop instead of ToolbarContext and does not update context\n * on click. Omit (undefined) for uncontrolled behaviour.\n */\n active?: boolean;\n /** Called after the toggle flips; receives the new active state. */\n onToggle?: (active: boolean) => void;\n disabled?: boolean;\n}\n\n/** A visual divider between button groups. */\nexport interface ToolbarSeparator {\n type: 'separator';\n}\n\n// ==========================================\n// Group item types (sub-tool flyout)\n// ==========================================\n\n/**\n * A single selectable sub-tool inside a group flyout.\n * All sub-items in the same ToolbarGroupItem share one radio group\n * keyed by the parent ToolbarGroupItem's `id`.\n */\nexport interface ToolbarGroupSubItem {\n id: string;\n label: string;\n icon: React.ReactNode;\n /** Keyboard shortcut displayed in the flyout panel. */\n shortcut?: string;\n disabled?: boolean;\n /** Called when this sub-item is selected. */\n onActivate?: (id: string) => void;\n}\n\n/** An entry inside a group flyout — either a sub-item or a separator. */\nexport type ToolbarGroupEntry = ToolbarGroupSubItem | { type: 'separator' };\n\n/**\n * A collapsed tool-family button that opens a flyout panel listing all\n * sub-tools. Only one sub-tool may be active at a time (radio semantics).\n * The parent button's icon morphs to show the currently active sub-tool.\n *\n * Supports both uncontrolled mode (omit activeItemId — state lives in\n * ToolbarContext) and controlled mode (provide activeItemId — the caller\n * is the single source of truth and must update the prop in response to\n * onActiveItemChange).\n */\nexport interface ToolbarGroupItem {\n type: 'group';\n /** Serves as both the button ID and the radio group key in ToolbarContext. */\n id: string;\n /** Tooltip / aria-label shown when no sub-item is active. */\n label: string;\n /** Icon shown when no sub-item is active. */\n defaultIcon: React.ReactNode;\n items: ToolbarGroupEntry[];\n disabled?: boolean;\n /**\n * Controlled active sub-item id. When provided (even as null), the\n * component reads this prop instead of ToolbarContext and fires\n * onActiveItemChange on click instead of updating context.\n * Omit (undefined) for uncontrolled behaviour.\n */\n activeItemId?: string | null;\n /**\n * Called when the user selects a sub-item in controlled mode.\n * The toolbar does not update itself — the caller must update activeItemId.\n */\n onActiveItemChange?: (id: string) => void;\n}\n\nexport type ToolbarItem =\n | ToolbarActionItem\n | ToolbarRadioItem\n | ToolbarToggleItem\n | ToolbarGroupItem\n | ToolbarSeparator;\n\n// ==========================================\n// Props and Handle\n// ==========================================\n\nexport interface ToolbarProps {\n /** Side the strip is attached to. Controls strip orientation. Default: 'left' */\n position?: 'left' | 'right' | 'top' | 'bottom';\n /** Ordered list of items to render. */\n items: ToolbarItem[];\n /** Collapse the strip to zero width/height. State is preserved — no unmount. */\n visible?: boolean;\n /** Called when show/hide/toggle is invoked on the imperative handle. */\n onVisibilityChange?: (visible: boolean) => void;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface ToolbarHandle {\n show(): void;\n hide(): void;\n toggle(): void;\n}\n\n// ==========================================\n// ToolbarGroupButton — internal sub-component\n// Manages its own open/close state and renders the flyout via a portal\n// so it is never clipped by the strip's overflow:hidden.\n// ==========================================\n\ninterface ToolbarGroupButtonProps {\n item: ToolbarGroupItem;\n position: 'left' | 'right' | 'top' | 'bottom';\n toolbar: ToolbarContextValue;\n}\n\nfunction flyoutPosition(\n rect: DOMRect,\n position: 'left' | 'right' | 'top' | 'bottom',\n isRtl = false,\n gap = 8,\n): React.CSSProperties {\n switch (position) {\n case 'left':\n // RTL: flex-row reverses, so 'left' toolbar sits on the right → open leftward\n return isRtl\n ? { right: window.innerWidth - rect.left + gap, top: rect.top }\n : { left: rect.right + gap, top: rect.top };\n case 'right':\n // RTL: 'right' toolbar sits on the left → open rightward\n return isRtl\n ? { left: rect.right + gap, top: rect.top }\n : { right: window.innerWidth - rect.left + gap, top: rect.top };\n case 'top':\n return isRtl\n ? { top: rect.bottom + gap, right: window.innerWidth - rect.right }\n : { top: rect.bottom + gap, left: rect.left };\n case 'bottom':\n return isRtl\n ? { bottom: window.innerHeight - rect.top + gap, right: window.innerWidth - rect.right }\n : { bottom: window.innerHeight - rect.top + gap, left: rect.left };\n }\n}\n\nfunction ToolbarGroupButton({ item, position, toolbar }: ToolbarGroupButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [btnRect, setBtnRect] = useState<DOMRect | null>(null);\n const btnRef = useRef<HTMLButtonElement>(null);\n const flyoutRef = useRef<HTMLDivElement>(null);\n\n const isControlled = item.activeItemId !== undefined;\n const activeId = isControlled ? item.activeItemId : toolbar.getActiveInGroup(item.id);\n const activeSubItem = item.items.find(\n (e): e is ToolbarGroupSubItem => !('type' in e) && e.id === activeId,\n );\n const isActive = activeId !== null;\n const displayIcon = activeSubItem?.icon ?? item.defaultIcon;\n const displayLabel = activeSubItem?.label ?? item.label;\n\n const handleClick = () => {\n if (item.disabled) return;\n if (!isOpen && btnRef.current) {\n setBtnRect(btnRef.current.getBoundingClientRect());\n }\n setIsOpen(prev => !prev);\n };\n\n // Clamp flyout to viewport after it renders (runs before paint to avoid jitter)\n useLayoutEffect(() => {\n if (!isOpen || !flyoutRef.current) return;\n const el = flyoutRef.current;\n const r = el.getBoundingClientRect();\n const PAD = 8;\n if (r.right > window.innerWidth - PAD) {\n el.style.left = `${Math.max(PAD, window.innerWidth - r.width - PAD)}px`;\n el.style.right = 'auto';\n }\n if (r.left < PAD) {\n el.style.left = `${PAD}px`;\n el.style.right = 'auto';\n }\n if (r.bottom > window.innerHeight - PAD) {\n el.style.top = `${Math.max(PAD, window.innerHeight - r.height - PAD)}px`;\n el.style.bottom = 'auto';\n }\n if (r.top < PAD) {\n el.style.top = `${PAD}px`;\n el.style.bottom = 'auto';\n }\n }, [isOpen]);\n\n // Close flyout on click-away (exclude clicks inside the button or flyout itself)\n useEffect(() => {\n if (!isOpen) return;\n const onMouseDown = (e: MouseEvent) => {\n const target = e.target as Node;\n if (btnRef.current?.contains(target)) return;\n if (flyoutRef.current?.contains(target)) return;\n setIsOpen(false);\n };\n document.addEventListener('mousedown', onMouseDown);\n return () => document.removeEventListener('mousedown', onMouseDown);\n }, [isOpen]);\n\n // Close flyout on Escape\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') setIsOpen(false); };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [isOpen]);\n\n return (\n <>\n <button\n ref={btnRef}\n type=\"button\"\n className={`rdd-toolbar-btn rdd-toolbar-btn-group${isActive ? ' rdd-active' : ''}`}\n title={displayLabel}\n aria-label={displayLabel}\n aria-expanded={isOpen}\n aria-haspopup=\"menu\"\n disabled={item.disabled}\n onClick={handleClick}\n >\n {displayIcon}\n </button>\n\n {isOpen && btnRect && createPortal(\n <div\n ref={flyoutRef}\n className={`rdd-toolbar-group-flyout rdd-${position}`}\n style={flyoutPosition(btnRect, position, document.documentElement.dir === 'rtl')}\n role=\"menu\"\n >\n {item.items.map((entry, i) => {\n if ('type' in entry) {\n return <div key={`sep-${i}`} className=\"rdd-toolbar-group-flyout-sep\" role=\"separator\" />;\n }\n const isSubActive = activeId === entry.id;\n return (\n <button\n key={entry.id}\n type=\"button\"\n className={`rdd-toolbar-group-flyout-item${isSubActive ? ' rdd-active' : ''}`}\n disabled={entry.disabled}\n role=\"menuitem\"\n aria-pressed={isSubActive}\n onClick={() => {\n if (isControlled) {\n item.onActiveItemChange?.(entry.id);\n } else {\n toolbar.setActiveInGroup(item.id, entry.id);\n }\n entry.onActivate?.(entry.id);\n setIsOpen(false);\n }}\n >\n <span className=\"rdd-toolbar-group-flyout-icon\">{entry.icon}</span>\n <span className=\"rdd-toolbar-group-flyout-label\">{entry.label}</span>\n {entry.shortcut && (\n <span className=\"rdd-toolbar-group-flyout-shortcut\">{entry.shortcut}</span>\n )}\n </button>\n );\n })}\n </div>,\n document.body,\n )}\n </>\n );\n}\n\n// ==========================================\n// renderItem — pure helper outside component\n// ==========================================\n\nfunction renderItem(\n item: ToolbarItem,\n index: number,\n toolbar: ToolbarContextValue,\n position: 'left' | 'right' | 'top' | 'bottom',\n): React.ReactNode {\n switch (item.type) {\n case 'separator':\n return <div key={`sep-${index}`} className=\"rdd-toolbar-separator\" role=\"separator\" />;\n\n case 'action':\n return (\n <button\n key={item.id}\n type=\"button\"\n className=\"rdd-toolbar-btn rdd-toolbar-btn-action\"\n title={item.label}\n aria-label={item.label}\n disabled={item.disabled}\n onClick={item.onClick}\n >\n {item.icon}\n </button>\n );\n\n case 'radio': {\n const isActive = toolbar.getActiveInGroup(item.group) === item.id;\n return (\n <button\n key={item.id}\n type=\"button\"\n className={`rdd-toolbar-btn rdd-toolbar-btn-radio${isActive ? ' rdd-active' : ''}`}\n title={item.label}\n aria-label={item.label}\n aria-pressed={isActive}\n disabled={item.disabled}\n onClick={() => {\n toolbar.setActiveInGroup(item.group, item.id);\n item.onActivate?.(item.id);\n }}\n >\n {item.icon}\n </button>\n );\n }\n\n case 'toggle': {\n const controlled = item.active !== undefined;\n const isActive = controlled ? item.active! : toolbar.isModifierActive(item.id);\n return (\n <button\n key={item.id}\n type=\"button\"\n className={`rdd-toolbar-btn rdd-toolbar-btn-toggle${isActive ? ' rdd-active' : ''}`}\n title={item.label}\n aria-label={item.label}\n aria-pressed={isActive}\n disabled={item.disabled}\n onClick={() => {\n if (!controlled) toolbar.toggleModifier(item.id);\n item.onToggle?.(!isActive);\n }}\n >\n {item.icon}\n </button>\n );\n }\n\n case 'group':\n return (\n <ToolbarGroupButton\n key={item.id}\n item={item}\n position={position}\n toolbar={toolbar}\n />\n );\n }\n}\n\n// ==========================================\n// Component\n// ==========================================\n\nexport const Toolbar: React.ForwardRefExoticComponent<ToolbarProps & React.RefAttributes<ToolbarHandle>> = forwardRef<ToolbarHandle, ToolbarProps>(function Toolbar(\n { position = 'left', items, visible, onVisibilityChange, className, style },\n ref\n) {\n const toolbar = useToolbar();\n const isVertical = position === 'left' || position === 'right';\n\n useImperativeHandle(ref, () => ({\n show: () => onVisibilityChange?.(true),\n hide: () => onVisibilityChange?.(false),\n toggle: () => onVisibilityChange?.(visible === false ? true : false),\n }), [visible, onVisibilityChange]);\n\n // CSS owns the open-state dimensions (including the touch @media 56px override).\n // Inline style only forces 0px when collapsed so the transition animates correctly.\n const collapseStyle: React.CSSProperties = visible !== false\n ? {}\n : isVertical\n ? { width: '0px' }\n : { height: '0px' };\n\n return (\n <div\n className={`rdd-toolbar-strip rdd-${position}${className ? ` ${className}` : ''}`}\n role=\"toolbar\"\n aria-orientation={isVertical ? 'vertical' : 'horizontal'}\n style={{ ...collapseStyle, ...style }}\n >\n {items.map((item, i) => renderItem(item, i, toolbar, position))}\n </div>\n );\n});\n\n// ==========================================\n// Barrel re-exports from ToolbarContext\n// ==========================================\n\nexport { useToolbar, ToolbarProvider } from './ToolbarContext';\nexport type { ToolbarContextValue } from './ToolbarContext';\n","import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/** Visual type of a toast notification. Determines the icon and accent color. */\nexport type ToastType = 'info' | 'success' | 'warning' | 'error';\n\n/** Corner position of the `<ToastContainer>` relative to the viewport. */\nexport type ToastPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n\n/**\n * Per-notification options passed to `toast()`, `toast.info()`, etc.\n * All fields are optional and fall back to `<ToastContainer>` defaults when unset.\n */\nexport interface ToastOptions {\n /** Visual type. Overridden by the `toast.info/success/warning/error` shorthands. @default 'info' */\n type?: ToastType;\n /** Auto-dismiss delay in ms. `0` = sticky (never auto-dismisses). @default from container */\n duration?: number;\n /** Explicit ID for dedup — calling `toast.*` with the same `id` updates the existing card in-place. */\n id?: string;\n /** Show the × close button on this notification. @default from container */\n closable?: boolean;\n /** Override the built-in type icon with arbitrary content. */\n icon?: React.ReactNode;\n /** Replace the string message with arbitrary JSX. */\n content?: React.ReactNode;\n /** Called when the notification is dismissed by timer, close button, or `toast.dismiss()`. */\n onClose?: () => void;\n}\n\n/**\n * Fully-resolved options passed to `ToastAdapter.show()` and `ToastAdapter.update()`.\n * All optional `ToastOptions` fields are resolved against the container defaults.\n */\nexport interface ResolvedToastOptions {\n id: string;\n type: ToastType;\n duration: number;\n closable: boolean;\n icon?: React.ReactNode;\n content?: React.ReactNode;\n onClose?: () => void;\n}\n\n/**\n * Props for `<ToastContainer>`. Mount one instance at your app root alongside `ModalStackRenderer`.\n * @example\n * <ToastContainer position=\"top-right\" progressBar />\n */\nexport interface ToastContainerProps {\n /** Where notifications appear in the viewport. @default 'top-right' */\n position?: ToastPosition;\n /** Maximum number of notifications shown simultaneously. Extras are queued. @default 3 */\n maxVisible?: number;\n /** Default auto-dismiss delay in ms. `0` = all notifications sticky. @default 5000 */\n defaultDuration?: number;\n /** Show the × close button on all notifications unless overridden per-toast. @default true */\n defaultClosable?: boolean;\n /** Pause the auto-dismiss timer while the cursor is over a notification. @default true */\n pauseOnHover?: boolean;\n /** Entry/exit animation style. @default 'slide' */\n animation?: 'slide' | 'fade' | 'none';\n /** When `true`, newest notification appears at the top of the stack. @default false */\n newestOnTop?: boolean;\n /** Show a countdown progress bar at the bottom of each notification. @default false */\n progressBar?: boolean;\n /** Width of each notification card in pixels. @default 320 */\n width?: number;\n /** Delegate all `toast.*` calls to a custom renderer (Ant Design, MUI, Sonner, etc.). */\n adapter?: ToastAdapter;\n}\n\n/**\n * Message set for `toast.promise()`. Each field may be static content or a function\n * that receives the resolved/rejected value and returns renderable content.\n * @template T The resolved value type of the tracked promise.\n */\nexport interface ToastPromiseMessages<T> {\n /** Shown while the promise is pending. */\n pending: React.ReactNode;\n /** Shown on fulfillment. Pass a function to include the resolved value. */\n success: React.ReactNode | ((result: T) => React.ReactNode);\n /** Shown on rejection. Pass a function to include the error reason. */\n error: React.ReactNode | ((err: unknown) => React.ReactNode);\n}\n\n/**\n * Strategy interface for replacing the built-in toast renderer with an external library.\n * Pass an instance via `<ToastContainer adapter={...} />` to redirect all `toast.*` calls\n * without changing any call sites in your application.\n * @see ToastContainerProps.adapter\n */\nexport interface ToastAdapter {\n /** Called when a new notification is requested. */\n show(id: string, message: React.ReactNode, options: ResolvedToastOptions): void;\n /** Called when an existing notification is updated (e.g. after `toast.promise()` resolves). */\n update(id: string, message: React.ReactNode, options: Partial<ResolvedToastOptions>): void;\n /** Called to dismiss one notification (`id` provided) or all active notifications (no `id`). */\n dismiss(id?: string): void;\n /**\n * `null` means the adapter manages its own DOM and `<ToastContainer>` renders nothing.\n * A component causes `<ToastContainer>` to portal-render it with a `position` prop.\n */\n Container: React.ComponentType<{ position: ToastPosition }> | null;\n}\n\n// ─── Internal types ───────────────────────────────────────────────────────────\n\ntype ToastEvent =\n | { kind: 'show'; id: string; message: React.ReactNode; rawOpts: ToastOptions & { id: string } }\n | { kind: 'update'; id: string; message: React.ReactNode; patch: Partial<ResolvedToastOptions> }\n | { kind: 'dismiss'; id?: string };\n\ninterface ActiveToast {\n id: string;\n message: React.ReactNode;\n options: ResolvedToastOptions;\n exiting: boolean;\n}\n\n// ─── ToastEmitter ─────────────────────────────────────────────────────────────\n\nclass ToastEmitter {\n private listeners = new Set<(e: ToastEvent) => void>();\n private counter = 0;\n\n subscribe(fn: (e: ToastEvent) => void) { this.listeners.add(fn); }\n unsubscribe(fn: (e: ToastEvent) => void) { this.listeners.delete(fn); }\n\n show(message: React.ReactNode, opts: ToastOptions = {}): string {\n const id = opts.id ?? `toast-${++this.counter}`;\n this.emit({ kind: 'show', id, message, rawOpts: { ...opts, id } });\n return id;\n }\n\n update(id: string, message: React.ReactNode, patch: Partial<ResolvedToastOptions>) {\n this.emit({ kind: 'update', id, message, patch });\n }\n\n dismiss(id?: string) { this.emit({ kind: 'dismiss', id }); }\n\n private emit(e: ToastEvent) { this.listeners.forEach(fn => fn(e)); }\n}\n\nconst emitter = new ToastEmitter();\n\n// ─── toast public API ─────────────────────────────────────────────────────────\n\n/**\n * Type of the `toast` singleton. Callable directly or via named shorthand methods.\n * Import this type to annotate variables or props that accept the `toast` object.\n * @example\n * function notify(fn: ToastFunction) { fn.success('Done!'); }\n */\nexport interface ToastFunction {\n /** Show a notification. `opts.type` defaults to `'info'`. Returns the notification ID. */\n (msg: React.ReactNode, opts?: ToastOptions): string;\n /** Show an info notification. Returns the notification ID. */\n info: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Show a success notification. Returns the notification ID. */\n success: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Show a warning notification. Returns the notification ID. */\n warning: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Show an error notification. Returns the notification ID. */\n error: (msg: React.ReactNode, opts?: ToastOptions) => string;\n /** Dismiss a notification by ID, or all active notifications when called with no argument. */\n dismiss: (id?: string) => void;\n /**\n * Track a promise through pending → success/error states.\n * Shows a sticky pending notification immediately, then transitions it on settlement.\n * @template T The resolved value type of the promise.\n */\n promise: <T>(promise: Promise<T>, messages: ToastPromiseMessages<T>, opts?: ToastOptions) => Promise<T>;\n}\n\n/**\n * Imperative notification singleton. Call from anywhere — inside or outside React.\n * Mount `<ToastContainer>` once at your app root to activate the renderer.\n * @example\n * toast.success('File saved.');\n * toast.error('Upload failed.', { duration: 0 }); // sticky\n * toast.promise(saveFile(), { pending: 'Saving…', success: 'Saved!', error: 'Failed.' });\n */\nexport const toast: ToastFunction = Object.assign(\n (msg: React.ReactNode, opts?: ToastOptions): string => emitter.show(msg, opts),\n {\n info: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'info' }),\n success: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'success' }),\n warning: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'warning' }),\n error: (msg: React.ReactNode, opts?: ToastOptions): string =>\n emitter.show(msg, { ...opts, type: 'error' }),\n dismiss: (id?: string): void => emitter.dismiss(id),\n promise: <T,>(\n promise: Promise<T>,\n messages: ToastPromiseMessages<T>,\n opts?: ToastOptions\n ): Promise<T> => {\n const id = emitter.show(messages.pending, { ...opts, type: 'info', duration: 0 });\n promise.then(\n result => {\n const msg = typeof messages.success === 'function' ? messages.success(result) : messages.success;\n emitter.update(id, msg, { type: 'success', duration: opts?.duration ?? 5000 });\n },\n err => {\n const msg = typeof messages.error === 'function' ? messages.error(err) : messages.error;\n emitter.update(id, msg, { type: 'error', duration: opts?.duration ?? 5000 });\n }\n );\n return promise;\n },\n }\n);\n\n// ─── Icons ────────────────────────────────────────────────────────────────────\n\nconst InfoIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.5\"/>\n <path d=\"M8 5v.01M8 7.5v3.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\nconst SuccessIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.5\"/>\n <path d=\"M5 8l2 2 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n);\nconst WarningIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8 2.5L14 13.5H2L8 2.5z\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinejoin=\"round\"/>\n <path d=\"M8 7v2.5M8 11.5v.01\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\nconst ErrorIcon = () => (\n <svg className=\"rdd-toast__icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.5\"/>\n <path d=\"M5.5 5.5l5 5M10.5 5.5l-5 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\nconst CloseIcon = () => (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 4l8 8M12 4l-8 8\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/>\n </svg>\n);\n\nconst DEFAULT_ICONS: Record<ToastType, React.ReactNode> = {\n info: <InfoIcon />,\n success: <SuccessIcon />,\n warning: <WarningIcon />,\n error: <ErrorIcon />,\n};\n\n// ─── ToastItem ────────────────────────────────────────────────────────────────\n\ninterface ToastItemProps {\n id: string;\n message: React.ReactNode;\n options: ResolvedToastOptions;\n exiting: boolean;\n isLeft: boolean;\n showProgress: boolean;\n pauseOnHover: boolean;\n animation: 'slide' | 'fade' | 'none';\n onDismiss: (id: string) => void;\n onExited: (id: string) => void;\n}\n\nfunction ToastItem({\n id, message, options, exiting, isLeft,\n showProgress, pauseOnHover, animation, onDismiss, onExited,\n}: ToastItemProps) {\n const divRef = useRef<HTMLDivElement>(null);\n const bodyRef = useRef<HTMLDivElement>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const remainRef = useRef<number>(options.duration);\n const startRef = useRef<number>(0);\n const [paused, setPaused] = useState(false);\n\n const startEntry =\n animation === 'none' ? 'rdd-toast--visible' :\n animation === 'fade' ? 'rdd-toast--fade-entering' :\n isLeft ? 'rdd-toast--entering-left' :\n 'rdd-toast--entering';\n const [entryClass, setEntryClass] = useState(startEntry);\n\n // Keep max-height in sync with the card's true content height, so content that\n // grows after mount (e.g. toast.promise()'s pending -> error message) never gets\n // clipped by the overflow: hidden below. The card's own box is exactly what this\n // effect holds at a fixed height, so it never reports a resize on its own — the\n // ResizeObserver instead watches the unconstrained inner body (the only thing\n // that actually grows with its content) purely as a trigger, and reads the\n // outer card's scrollHeight (which reports the true, uncapped content height\n // even while a stale cap is still clipping it — offsetHeight/clientHeight would\n // just return that stale cap) to compute the new value. Frozen once exiting\n // starts: .rdd-toast--exiting's `max-height: 0 !important` below takes over\n // from there regardless of this inline value.\n useLayoutEffect(() => {\n const el = divRef.current;\n const body = bodyRef.current;\n if (!el || !body || exiting) return;\n\n const applyHeight = () => { el.style.maxHeight = `${el.scrollHeight}px`; };\n applyHeight();\n\n const observer = new ResizeObserver(applyHeight);\n observer.observe(body);\n return () => observer.disconnect();\n }, [exiting]);\n\n // Trigger entry transition on next frame\n useEffect(() => {\n if (animation === 'none') return;\n const raf = requestAnimationFrame(() => setEntryClass('rdd-toast--visible'));\n return () => cancelAnimationFrame(raf);\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Auto-dismiss timer\n const scheduleDismiss = useCallback((ms: number) => {\n if (ms <= 0) return;\n startRef.current = Date.now();\n timerRef.current = setTimeout(() => onDismiss(id), ms);\n }, [id, onDismiss]);\n\n useEffect(() => {\n if (timerRef.current) clearTimeout(timerRef.current);\n remainRef.current = options.duration;\n scheduleDismiss(options.duration);\n return () => { if (timerRef.current) clearTimeout(timerRef.current); };\n }, [options.duration, scheduleDismiss]);\n\n // Exit animation → call onExited after transition\n useEffect(() => {\n if (!exiting) return;\n const el = divRef.current;\n if (!el || animation === 'none') {\n onExited(id);\n return;\n }\n const handle = (e: TransitionEvent) => {\n if (e.propertyName === 'max-height') onExited(id);\n };\n el.addEventListener('transitionend', handle);\n const fallback = setTimeout(() => onExited(id), 520);\n return () => {\n el.removeEventListener('transitionend', handle);\n clearTimeout(fallback);\n };\n }, [exiting, id, onExited, animation]);\n\n const handleMouseEnter = () => {\n if (!pauseOnHover || options.duration === 0) return;\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n remainRef.current = Math.max(0, remainRef.current - (Date.now() - startRef.current));\n }\n setPaused(true);\n };\n\n const handleMouseLeave = () => {\n if (!pauseOnHover || options.duration === 0) return;\n setPaused(false);\n scheduleDismiss(remainRef.current);\n };\n\n const cls = [\n 'rdd-toast',\n options.type && `rdd-toast--${options.type}`,\n entryClass,\n exiting && 'rdd-toast--exiting',\n paused && 'rdd-toast--paused',\n ].filter(Boolean).join(' ');\n\n const icon = options.icon !== undefined ? options.icon : (options.type ? DEFAULT_ICONS[options.type] : null);\n\n return (\n <div\n ref={divRef}\n role=\"status\"\n aria-live=\"polite\"\n className={cls}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n {icon && icon}\n <div ref={bodyRef} className=\"rdd-toast__body\">\n {options.content !== undefined ? options.content : message}\n </div>\n {options.closable && (\n <button\n type=\"button\"\n className=\"rdd-toast__close\"\n onClick={() => onDismiss(id)}\n aria-label=\"Close notification\"\n >\n <CloseIcon />\n </button>\n )}\n {showProgress && options.duration > 0 && (\n <div\n className=\"rdd-toast__progress\"\n style={{ animationDuration: `${options.duration}ms` }}\n />\n )}\n </div>\n );\n}\n\n// ─── ToastContainer ───────────────────────────────────────────────────────────\n\nfunction resolveOpts(\n raw: ToastOptions & { id: string },\n defaultDuration: number,\n defaultClosable: boolean\n): ResolvedToastOptions {\n return {\n id: raw.id,\n type: raw.type ?? 'info',\n duration: raw.duration ?? defaultDuration,\n closable: raw.closable ?? defaultClosable,\n icon: raw.icon,\n content: raw.content,\n onClose: raw.onClose,\n };\n}\n\n/**\n * Portal-rendered notification host. Mount once at your app root, outside the workspace\n * container. All `toast.*` calls are routed here automatically via the internal event emitter.\n * @example\n * <ToastContainer position=\"top-right\" progressBar />\n */\nexport function ToastContainer({\n position = 'top-right',\n maxVisible = 3,\n defaultDuration = 5000,\n defaultClosable = true,\n pauseOnHover = true,\n animation = 'slide',\n newestOnTop = false,\n progressBar = false,\n width = 320,\n adapter,\n}: ToastContainerProps): React.ReactElement | null {\n const [toasts, setToasts] = useState<ActiveToast[]>([]);\n const queueRef = useRef<Array<{ id: string; message: React.ReactNode; rawOpts: ToastOptions & { id: string } }>>([]);\n const toastsRef = useRef<ActiveToast[]>(toasts);\n toastsRef.current = toasts;\n\n const handleDismiss = useCallback((id: string) => {\n setToasts(prev => prev.map(t => t.id === id ? { ...t, exiting: true } : t));\n toastsRef.current.find(t => t.id === id)?.options.onClose?.();\n }, []);\n\n const handleExited = useCallback((id: string) => {\n // Shift outside the updater (once) so the updater is pure and safe for StrictMode\n const promoted = queueRef.current.shift() ?? null;\n setToasts(prev => {\n const filtered = prev.filter(t => t.id !== id);\n if (!promoted) return filtered;\n const options = resolveOpts(promoted.rawOpts, defaultDuration, defaultClosable);\n return [...filtered, { id: promoted.id, message: promoted.message, options, exiting: false }];\n });\n }, [defaultDuration, defaultClosable]);\n\n // Subscribe to emitter (built-in path)\n useEffect(() => {\n if (adapter) return;\n\n const handle = (e: ToastEvent) => {\n if (e.kind === 'show') {\n // Resolve options once outside the updater so the updater stays pure\n const options = resolveOpts(e.rawOpts, defaultDuration, defaultClosable);\n const newEntry: ActiveToast = { id: e.id, message: e.message, options, exiting: false };\n const rawEntry = { id: e.id, message: e.message, rawOpts: e.rawOpts };\n\n setToasts(prev => {\n // Dedup check against actual prev (not stale ref) so batched calls are safe\n const existing = prev.find(t => t.id === e.id);\n if (existing) {\n return prev.map(t => t.id === e.id ? { ...t, message: e.message, options } : t);\n }\n // Count against actual prev so multiple synchronous toast() calls batch correctly\n const visible = prev.filter(t => !t.exiting).length;\n if (visible < maxVisible) {\n return [...prev, newEntry];\n }\n // Queue — guard prevents duplicate push when React calls updater twice (StrictMode)\n if (!queueRef.current.some(q => q.id === rawEntry.id)) {\n queueRef.current.push(rawEntry);\n }\n return prev;\n });\n } else if (e.kind === 'update') {\n setToasts(prev => prev.map(t => {\n if (t.id !== e.id) return t;\n const merged: ResolvedToastOptions = { ...t.options, ...e.patch, id: t.id };\n return { ...t, message: e.message, options: merged };\n }));\n queueRef.current = queueRef.current.map(q => {\n if (q.id !== e.id) return q;\n return { ...q, message: e.message, rawOpts: { ...q.rawOpts, ...e.patch } };\n });\n } else if (e.kind === 'dismiss') {\n if (e.id === undefined) {\n setToasts(prev => prev.map(t => ({ ...t, exiting: true })));\n queueRef.current = [];\n } else {\n const isActive = toastsRef.current.some(t => t.id === e.id);\n if (isActive) {\n handleDismiss(e.id);\n } else {\n queueRef.current = queueRef.current.filter(q => q.id !== e.id);\n }\n }\n }\n };\n\n emitter.subscribe(handle);\n return () => emitter.unsubscribe(handle);\n }, [adapter, maxVisible, defaultDuration, defaultClosable, handleDismiss]);\n\n // Subscribe to emitter (adapter path)\n useEffect(() => {\n if (!adapter) return;\n const handle = (e: ToastEvent) => {\n if (e.kind === 'show') {\n const opts = resolveOpts(e.rawOpts, defaultDuration, defaultClosable);\n adapter.show(e.id, e.message, opts);\n } else if (e.kind === 'update') {\n adapter.update(e.id, e.message, e.patch);\n } else if (e.kind === 'dismiss') {\n adapter.dismiss(e.id);\n }\n };\n emitter.subscribe(handle);\n return () => emitter.unsubscribe(handle);\n }, [adapter, defaultDuration, defaultClosable]);\n\n if (adapter) {\n if (!adapter.Container) return null;\n const AdapterContainer = adapter.Container;\n return createPortal(<AdapterContainer position={position} />, document.body);\n }\n\n const isLeft = position.endsWith('left');\n let dirMod = '';\n if (newestOnTop === true) dirMod = 'rdd-toast-container--newest-top';\n if (newestOnTop === false) dirMod = 'rdd-toast-container--newest-bottom';\n\n const cls = ['rdd-toast-container', `rdd-toast-container--${position}`, dirMod]\n .filter(Boolean).join(' ');\n\n return createPortal(\n <div className={cls} style={{ width }} aria-label=\"Notifications\" aria-live=\"polite\">\n {toasts.map(t => (\n <ToastItem\n key={t.id}\n id={t.id}\n message={t.message}\n options={t.options}\n exiting={t.exiting}\n isLeft={isLeft}\n showProgress={progressBar}\n pauseOnHover={pauseOnHover}\n animation={animation}\n onDismiss={handleDismiss}\n onExited={handleExited}\n />\n ))}\n </div>,\n document.body\n );\n}\n","import React, {\n useState,\n useContext,\n createContext,\n useRef,\n useLayoutEffect,\n useCallback,\n useMemo,\n useEffect,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { WindowStateContext, formatLabel, useFormatMessage, usePredefinedMessages } from './WindowManagerContext';\nimport type { FloatAnchor } from './WindowManagerContext';\n// Type-only, so this stays a one-way dependency: PanelProviderContext imports nothing from here.\nimport type { PanelTitle } from './PanelProviderContext';\nimport { flipZoneHorizontal } from './anchorGeometry';\nimport { startPointerDrag, computeResizedRect } from './dragResize';\nimport type { ResizeDir } from './dragResize';\nexport type { FloatAnchor };\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\n/** Edge of a panel to which a `PanelToolbar` attaches. */\nexport type ToolbarPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/**\n * Which of a docked widget's axes span the host panel instead of carrying a fixed size.\n *\n * A docked widget normally pins one end of each axis and carries an explicit size. A stretched\n * axis pins **both** ends and carries no size at all, so the widget tracks the panel as it\n * resizes — with no `ResizeObserver` and no JS, because CSS already does exactly this.\n *\n * - `'width'` — spans the panel's inline axis; height still fixed. A status or timeline strip.\n * - `'height'` — spans the block axis; width still fixed. A full-height side column.\n * - `'both'` — fills the panel, the inner-widget equivalent of maximizing a floating window.\n */\nexport type Stretch = 'width' | 'height' | 'both';\n\n/**\n * Where a docked widget sits: which corner it is anchored to, plus which axes (if any) span the\n * panel. Reported as a unit because a single gesture can change both at once — dropping a\n * full-width bottom strip onto the left edge flips the anchor *and* the stretched axis together,\n * and reporting those separately would expose a state that is never actually valid.\n */\nexport interface PanelFloatPlacement {\n anchor: FloatAnchor;\n stretch: Stretch | null;\n}\n\nconst stretchesInline = (s: Stretch | null): boolean => s === 'width' || s === 'both';\nconst stretchesBlock = (s: Stretch | null): boolean => s === 'height' || s === 'both';\n\n/** Adds one axis to a stretch value, keeping whatever was already stretched. */\nconst addAxis = (s: Stretch | null, axis: 'inline' | 'block'): Stretch => {\n if (axis === 'inline') return stretchesBlock(s) ? 'both' : 'width';\n return stretchesInline(s) ? 'both' : 'height';\n};\n\n/** Drops one axis from a stretch value, keeping the other. */\nconst releaseAxis = (s: Stretch | null, axis: 'inline' | 'block'): Stretch | null => {\n if (axis === 'inline') return s === 'both' ? 'height' : stretchesInline(s) ? null : s;\n return s === 'both' ? 'width' : stretchesBlock(s) ? null : s;\n};\n\n/**\n * Which stack buckets a placement occupies.\n *\n * The four corner buckets are really a proxy for *\"do these overlap on the inline axis?\"* — two\n * widgets in the same corner overlap and so stack; widgets in opposite corners sit side by side and\n * don't. A full-width strip overlaps everything on its edge, so it belongs to **both** buckets of\n * that edge and pushes the widgets in each. (Computing real inline overlap was rejected: widths\n * change continuously during a resize drag, so widgets would reshuffle mid-gesture.)\n *\n * A block-stretched widget spans the very axis stacking uses to separate siblings, so it can't\n * participate at all and occupies no bucket — z-order decides any overlap.\n */\nconst bucketsFor = (anchor: FloatAnchor, stretch: Stretch | null): FloatAnchor[] => {\n if (stretchesBlock(stretch)) return [];\n if (stretchesInline(stretch)) {\n return anchor.startsWith('top-')\n ? ['top-left', 'top-right']\n : ['bottom-left', 'bottom-right'];\n }\n return [anchor];\n};\n\n/** Replaces one half of a corner anchor, leaving the other axis alone. */\nconst withInlineHalf = (a: FloatAnchor, half: 'left' | 'right'): FloatAnchor =>\n `${a.startsWith('top-') ? 'top' : 'bottom'}-${half}` as FloatAnchor;\nconst withBlockHalf = (a: FloatAnchor, half: 'top' | 'bottom'): FloatAnchor =>\n `${half}-${a.endsWith('-right') ? 'right' : 'left'}` as FloatAnchor;\n\nconst ANCHORS: readonly FloatAnchor[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/**\n * Configuration for a window spawned imperatively via `usePanelFloatingWindowManager().open()`.\n * @see usePanelFloatingWindowManager\n */\nexport interface ManagedWindowConfig {\n /**\n * Text shown in the window's header bar. Accepts a plain string or an i18n message descriptor.\n *\n * A descriptor is re-resolved on every render, so the header follows a language change without\n * the window being closed and reopened — which a plain string cannot do here, because this\n * config is stored by the overlay rather than re-read from your own render.\n */\n title: PanelTitle;\n /** Optional icon shown to the left of the title in the header. */\n icon?: React.ReactNode;\n /** Window body content. */\n content: React.ReactNode;\n /** Corner of the panel to dock to on first render. @default 'top-right' */\n anchor?: FloatAnchor;\n /** Initial width in pixels. */\n width?: number;\n /** Initial height in pixels. */\n height?: number;\n /**\n * Which axes span the panel instead of carrying a fixed size. `width`/`height` above still apply\n * to any axis that isn't spanning, and are what a spanning axis returns to when released.\n * @see Stretch\n */\n stretch?: Stretch;\n}\n\n// ─── Internal contexts ────────────────────────────────────────────────────────\n\ninterface PanelToolbarCtx {\n registerToolbar(pos: ToolbarPosition, size: number): () => void;\n insetTop: number;\n insetBottom: number;\n}\nconst PanelToolbarContext = createContext<PanelToolbarCtx | null>(null);\n\ninterface PanelManagerCtx {\n managedWindowIds: string[];\n openManaged(id: string, config: ManagedWindowConfig): void;\n closeManaged(id: string): void;\n closeAllManaged(): void;\n}\nconst PanelManagerContext = createContext<PanelManagerCtx | null>(null);\n\ninterface PanelOverlayCtx {\n topId: string | null;\n zOrders: Record<string, number>;\n focusWindow(id: string): void;\n containerRef: React.RefObject<HTMLDivElement>;\n stacks: Record<FloatAnchor, string[]>;\n dockedSizes: Record<string, number>;\n dockWindow(id: string, anchor: FloatAnchor, stretch?: Stretch | null): void;\n undockWindow(id: string): void;\n reportDockedSize(id: string, size: number): void;\n draggingId: string | null;\n setDraggingId(id: string | null): void;\n hoveredZone: FloatAnchor | null;\n setHoveredZone(zone: FloatAnchor | null): void;\n /** Block-axis space claimed by `PanelToolbar`s on the top/bottom edges. */\n insetTop: number;\n insetBottom: number;\n /**\n * Inline-axis space claimed by `PanelToolbar`s on the `left`/`right` edges. Logical, matching\n * how `PanelToolbar` positions itself (`insetInlineStart`/`insetInlineEnd`), so `left` means\n * inline-start regardless of direction. `registerToolbar` has always recorded these; they simply\n * weren't surfaced, so nothing could keep clear of a side toolbar the way the block axis does.\n */\n insetInlineStart: number;\n insetInlineEnd: number;\n}\nconst PanelOverlayContext = createContext<PanelOverlayCtx | null>(null);\n\n// ─── Helper ───────────────────────────────────────────────────────────────────\n\nconst DROP_ZONE_SIZE = 80;\n\nfunction getHoveredZone(container: HTMLElement, clientX: number, clientY: number): FloatAnchor | null {\n const rect = container.getBoundingClientRect();\n const x = clientX - rect.left;\n const y = clientY - rect.top;\n if (x < DROP_ZONE_SIZE && y < DROP_ZONE_SIZE) return 'top-left';\n if (x > rect.width - DROP_ZONE_SIZE && y < DROP_ZONE_SIZE) return 'top-right';\n if (x < DROP_ZONE_SIZE && y > rect.height - DROP_ZONE_SIZE) return 'bottom-left';\n if (x > rect.width - DROP_ZONE_SIZE && y > rect.height - DROP_ZONE_SIZE) return 'bottom-right';\n return null;\n}\n\n// ─── PanelOverlayRoot ─────────────────────────────────────────────────────────\n\n/** Props for `<PanelOverlayRoot>`. */\nexport interface PanelOverlayRootProps {\n children: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Context provider and layout root for the Panel Overlay system. Wrap your panel content\n * with this to enable `PanelToolbar`, `PanelFloatingWindow`, and `usePanelFloatingWindowManager`.\n * @example\n * function MyPanel() {\n * return (\n * <PanelOverlayRoot style={{ position: 'relative', width: '100%', height: '100%' }}>\n * <PanelToolbar position=\"top\">...</PanelToolbar>\n * <div className=\"panel-body\">content</div>\n * </PanelOverlayRoot>\n * );\n * }\n */\nexport function PanelOverlayRoot({ children, className, style }: PanelOverlayRootProps): React.ReactElement {\n const [toolbarSizes, setToolbarSizes] = useState<Partial<Record<ToolbarPosition, number>>>({});\n const [zOrders, setZOrders] = useState<Record<string, number>>({});\n const [stacks, setStacks] = useState<Record<FloatAnchor, string[]>>({\n 'top-left': [], 'top-right': [], 'bottom-left': [], 'bottom-right': [],\n });\n const [dockedSizes, setDockedSizes] = useState<Record<string, number>>({});\n const [draggingId, setDraggingId] = useState<string | null>(null);\n const [hoveredZone, setHoveredZone] = useState<FloatAnchor | null>(null);\n const [topId, setTopId] = useState<string | null>(null);\n const [managedWindows, setManagedWindows] = useState<Map<string, ManagedWindowConfig>>(() => new Map());\n const zCounterRef = useRef(100);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const registerToolbar = useCallback((pos: ToolbarPosition, size: number): (() => void) => {\n setToolbarSizes(prev => ({ ...prev, [pos]: size }));\n return () => setToolbarSizes(prev => {\n const next = { ...prev };\n delete next[pos];\n return next;\n });\n }, []);\n\n const focusWindow = useCallback((id: string): void => {\n zCounterRef.current += 1;\n const z = zCounterRef.current;\n setZOrders(prev => ({ ...prev, [id]: z }));\n setTopId(id);\n }, []);\n\n const dockWindow = useCallback((id: string, anchor: FloatAnchor, stretch: Stretch | null = null): void => {\n const buckets = bucketsFor(anchor, stretch);\n setStacks(prev => {\n const next: Record<FloatAnchor, string[]> = {\n 'top-left': prev['top-left'].filter(x => x !== id),\n 'top-right': prev['top-right'].filter(x => x !== id),\n 'bottom-left': prev['bottom-left'].filter(x => x !== id),\n 'bottom-right': prev['bottom-right'].filter(x => x !== id),\n };\n for (const bucket of buckets) next[bucket] = [...next[bucket], id];\n // Re-registering identical membership would allocate fresh arrays on every placement effect\n // and churn every consumer of `stacks`, so bail out when nothing actually moved.\n const unchanged = ANCHORS.every(a =>\n next[a].length === prev[a].length && next[a].every((x, i) => x === prev[a][i]));\n return unchanged ? prev : next;\n });\n }, []);\n\n const undockWindow = useCallback((id: string): void => {\n setStacks(prev => ({\n 'top-left': prev['top-left'].filter(x => x !== id),\n 'top-right': prev['top-right'].filter(x => x !== id),\n 'bottom-left': prev['bottom-left'].filter(x => x !== id),\n 'bottom-right': prev['bottom-right'].filter(x => x !== id),\n }));\n }, []);\n\n const reportDockedSize = useCallback((id: string, size: number): void => {\n setDockedSizes(prev => {\n if (prev[id] === size) return prev;\n return { ...prev, [id]: size };\n });\n }, []);\n\n const openManaged = useCallback((id: string, config: ManagedWindowConfig): void => {\n setManagedWindows(prev => {\n const next = new Map(prev);\n next.set(id, config);\n return next;\n });\n }, []);\n\n const closeManaged = useCallback((id: string): void => {\n setManagedWindows(prev => {\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n const closeAllManaged = useCallback((): void => {\n setManagedWindows(new Map());\n }, []);\n\n const managedWindowIds = useMemo(() => Array.from(managedWindows.keys()), [managedWindows]);\n\n const toolbarCtxValue = useMemo<PanelToolbarCtx>(() => ({\n registerToolbar,\n insetTop: toolbarSizes.top ?? 0,\n insetBottom: toolbarSizes.bottom ?? 0,\n }), [registerToolbar, toolbarSizes]);\n\n const managerCtxValue = useMemo<PanelManagerCtx>(() => ({\n managedWindowIds,\n openManaged,\n closeManaged,\n closeAllManaged,\n }), [managedWindowIds, openManaged, closeManaged, closeAllManaged]);\n\n const coreCtxValue = useMemo<PanelOverlayCtx>(() => ({\n topId,\n zOrders,\n focusWindow,\n containerRef: containerRef as React.RefObject<HTMLDivElement>,\n stacks,\n dockedSizes,\n dockWindow,\n undockWindow,\n reportDockedSize,\n draggingId,\n setDraggingId,\n hoveredZone,\n setHoveredZone,\n insetTop: toolbarSizes.top ?? 0,\n insetBottom: toolbarSizes.bottom ?? 0,\n insetInlineStart: toolbarSizes.left ?? 0,\n insetInlineEnd: toolbarSizes.right ?? 0,\n }), [topId, zOrders, focusWindow, stacks, dockedSizes, dockWindow, undockWindow,\n reportDockedSize, draggingId, hoveredZone, toolbarSizes]);\n\n return (\n <PanelToolbarContext.Provider value={toolbarCtxValue}>\n <PanelManagerContext.Provider value={managerCtxValue}>\n <PanelOverlayContext.Provider value={coreCtxValue}>\n <div\n ref={containerRef}\n className={`rdd-panel-overlay-root${draggingId !== null ? ' rdd-dragging-active' : ''}${className ? ' ' + className : ''}`}\n style={style}\n >\n {children}\n {draggingId !== null && <DropZoneOverlay hoveredZone={hoveredZone} />}\n {Array.from(managedWindows.entries()).map(([id, cfg]) => (\n <PanelFloatingWindow\n key={id}\n id={id}\n title={cfg.title}\n icon={cfg.icon}\n open={true}\n onClose={() => closeManaged(id)}\n defaultAnchor={cfg.anchor ?? 'top-right'}\n defaultWidth={cfg.width ?? 320}\n defaultHeight={cfg.height ?? 240}\n defaultStretch={cfg.stretch}\n >\n {cfg.content}\n </PanelFloatingWindow>\n ))}\n </div>\n </PanelOverlayContext.Provider>\n </PanelManagerContext.Provider>\n </PanelToolbarContext.Provider>\n );\n}\n\n// ─── Internal: DropZoneOverlay ────────────────────────────────────────────────\n\nfunction DropZoneOverlay({ hoveredZone }: { hoveredZone: FloatAnchor | null }): React.ReactElement {\n return (\n <>\n {ANCHORS.map(zone => (\n <div\n key={zone}\n className={`rdd-panel-float-dropzone rdd-panel-float-dropzone--${zone}${hoveredZone === zone ? ' rdd-panel-float-dropzone--hovered' : ''}`}\n aria-hidden=\"true\"\n />\n ))}\n </>\n );\n}\n\n// ─── PanelToolbar ─────────────────────────────────────────────────────────────\n\n/** Background style of a `PanelToolbar`. */\nexport type ToolbarVariant = 'transparent' | 'frosted' | 'solid';\n\n/** Visual style applied to `ToolbarButton` and `ToolbarToggle` components. */\nexport type ButtonVariant = 'ghost' | 'soft' | 'outlined' | 'filled';\n\n/** Props for `<PanelToolbar>`. */\nexport interface PanelToolbarProps {\n /** Edge of the panel overlay to attach to. @see ToolbarPosition */\n position: ToolbarPosition;\n /** Background style of the toolbar strip. @default 'transparent' */\n variant?: ToolbarVariant;\n /** Default button style inherited by `ToolbarButton` and `ToolbarToggle` children. @default 'ghost' */\n buttonVariant?: ButtonVariant;\n /** Icon size in pixels for all buttons in this toolbar. Falls back to CSS default when unset. */\n buttonSize?: number;\n style?: React.CSSProperties;\n className?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Toolbar strip that attaches to any edge of a `PanelOverlayRoot`.\n * Left/right toolbars inset automatically to avoid overlapping top/bottom toolbars.\n * RTL layouts are detected and handled automatically.\n * @example\n * <PanelToolbar position=\"top\" variant=\"frosted\">\n * <ToolbarButton icon={<SaveIcon />} title=\"Save\" onClick={save} />\n * <ToolbarToggle icon={<GridIcon />} title=\"Grid\" active={grid} onToggle={() => setGrid(v => !v)} />\n * </PanelToolbar>\n */\nexport function PanelToolbar({ position, variant = 'transparent', buttonVariant = 'ghost', buttonSize, style, className, children }: PanelToolbarProps): React.ReactElement {\n const ctx = useContext(PanelToolbarContext);\n const ref = useRef<HTMLDivElement>(null);\n const cleanupRef = useRef<(() => void) | null>(null);\n\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el) return;\n if (!ctx) return;\n const measure = () => {\n const size = (position === 'top' || position === 'bottom') ? el.offsetHeight : el.offsetWidth;\n cleanupRef.current?.();\n cleanupRef.current = ctx.registerToolbar(position, size);\n };\n measure();\n // A one-shot measurement is correct for a live mount (already at final size), but during a\n // layout restore (loadLayout()/initialState) the panel's DOM isn't necessarily settled yet at\n // this exact instant — without re-measuring, a wrong size (often 0) is baked in permanently,\n // and every docked float ends up positioned at the toolbar's own y/x, covering it. This also\n // catches any later size change (button wrapping, a buttonSize/variant change, content change).\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => {\n ro.disconnect();\n cleanupRef.current?.();\n cleanupRef.current = null;\n };\n // ctx?.registerToolbar is a stable useCallback — depending on ctx directly\n // would re-run on every toolbarSizes update, causing an infinite loop.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [position, ctx?.registerToolbar]);\n\n const posStyle: React.CSSProperties = { position: 'absolute', zIndex: 5, pointerEvents: 'none', boxSizing: 'border-box' };\n\n if (position === 'top') {\n posStyle.top = 0; posStyle.left = 0; posStyle.right = 0;\n } else if (position === 'bottom') {\n posStyle.bottom = 0; posStyle.left = 0; posStyle.right = 0;\n } else if (position === 'left') {\n posStyle.insetInlineStart = 0;\n posStyle.top = ctx?.insetTop ?? 0;\n posStyle.bottom = ctx?.insetBottom ?? 0;\n } else {\n posStyle.insetInlineEnd = 0;\n posStyle.top = ctx?.insetTop ?? 0;\n posStyle.bottom = ctx?.insetBottom ?? 0;\n }\n\n const isSide = position === 'left' || position === 'right';\n const sideStyle: React.CSSProperties = isSide ? {\n ...(ctx?.insetTop ?? 0) > 0 ? { paddingTop: 0 } : {},\n ...(ctx?.insetBottom ?? 0) > 0 ? { paddingBottom: 0 } : {},\n } : {};\n\n const sizeStyle: React.CSSProperties = buttonSize != null\n ? { ['--rdd-panel-toolbar-btn-size' as string]: `${buttonSize}px` }\n : {};\n\n return (\n <div\n ref={ref}\n className={`rdd-panel-toolbar rdd-panel-toolbar--${position}${className ? ' ' + className : ''}`}\n data-variant={variant}\n data-btn-variant={buttonVariant}\n style={{ ...posStyle, ...sideStyle, ...sizeStyle, ...style }}\n >\n {children}\n </div>\n );\n}\n\n// ─── ToolbarButton ────────────────────────────────────────────────────────────\n\n/** Props for `<ToolbarButton>`. */\nexport interface ToolbarButtonProps {\n /** Button icon — typically a small SVG component. */\n icon: React.ReactNode;\n /** Click handler. */\n onClick(): void;\n disabled?: boolean;\n /** Tooltip text and accessible `aria-label`. */\n title?: string;\n /** Visual style override. Falls back to the parent `PanelToolbar`'s `buttonVariant`. */\n variant?: ButtonVariant;\n}\n\n/** Icon button for use inside a `PanelToolbar`. */\nexport function ToolbarButton({ icon, onClick, disabled, title, variant }: ToolbarButtonProps): React.ReactElement {\n return (\n <button\n type=\"button\"\n className=\"rdd-panel-toolbar-btn\"\n onClick={onClick}\n disabled={disabled}\n title={title}\n aria-label={title}\n {...(variant ? { 'data-variant': variant } : {})}\n >\n {icon}\n </button>\n );\n}\n\n// ─── ToolbarToggle ────────────────────────────────────────────────────────────\n\n/** Props for `<ToolbarToggle>`. */\nexport interface ToolbarToggleProps {\n /** Button icon — typically a small SVG component. */\n icon: React.ReactNode;\n /** Whether the toggle is in the active/pressed state. Sets `aria-pressed` automatically. */\n active: boolean;\n /** Called when the button is clicked. Toggle `active` in response. */\n onToggle(): void;\n disabled?: boolean;\n /** Tooltip text and accessible `aria-label`. */\n title?: string;\n /** Visual style override. Falls back to the parent `PanelToolbar`'s `buttonVariant`. */\n variant?: ButtonVariant;\n}\n\n/** Two-state icon toggle button for use inside a `PanelToolbar`. Sets `aria-pressed` automatically. */\nexport function ToolbarToggle({ icon, active, onToggle, disabled, title, variant }: ToolbarToggleProps): React.ReactElement {\n return (\n <button\n type=\"button\"\n className={`rdd-panel-toolbar-btn${active ? ' rdd-panel-toolbar-btn--active' : ''}`}\n onClick={onToggle}\n disabled={disabled}\n title={title}\n aria-label={title}\n aria-pressed={active}\n {...(variant ? { 'data-variant': variant } : {})}\n >\n {icon}\n </button>\n );\n}\n\n// ─── ToolbarSeparator ─────────────────────────────────────────────────────────\n\n/** Vertical (or horizontal) divider line between groups of toolbar items. */\nexport function ToolbarSeparator(): React.ReactElement {\n return <span className=\"rdd-panel-toolbar__sep\" aria-hidden=\"true\" />;\n}\n\n// ─── ToolbarSpacer ────────────────────────────────────────────────────────────\n\n/** Flex-grow spacer that pushes subsequent toolbar items to the far edge. */\nexport function ToolbarSpacer(): React.ReactElement {\n return <span className=\"rdd-panel-toolbar__spacer\" aria-hidden=\"true\" />;\n}\n\n// ─── ToolbarItem (custom control wrapper) ────────────────────────────────────\n\n/** Wrapper for a custom non-button control (e.g. a dropdown or input) inside a `PanelToolbar`. */\nexport function ToolbarItem({ children }: { children: React.ReactNode }): React.ReactElement {\n return <span className=\"rdd-panel-toolbar__item\">{children}</span>;\n}\n\n// ─── ToolbarCenter ────────────────────────────────────────────────────────────\n\n/** Centers its children within the toolbar using absolute positioning. */\nexport function ToolbarCenter({ children }: { children: React.ReactNode }): React.ReactElement {\n return <div className=\"rdd-panel-toolbar__center\">{children}</div>;\n}\n\n// ─── ToolbarSearchInput ───────────────────────────────────────────────────────\n\n/** A single result item returned by `ToolbarSearchInputProps.onSearch`. */\nexport interface SearchResult {\n /** Unique identifier for this result — passed to `onSelect`. */\n id: string;\n /** Primary display text. */\n label: string;\n /** Optional secondary text shown below the label in the dropdown. */\n description?: string;\n /** Optional group header used to bucket results visually. */\n group?: string;\n /** Optional icon shown to the left of the label. */\n icon?: React.ReactNode;\n}\n\n/** Props for `<ToolbarSearchInput>`. */\nexport interface ToolbarSearchInputProps {\n /** Placeholder text shown in the expanded input field. @default 'Search…' */\n placeholder?: string;\n /**\n * Called with the current query and an `AbortSignal` each time the input changes (debounced).\n * Return `SearchResult[]` directly for synchronous sources, or `Promise<SearchResult[]>` for async.\n * Abort in-flight requests when the signal fires to prevent stale result races.\n */\n onSearch(query: string, signal: AbortSignal): Promise<SearchResult[]> | SearchResult[];\n /** Called when the user selects a result from the dropdown. */\n onSelect(result: SearchResult): void;\n}\n\n/**\n * Debounced async search field for use inside a `PanelToolbar`.\n * Renders as a compact icon button that expands into a text input on activation.\n * Results appear in a portal-rendered dropdown below the input.\n * @example\n * <ToolbarSearchInput\n * placeholder=\"Find layer…\"\n * onSearch={(q, signal) => fetchLayers(q, { signal })}\n * onSelect={result => workspace.focusLayer(result.id)}\n * />\n */\nexport function ToolbarSearchInput({ placeholder = 'Search…', onSearch, onSelect }: ToolbarSearchInputProps): React.ReactElement {\n const [expanded, setExpanded] = useState(false);\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResult[]>([]);\n const [dropdownPos, setDropdownPos] = useState<{ top: number; left: number; width: number } | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const abortRef = useRef<AbortController | null>(null);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const openSearch = (): void => {\n setExpanded(true);\n setTimeout(() => inputRef.current?.focus({ preventScroll: true }), 0);\n };\n\n const closeSearch = (): void => {\n setExpanded(false);\n setQuery('');\n setResults([]);\n setDropdownPos(null);\n abortRef.current?.abort();\n if (debounceRef.current) clearTimeout(debounceRef.current);\n };\n\n const handleQueryChange = (e: React.ChangeEvent<HTMLInputElement>): void => {\n const q = e.target.value;\n setQuery(q);\n abortRef.current?.abort();\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (!q.trim()) { setResults([]); setDropdownPos(null); return; }\n\n debounceRef.current = setTimeout(async () => {\n const ctrl = new AbortController();\n abortRef.current = ctrl;\n try {\n const res = await onSearch(q, ctrl.signal);\n if (!ctrl.signal.aborted) {\n setResults(res);\n const el = containerRef.current;\n if (el && res.length > 0) {\n const r = el.getBoundingClientRect();\n const dropW = Math.max(r.width, 240);\n let left = r.left;\n if (left + dropW > window.innerWidth - 8) left = window.innerWidth - dropW - 8;\n setDropdownPos({ top: r.bottom + 4, left, width: dropW });\n } else {\n setDropdownPos(null);\n }\n }\n } catch {\n // AbortError or user-thrown — ignore\n }\n }, 300);\n };\n\n const handleSelect = (result: SearchResult): void => {\n onSelect(result);\n closeSearch();\n };\n\n const handleBlur = (e: React.FocusEvent): void => {\n if (!containerRef.current?.contains(e.relatedTarget as Node)) {\n closeSearch();\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent): void => {\n if (e.key === 'Escape') closeSearch();\n };\n\n const grouped = useMemo((): Record<string, SearchResult[]> => {\n const map: Record<string, SearchResult[]> = {};\n for (const r of results) {\n const g = r.group ?? '';\n if (!map[g]) map[g] = [];\n map[g].push(r);\n }\n return map;\n }, [results]);\n\n const SearchIcon = (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"6.5\" cy=\"6.5\" r=\"4.5\" />\n <line x1=\"10\" y1=\"10\" x2=\"14\" y2=\"14\" />\n </svg>\n );\n\n if (!expanded) {\n return (\n <div ref={containerRef} className=\"rdd-panel-toolbar-search\">\n <button type=\"button\" className=\"rdd-panel-toolbar-btn\" onClick={openSearch} title=\"Search\" aria-label=\"Search\">\n {SearchIcon}\n </button>\n </div>\n );\n }\n\n return (\n <div ref={containerRef} className=\"rdd-panel-toolbar-search rdd-panel-toolbar-search--open\" onBlur={handleBlur}>\n <button type=\"button\" className=\"rdd-panel-toolbar-btn\" onClick={closeSearch} aria-label=\"Close search\" title=\"Close search\">\n {SearchIcon}\n </button>\n <input\n ref={inputRef}\n className=\"rdd-panel-toolbar-search__input\"\n type=\"text\"\n value={query}\n onChange={handleQueryChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n autoComplete=\"off\"\n />\n {dropdownPos && results.length > 0 && createPortal(\n <div\n className=\"rdd-panel-toolbar-search__dropdown\"\n // z-index from .rdd-panel-toolbar-search__dropdown (+8502), not inline, so\n // zIndexBase shifts it too. Resolves to the same 9502 by default.\n style={{ position: 'fixed', top: dropdownPos.top, left: dropdownPos.left, width: dropdownPos.width }}\n onMouseDown={e => e.preventDefault()}\n >\n {Object.entries(grouped).map(([group, items]) => (\n <React.Fragment key={group || '__default__'}>\n {group && <div className=\"rdd-panel-toolbar-search__group\">{group}</div>}\n {items.map(item => (\n <button\n key={item.id}\n type=\"button\"\n className=\"rdd-panel-toolbar-search__item\"\n onClick={() => handleSelect(item)}\n >\n {item.icon && <span className=\"rdd-panel-toolbar-search__item-icon\">{item.icon}</span>}\n <span className=\"rdd-panel-toolbar-search__item-label\">{item.label}</span>\n {item.description && <span className=\"rdd-panel-toolbar-search__item-desc\">{item.description}</span>}\n </button>\n ))}\n </React.Fragment>\n ))}\n </div>,\n document.body,\n )}\n </div>\n );\n}\n\n// ─── PanelFloatingWindow ──────────────────────────────────────────────────────\n\n/** Props for `<PanelFloatingWindow>`. */\nexport interface PanelFloatingWindowProps {\n /** Unique identifier within the panel overlay. Used for z-order and stack tracking. */\n id: string;\n /** Text shown in the window's header bar. Accepts a plain string or an i18n message descriptor. */\n title: PanelTitle;\n /** Optional icon shown to the left of the title in the header. */\n icon?: React.ReactNode;\n /** Whether the window is mounted and visible. Set to `false` to close/unmount it. */\n open: boolean;\n /** Called when the user clicks the × button. Set `open` to `false` in response. */\n onClose(): void;\n /** Corner of the panel to dock to on first render. @see FloatAnchor */\n defaultAnchor: FloatAnchor;\n /** Initial width in pixels. Ignored on an axis that starts stretched, and restored to when that\n * axis is later released. */\n defaultWidth: number;\n /** Initial height in pixels. Ignored on an axis that starts stretched, and restored to when that\n * axis is later released. */\n defaultHeight: number;\n /**\n * Which axes span the panel on first render. Uncontrolled: gestures update it from here.\n * @see Stretch\n */\n defaultStretch?: Stretch;\n /**\n * Controlled stretch state. When provided — **including as `null`** — the caller is the single\n * source of truth: gestures report through {@link PanelFloatingWindowProps.onPlacementChange}\n * instead of updating internally, and the caller must echo the new value back. Omit entirely\n * (`undefined`) for uncontrolled behaviour, matching `ToolbarToggleItem.active` and\n * `Sidebar.activeTabId`.\n */\n stretch?: Stretch | null;\n /**\n * Called whenever a gesture changes where the widget sits — a stretched axis released, a\n * re-dock, or a detach. Reports anchor and stretch **together**, because one gesture can change\n * both at once and reporting them separately would surface a state that is never valid.\n *\n * This is also the only way to persist placement: the library serialises nothing about inner\n * widgets, so store what you receive here and feed it back via `defaultAnchor`/`stretch`.\n */\n onPlacementChange?: (placement: PanelFloatPlacement) => void;\n /**\n * Whether this widget may span the panel at all. `false` disables resize-to-stretch snapping,\n * for content that only makes sense at a bounded size. Default `true`.\n */\n stretchable?: boolean;\n children?: React.ReactNode;\n}\n\n/**\n * Declarative floating window anchored inside a `PanelOverlayRoot`.\n *\n * Docks to any corner, drags free of it, and drops back onto one. Windows sharing a corner stack\n * along the block axis with animated offsets. An axis can also **span the panel** instead of\n * carrying a fixed size, so the window tracks the panel as it resizes — see\n * {@link PanelFloatingWindowProps.defaultStretch} and {@link Stretch}.\n *\n * Resize handles follow what is actually movable: a free-floating window is pinned by nothing and\n * offers all eight, while a docked one offers only its free edges — plus both ends of any spanning\n * axis, either of which releases it.\n *\n * @example\n * const info = usePanelFloatingWindow();\n * <PanelFloatingWindow\n * id=\"layer-info\" title=\"Layer Info\"\n * open={info.isOpen} onClose={info.close}\n * defaultAnchor=\"top-right\" defaultWidth={300} defaultHeight={200}\n * >\n * <LayerInfoContent />\n * </PanelFloatingWindow>\n *\n * @example\n * // A full-width status strip along the bottom, tracking the panel's width.\n * // defaultHeight still applies; defaultWidth is what the inline axis returns to if released.\n * <PanelFloatingWindow\n * id=\"timeline\" title=\"Timeline\"\n * open onClose={close}\n * defaultAnchor=\"bottom-left\" defaultStretch=\"width\"\n * defaultWidth={240} defaultHeight={120}\n * >\n * <TimelineContent />\n * </PanelFloatingWindow>\n */\nexport function PanelFloatingWindow(props: PanelFloatingWindowProps): React.ReactElement | null {\n const ctx = useContext(PanelOverlayContext);\n if (!props.open) return null;\n return <FloatingWindowBody key={props.id} ctx={ctx} {...props} />;\n}\n\n// ─── Internal: FloatingWindowBody ─────────────────────────────────────────────\n\ninterface FloatingWindowBodyProps extends PanelFloatingWindowProps {\n ctx: PanelOverlayCtx | null;\n}\n\ntype WindowMode = 'docked' | 'free';\n\nconst MIN_W = 120;\nconst MIN_H = 60;\nconst DOCK_INSET = 8;\nconst DOCK_GAP = 8;\n/**\n * Resize-to-stretch snapping. Asymmetric on purpose: arming within `SNAP_IN` of the full extent\n * but only disarming once the drag pulls back past the wider `SNAP_OUT`. Without that hysteresis,\n * releasing a stretched axis by dragging a few pixels inward would immediately re-arm and snap\n * straight back on release, which makes the gesture feel broken.\n */\nconst SNAP_IN = 16;\nconst SNAP_OUT = 40;\n\nfunction FloatingWindowBody({ id, title, icon, defaultAnchor, defaultWidth, defaultHeight, defaultStretch, stretch: stretchProp, onPlacementChange, stretchable = true, children, ctx, onClose }: FloatingWindowBodyProps): React.ReactElement {\n const isRtl = useContext(WindowStateContext)?.isRtl ?? false;\n // Resolved here rather than at the call site, so a descriptor title re-resolves whenever the\n // formatter changes. Both hooks fall back to the message's own `defaultMessage` when there is no\n // provider, so an overlay used outside a WindowManager keeps working.\n const formatMessage = useFormatMessage();\n const messages = usePredefinedMessages();\n const [mode, setMode] = useState<WindowMode>('docked');\n const [currentAnchor, setCurrentAnchor] = useState<FloatAnchor>(defaultAnchor);\n // `size` is deliberately left untouched while an axis is stretched — the render branch below\n // simply stops reading it, exactly as a maximized workspace window keeps its x/y/w/h. Releasing\n // the axis therefore restores the previous size with no snapshot and no bookkeeping.\n const [internalStretch, setInternalStretch] = useState<Stretch | null>(defaultStretch ?? null);\n // Controlled when the prop is present at all — `null` is a meaningful value (\"not stretched\"),\n // so only `undefined` means \"manage it yourself\".\n const isStretchControlled = stretchProp !== undefined;\n const stretch = isStretchControlled ? (stretchProp ?? null) : internalStretch;\n const [freePos, setFreePos] = useState<{ x: number; y: number } | null>(null);\n const [size, setSize] = useState({ w: defaultWidth, h: defaultHeight });\n const windowRef = useRef<HTMLDivElement>(null);\n\n // Refs to avoid stale closures in pointer handlers\n const modeRef = useRef(mode);\n modeRef.current = mode;\n const freePosRef = useRef(freePos);\n freePosRef.current = freePos;\n const sizeRef = useRef(size);\n sizeRef.current = size;\n const stretchRef = useRef(stretch);\n stretchRef.current = stretch;\n const currentAnchorRef = useRef(currentAnchor);\n currentAnchorRef.current = currentAnchor;\n const onPlacementChangeRef = useRef(onPlacementChange);\n onPlacementChangeRef.current = onPlacementChange;\n /** Which axes would snap to stretched if the drag were released now — drives the visual cue. */\n const [snapArmed, setSnapArmed] = useState<{ inline: boolean; block: boolean }>({ inline: false, block: false });\n const snapArmedRef = useRef(snapArmed);\n snapArmedRef.current = snapArmed;\n /** The block extent available to this widget depends on what it is stacked behind. */\n const stackOffsetRef = useRef(0);\n\n /**\n * The single write path for placement. Anchor is always internal; stretch is internal only when\n * uncontrolled. Either way the pair is reported once, so a listener never observes a half-applied\n * transition.\n */\n const applyPlacement = useCallback((anchor: FloatAnchor, next: Stretch | null): void => {\n setCurrentAnchor(anchor);\n if (!isStretchControlled) setInternalStretch(next);\n onPlacementChangeRef.current?.({ anchor, stretch: next });\n }, [isStretchControlled]);\n\n const dragState = useRef<{ mouseX: number; mouseY: number; posX: number; posY: number; hasDragged: boolean } | null>(null);\n\n // Bucket membership depends on the whole placement (see bucketsFor), so this re-runs whenever\n // the anchor or a stretched axis changes — not only on mount. Free-floating widgets are in no\n // stack at all.\n useLayoutEffect(() => {\n if (mode !== 'docked') return;\n ctx?.dockWindow(id, currentAnchor, stretch);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mode, currentAnchor, stretch]);\n\n // Leave the stack on unmount (close). Closing resets to the defaults on the next open, since a\n // fresh mount means fresh state.\n useLayoutEffect(() => () => { ctx?.undockWindow(id); },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []);\n\n // Dev-only: a block-stretched widget spans the whole block axis, so it cannot stack with\n // anything — it will simply overlap siblings on its own inline side, with z-order deciding.\n // Warns once per widget, matching the warning conventions in Sidebar/WindowManager.\n const blockStretchWarnedRef = useRef(false);\n useEffect(() => {\n if (process.env.NODE_ENV !== 'development') return;\n if (blockStretchWarnedRef.current) return;\n if (mode !== 'docked' || !stretchesBlock(stretch) || !ctx) return;\n const half = currentAnchor.endsWith('-right') ? 'right' : 'left';\n const neighbours = ([`top-${half}`, `bottom-${half}`] as FloatAnchor[])\n .flatMap(bucket => ctx.stacks[bucket] ?? [])\n .filter(other => other !== id);\n if (neighbours.length === 0) return;\n blockStretchWarnedRef.current = true;\n console.warn(\n `[react-dockable-desktop] PanelFloatingWindow \"${id}\" stretches the block axis ` +\n `(stretch: \"${stretch}\") while ${neighbours.length} other widget(s) are anchored to the ` +\n `same side (${neighbours.join(', ')}). A block-stretched widget spans the axis that stacking ` +\n `uses to separate siblings, so it cannot stack and will overlap them — z-order decides which ` +\n `is on top. Either give it a fixed height, or move the other widgets to the opposite side.`\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mode, stretch, currentAnchor, ctx?.stacks, id]);\n\n // Report height whenever size changes so stack peers can compute their offset.\n useEffect(() => {\n ctx?.reportDockedSize(id, size.h);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [size.h]);\n\n const zOrder = ctx?.zOrders[id] ?? 101;\n\n const isActive = !ctx || ctx.topId === id;\n\n const getContainerBounds = (): { cw: number; ch: number } => {\n const container = windowRef.current?.offsetParent as HTMLElement | null;\n return { cw: container?.clientWidth ?? 9999, ch: container?.clientHeight ?? 9999 };\n };\n\n /**\n * The band a docked widget is allowed to occupy, in physical pixels from the container's edges.\n *\n * The block axis keeps clear of top/bottom `PanelToolbar`s only; the inline axis also adds the\n * `DOCK_INSET` gutter, matching how a docked widget is already positioned (one inline inset of\n * `DOCK_INSET`, one block inset of the toolbar size). Growth previously stopped at the raw\n * container edge, so a docked widget could be resized straight over the toolbar on the far side —\n * which the library elsewhere treats as a bug (a 5.x fix stopped docked floats *positioning*\n * themselves over a toolbar; the resize path never got the same treatment).\n *\n * Inline is converted from logical to physical here because handle directions and measured rects\n * are physical, while `PanelToolbar` claims its space logically.\n */\n const dockedBand = (): { left: number; right: number; top: number; bottom: number } => {\n const logicalStart = ctx?.insetInlineStart ?? 0;\n const logicalEnd = ctx?.insetInlineEnd ?? 0;\n return {\n left: (isRtl ? logicalEnd : logicalStart) + DOCK_INSET,\n right: (isRtl ? logicalStart : logicalEnd) + DOCK_INSET,\n top: ctx?.insetTop ?? 0,\n bottom: ctx?.insetBottom ?? 0,\n };\n };\n\n const handleWindowPointerDown = (): void => {\n ctx?.focusWindow(id);\n };\n\n const handleHeaderPointerDown = (e: React.PointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return;\n e.preventDefault();\n\n let startX: number;\n let startY: number;\n\n if (modeRef.current === 'docked') {\n // Snapshot the rendered position so that *if* this becomes a real drag, switching to free\n // positioning causes no visual jump. Undocking itself is deferred to the drag threshold\n // below — doing it here meant a plain click on the header silently tore the widget off its\n // anchor: it looked unchanged, but its stacked siblings reflowed to close the gap and it\n // stopped tracking the corner on every later panel resize.\n const el = windowRef.current;\n const container = ctx?.containerRef?.current;\n if (el && container) {\n const elRect = el.getBoundingClientRect();\n const cRect = container.getBoundingClientRect();\n startX = elRect.left - cRect.left;\n startY = elRect.top - cRect.top;\n } else {\n startX = DOCK_INSET;\n startY = ctx?.insetTop ?? 0;\n }\n } else {\n startX = freePosRef.current?.x ?? 0;\n startY = freePosRef.current?.y ?? 0;\n }\n\n dragState.current = { mouseX: e.clientX, mouseY: e.clientY, posX: startX, posY: startY, hasDragged: false };\n windowRef.current?.setPointerCapture(e.pointerId);\n };\n\n const handleResizePointerDown = (dir: ResizeDir) => (e: React.PointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n // Snapshot current rendered position for offset-from-edge calculations\n let startX = 0, startY = 0;\n if (modeRef.current === 'free') {\n startX = freePosRef.current?.x ?? 0;\n startY = freePosRef.current?.y ?? 0;\n } else {\n const el = windowRef.current;\n const container = el?.offsetParent as HTMLElement | null;\n if (el && container) {\n const er = el.getBoundingClientRect();\n const cr = container.getBoundingClientRect();\n startX = er.left - cr.left;\n startY = er.top - cr.top;\n }\n }\n // For a stretched axis the stored size is stale by design (the render branch stops reading it),\n // so the drag has to start from the *measured* extent or the widget would jump.\n const measured = windowRef.current?.getBoundingClientRect();\n const startRect = {\n x: startX,\n y: startY,\n w: stretchesInline(stretchRef.current) && measured ? measured.width : sizeRef.current.w,\n h: stretchesBlock(stretchRef.current) && measured ? measured.height : sizeRef.current.h,\n };\n\n // Dragging an end of a stretched axis releases that axis: the edge under the pointer becomes\n // the moving one and the opposite end becomes the new pin, so it reads exactly like an ordinary\n // resize. Done once per drag; `released` guards against repeat moves before the re-render.\n const dragsInline = dir.includes('e') || dir.includes('w');\n const dragsBlock = dir.includes('n') || dir.includes('s');\n let released = false;\n let armed = { inline: false, block: false };\n const releaseIfNeeded = (): void => {\n if (released || modeRef.current !== 'docked') return;\n const st = stretchRef.current;\n const releasingInline = dragsInline && stretchesInline(st);\n const releasingBlock = dragsBlock && stretchesBlock(st);\n if (!releasingInline && !releasingBlock) return;\n released = true;\n\n let next = st;\n let nextAnchor = currentAnchorRef.current;\n if (releasingInline) {\n next = releaseAxis(next, 'inline');\n // Pin the end opposite the dragged edge. Handle dirs are physical, anchors are logical.\n const pinsPhysicalLeft = dir.includes('e');\n nextAnchor = withInlineHalf(nextAnchor, (pinsPhysicalLeft !== isRtl) ? 'left' : 'right');\n }\n if (releasingBlock) {\n next = releaseAxis(next, 'block');\n nextAnchor = withBlockHalf(nextAnchor, dir.includes('s') ? 'top' : 'bottom');\n }\n applyPlacement(nextAnchor, next);\n };\n\n startPointerDrag({\n element: e.currentTarget,\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n captureStart: () => startRect,\n activeClasses: [{ el: document.body, classes: ['rdd-resizing-active'] }],\n onMove: (dx, dy, start) => {\n // Re-measured every move, matching the original's live re-measurement —\n // the container can in principle change size during a drag.\n const { cw, ch } = getContainerBounds();\n // Docked widgets stop at the toolbar band; free-floating ones stay unconstrained beyond the\n // container itself, since \"free\" means free.\n const band = modeRef.current === 'docked'\n ? dockedBand()\n : { left: 0, right: 0, top: 0, bottom: 0 };\n const { x: newX, y: newY, w: newW, h: newH } = computeResizedRect(dir, dx, dy, start, {\n minW: MIN_W, minH: MIN_H,\n maxW: (cw - band.right) - start.x, maxH: (ch - band.bottom) - start.y,\n minX: band.left, minY: band.top,\n });\n releaseIfNeeded();\n\n // ── resize-to-stretch snapping ──\n // The clamps above already stop growth exactly where a stretched axis would sit, so an\n // armed drag is already visually at its target; the cue is an outline rather than a ghost.\n if (modeRef.current === 'docked' && stretchable) {\n const fullInline = cw - band.left - band.right;\n const fullBlock = ch - band.top - band.bottom - stackOffsetRef.current;\n const st = stretchRef.current;\n const nextArmed = { ...armed };\n if (dragsInline && !stretchesInline(st)) {\n if (newW >= fullInline - SNAP_IN) nextArmed.inline = true;\n else if (armed.inline && newW < fullInline - SNAP_OUT) nextArmed.inline = false;\n }\n if (dragsBlock && !stretchesBlock(st)) {\n if (newH >= fullBlock - SNAP_IN) nextArmed.block = true;\n else if (armed.block && newH < fullBlock - SNAP_OUT) nextArmed.block = false;\n }\n if (nextArmed.inline !== armed.inline || nextArmed.block !== armed.block) {\n armed = nextArmed;\n setSnapArmed(nextArmed);\n }\n }\n // Only write an axis that carries a size. A still-stretched axis must keep its stored\n // value, so releasing it later restores the size it had before stretching.\n const st = released ? releaseAxis(releaseAxis(stretchRef.current,\n dragsInline ? 'inline' : 'block'), dragsBlock ? 'block' : 'inline') : stretchRef.current;\n setSize(prev => ({\n w: stretchesInline(st) ? prev.w : newW,\n h: stretchesBlock(st) ? prev.h : newH,\n }));\n if (modeRef.current === 'free') {\n setFreePos({ x: newX, y: newY });\n }\n },\n onEnd: (start) => {\n if (!armed.inline && !armed.block) {\n if (snapArmedRef.current.inline || snapArmedRef.current.block) {\n setSnapArmed({ inline: false, block: false });\n }\n return;\n }\n // Restore the size the axis had *before* this drag: while an axis is stretched its stored\n // size is what releasing it later returns to, so it should be the size the user last chose\n // deliberately — not the full-bleed value the drag happened to pass through.\n setSize(prev => ({\n w: armed.inline ? start.w : prev.w,\n h: armed.block ? start.h : prev.h,\n }));\n let next = stretchRef.current;\n if (armed.inline) next = addAxis(next, 'inline');\n if (armed.block) next = addAxis(next, 'block');\n applyPlacement(currentAnchorRef.current, next);\n setSnapArmed({ inline: false, block: false });\n },\n });\n };\n\n const handleWindowPointerMove = (e: React.PointerEvent): void => {\n if (dragState.current) {\n const ds = dragState.current;\n if (!ds.hasDragged) {\n const dist = Math.abs(e.clientX - ds.mouseX) + Math.abs(e.clientY - ds.mouseY);\n if (dist < 4) return;\n ds.hasDragged = true;\n // This, not pointerdown, is the moment the widget leaves its anchor.\n if (modeRef.current === 'docked') {\n // A stretched axis carries no size, so free mode — which positions from an explicit box —\n // would otherwise snap back to whatever the size was before stretching. Materialise what\n // is actually on screen, then clear stretch: \"free\" and \"spanning the panel\" are\n // mutually exclusive.\n if (stretchRef.current) {\n const r = windowRef.current?.getBoundingClientRect();\n if (r) setSize({ w: Math.round(r.width), h: Math.round(r.height) });\n applyPlacement(currentAnchorRef.current, null);\n }\n ctx?.undockWindow(id);\n setMode('free');\n }\n document.body.classList.add('rdd-dragging-active');\n ctx?.setDraggingId(id);\n }\n const { cw, ch } = getContainerBounds();\n const newX = Math.max(0, Math.min(ds.posX + e.clientX - ds.mouseX, cw - sizeRef.current.w));\n const newY = Math.max(0, Math.min(ds.posY + e.clientY - ds.mouseY, ch - sizeRef.current.h));\n setFreePos({ x: newX, y: newY });\n\n const container = ctx?.containerRef?.current;\n if (container) {\n const rawZone = getHoveredZone(container, e.clientX, e.clientY);\n ctx?.setHoveredZone(rawZone && isRtl ? flipZoneHorizontal(rawZone) : rawZone);\n }\n }\n };\n\n const handleWindowPointerUp = (): void => {\n if (dragState.current?.hasDragged) {\n const zone = ctx?.hoveredZone;\n if (zone) {\n ctx?.dockWindow(id, zone, stretchRef.current);\n setMode('docked');\n setFreePos(null);\n applyPlacement(zone, stretchRef.current);\n }\n ctx?.setHoveredZone(null);\n ctx?.setDraggingId(null);\n }\n document.body.classList.remove('rdd-dragging-active');\n dragState.current = null;\n };\n\n const handleWindowPointerCancel = (): void => {\n if (dragState.current?.hasDragged) {\n ctx?.setHoveredZone(null);\n ctx?.setDraggingId(null);\n }\n document.body.classList.remove('rdd-dragging-active');\n dragState.current = null;\n };\n\n // ── Compute position style ─────────────────────────────────────────────────\n let windowStyle: React.CSSProperties;\n\n if (mode === 'docked' && ctx) {\n // Offset is the largest offset across every bucket this widget occupies, so a strip spanning\n // an edge clears whatever is stacked in *both* of that edge's corners.\n const buckets = bucketsFor(currentAnchor, stretch);\n let stackOffset = 0;\n // A widget with no buckets (block-stretched) is never \"in\" a stack, so it must not be held\n // invisible by the not-yet-registered guard below.\n let registered = buckets.length === 0;\n for (const bucket of buckets) {\n const stack = ctx.stacks[bucket] ?? [];\n const idx = stack.indexOf(id);\n if (idx === -1) continue;\n registered = true;\n let offset = 0;\n for (let i = 0; i < idx; i++) {\n offset += (ctx.dockedSizes[stack[i]] ?? defaultHeight) + DOCK_GAP;\n }\n stackOffset = Math.max(stackOffset, offset);\n }\n stackOffsetRef.current = stackOffset;\n\n const band = dockedBand();\n\n windowStyle = {\n zIndex: zOrder,\n transition: 'top 0.2s ease, bottom 0.2s ease',\n // Hide until registered in stack (first layout effect hasn't run yet)\n opacity: registered ? undefined : 0,\n pointerEvents: registered ? undefined : 'none',\n };\n\n // Inline axis: one inset plus an explicit width, or both insets and no width at all. Setting\n // both ends is the whole mechanism — CSS then keeps the widget spanning the panel for free.\n if (stretchesInline(stretch)) {\n windowStyle.insetInlineStart = (ctx.insetInlineStart ?? 0) + DOCK_INSET;\n windowStyle.insetInlineEnd = (ctx.insetInlineEnd ?? 0) + DOCK_INSET;\n } else {\n windowStyle[currentAnchor.endsWith('-right') ? 'insetInlineEnd' : 'insetInlineStart'] = DOCK_INSET;\n windowStyle.width = size.w;\n }\n\n // Block axis: same idea. Note the block insets carry no DOCK_INSET gutter, matching how a\n // docked widget has always been positioned against a top/bottom toolbar (flush, not inset).\n if (stretchesBlock(stretch)) {\n windowStyle.top = band.top;\n windowStyle.bottom = band.bottom;\n } else if (currentAnchor.startsWith('top-')) {\n windowStyle.top = band.top + stackOffset;\n windowStyle.height = size.h;\n } else {\n windowStyle.bottom = band.bottom + stackOffset;\n windowStyle.height = size.h;\n }\n } else {\n windowStyle = {\n left: freePos?.x ?? 0,\n top: freePos?.y ?? 0,\n width: size.w,\n height: size.h,\n zIndex: zOrder,\n };\n }\n\n // ── Which resize handles this window offers ────────────────────────────────\n // Free-floating: all eight, nothing is pinned.\n //\n // Docked: only the edges that can actually move. A docked window has one edge pinned per axis\n // (see the positioning block above — `top-*` pins `top`, `bottom-*` pins `bottom`, `*-left`\n // pins `insetInlineStart`, `*-right` pins `insetInlineEnd`), so dragging a handle on a pinned\n // side moves the *opposite* edge instead of the one under the cursor, and can't move it further\n // than that side's own inset before `computeResizedRect`'s bounds stop it — an inert stub with a\n // resize cursor on it. The handle set used to be hardcoded to the five non-northern directions\n // regardless of anchor, which made that harmless-looking for top anchors but left every\n // bottom-anchored window with no working vertical resize at all: `n` wasn't rendered, and `s`\n // was the stub.\n //\n // Restricting docked mode to free edges also means the existing resize bounds are already\n // correct for every direction that remains: `maxW`/`maxH` apply only to eastward/southward\n // growth (where the top-left origin genuinely is pinned), while `minX`/`minY` bound the moving\n // edge for westward/northward growth — so no change to the resize math is needed.\n const handleDirs: ResizeDir[] = React.useMemo(() => {\n if (mode === 'free') return ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'];\n\n // Block axis is direction-agnostic; the inline axis is not. The pin is a logical property\n // (`insetInlineEnd`) but the handle classes are physical (`.rdd-resize-e { right: -4px }`), so\n // which *physical* side is pinned depends on the window's own `dir`.\n const freeBlock: ResizeDir = currentAnchor.startsWith('top-') ? 's' : 'n';\n const pinsPhysicalRight = currentAnchor.endsWith('-right') !== isRtl;\n const freeInline: ResizeDir = pinsPhysicalRight ? 'w' : 'e';\n\n const inlineStretched = stretchesInline(stretch);\n const blockStretched = stretchesBlock(stretch);\n\n // A stretched axis has both ends pinned, but both are *releasable*: dragging either end moves\n // that edge and pins the opposite one, so the widget leaves stretch at the width the drag\n // produced. Hence handles on both ends — which is also what keeps the fully-stretched state\n // from being a dead end with nothing to grab.\n const dirs: ResizeDir[] = [];\n dirs.push(...(inlineStretched ? (['e', 'w'] as ResizeDir[]) : [freeInline]));\n dirs.push(...(blockStretched ? (['n', 's'] as ResizeDir[]) : [freeBlock]));\n // The corner belongs only to the all-pinned state; in a stretched state it would mix a resize\n // and a release into one gesture.\n if (!inlineStretched && !blockStretched) dirs.push(`${freeBlock}${freeInline}` as ResizeDir);\n return dirs;\n }, [mode, currentAnchor, isRtl, stretch]);\n\n const CloseIcon = (\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\">\n <line x1=\"1\" y1=\"1\" x2=\"9\" y2=\"9\" />\n <line x1=\"9\" y1=\"1\" x2=\"1\" y2=\"9\" />\n </svg>\n );\n\n return (\n <div\n ref={windowRef}\n dir={isRtl ? 'rtl' : 'ltr'}\n className={[\n 'rdd-panel-float',\n isActive ? 'rdd-panel-float--active' : '',\n snapArmed.inline || snapArmed.block ? 'rdd-panel-float--snapping' : '',\n ].filter(Boolean).join(' ')}\n style={windowStyle}\n onPointerDown={handleWindowPointerDown}\n onPointerMove={handleWindowPointerMove}\n onPointerUp={handleWindowPointerUp}\n onPointerCancel={handleWindowPointerCancel}\n >\n <div className=\"rdd-panel-float__header\" onPointerDown={handleHeaderPointerDown}>\n {icon && <span className=\"rdd-panel-float__icon\">{icon}</span>}\n <span className=\"rdd-panel-float__title\">{formatLabel(title, formatMessage)}</span>\n <button\n type=\"button\"\n className=\"rdd-panel-float__close\"\n onClick={onClose}\n onPointerDown={e => e.stopPropagation()}\n title={formatLabel(messages.closeTooltip, formatMessage)}\n aria-label={formatLabel(messages.closeTooltip, formatMessage)}\n >\n {CloseIcon}\n </button>\n </div>\n <div className=\"rdd-panel-float__body\">{children}</div>\n {handleDirs.map(dir => (\n <div\n key={dir}\n className={`rdd-resize-handle rdd-resize-${dir}`}\n onPointerDown={handleResizePointerDown(dir)}\n />\n ))}\n </div>\n );\n}\n\n// ─── usePanelFloatingWindow ───────────────────────────────────────────────────\n\n/** Return type of `usePanelFloatingWindow`. @see usePanelFloatingWindow */\nexport interface UsePanelFloatingWindowReturn {\n /** Whether the floating window is currently open. */\n isOpen: boolean;\n /** Open the floating window. */\n open(): void;\n /** Close the floating window. */\n close(): void;\n}\n\n/**\n * Manages the open/close boolean state for a single `PanelFloatingWindow`.\n * Pass `isOpen` to `open`, `close` to `onClose` on the component directly.\n * @returns A stable `UsePanelFloatingWindowReturn` object.\n * @example\n * const info = usePanelFloatingWindow();\n * <PanelFloatingWindow id=\"info\" open={info.isOpen} onClose={info.close} ... />\n */\nexport function usePanelFloatingWindow(): UsePanelFloatingWindowReturn {\n const [isOpen, setIsOpen] = useState(false);\n const open = useCallback((): void => { setIsOpen(true); }, []);\n const close = useCallback((): void => { setIsOpen(false); }, []);\n return { isOpen, open, close };\n}\n\n// ─── usePanelFloatingWindowManager ───────────────────────────────────────────\n\nconst EMPTY_IDS: string[] = [];\n\n/**\n * Imperative handle returned by `usePanelFloatingWindowManager`.\n * @see usePanelFloatingWindowManager\n */\nexport interface PanelFloatingWindowManagerHandle {\n /** Spawn or reconfigure a named window. Safe to call with an already-open ID to update config. */\n open(id: string, config: ManagedWindowConfig): void;\n /** Close a named window by ID. No-op if the window is not open. */\n close(id: string): void;\n /** Close all managed windows. */\n closeAll(): void;\n /** Returns `true` if the named window is currently open. */\n isOpen(id: string): boolean;\n /** IDs of all currently open managed windows. Changes to this array trigger re-renders. */\n openIds: string[];\n}\n\n/**\n * Imperative hook for spawning N named floating windows at runtime from data or event handlers.\n * All windows share z-ordering, drag, and corner-docking infrastructure of the `PanelOverlayRoot`,\n * and accept the same placement options — including {@link ManagedWindowConfig.stretch} to span an\n * axis of the panel.\n *\n * Must be called inside a **descendant** of `PanelOverlayRoot`, not in the component that renders the root.\n * @returns A stable `PanelFloatingWindowManagerHandle`.\n * @example\n * const manager = usePanelFloatingWindowManager();\n * manager.open('feature-42', { title: 'Feature 42', content: <FeatureDetail id={42} />, anchor: 'top-right' });\n *\n * // A full-width strip along the bottom edge:\n * manager.open('timeline', { title: 'Timeline', content: <Timeline />, anchor: 'bottom-left', stretch: 'width', height: 120 });\n */\nexport function usePanelFloatingWindowManager(): PanelFloatingWindowManagerHandle {\n const ctx = useContext(PanelManagerContext);\n const ids = ctx?.managedWindowIds ?? EMPTY_IDS;\n\n return useMemo(() => ({\n open: (id: string, config: ManagedWindowConfig) => ctx?.openManaged(id, config),\n close: (id: string) => ctx?.closeManaged(id),\n closeAll: () => ctx?.closeAllManaged(),\n isOpen: (id: string) => ids.includes(id),\n openIds: ids,\n }), [ctx, ids]);\n}\n"],"mappings":"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","names":["React","useState","useRef","useEffect","useCallback","useContext","createPortal","createContext","useContext","useState","useRef","useMemo","useCallback","useEffect","useSyncExternalStore","createContext","useContext","useSyncExternalStore","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","usePanelSize","onResize","getDimensions","onStoreChange","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","isValidElement","isSerializable","value","type","proto","jsx","WindowStateContext","createContext","WindowActionsContext","WindowI18nContext","WindowStoreSyncContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","useContext","RegistryContext","PanelRegistry","useRegistry","PanelEventBus","event","callback","cb","data","EMPTY_LEAF","isVisibleActiveTarget","id","scope","info","w","isLeafSelection","node","deriveActivePanelId","isCandidate","fromLeaves","child","found","selected","frontmost","parseLayoutPayload","parsed","floating","fw","anchor","_sr","_sb","rest","persisted","activePanelId","parseInitialState","json","payload","WindowManagerProvider","children","client","formatMessage","predefinedMessages","dirProp","modalClass","modalBodyClass","sidePanelClass","sidePanelBodyClass","windowClass","windowBodyClass","zIndexBaseProp","registry","useRef","effectiveFormatMessage","effectivePredefinedMessages","effectiveDir","effectiveZIndexBase","state","setState","useState","stateRef","stateSubscribersRef","useEffect","getSnapshot","useCallback","subscribeToState","closeGuardsRef","stateProvidersRef","mergedMessages","useMemo","eventBusRef","maxZRef","subscribe","publish","getCascadedPosition","fav","currentFloating","x","y","width","height","isOverlapping","pos","wx","wy","attempts","viewW","viewH","focusPanel","prev","panel","win","alreadyTop","selectActiveInTree","removePanelFromTree","idx","panels","p","updatedLeaf","c","sizes","sum","a","b","s","addPanelToLeaf","leafId","panelId","findFirstLeafId","openPanel","component","options","resolvedId","match","isNew","isRedirect","shouldFocus","serializable","isSerializable","exists","entry","title","target","favPos","nextMinimized","m","cascaded","firstLeaf","newPanelInfo","nextPanels","closePanel","nextRoot","nextFloating","nextActivePanelId","registerCloseGuard","guard","unregisterCloseGuard","registerStateProvider","provider","unregisterStateProvider","setPanelDirty","dirty","updatePanelTitle","requestClosePanel","minimizePanel","wasActive","lastFloatingRect","lastLeafId","findLeafForPanel","res","restorePanel","wasMinimized","prevState","nextActive","leafExists","targetId","parentLeafExists","canDrag","targetLeafId","floatPanel","rect","cleanRoot","dockPanel","splitLeafInTree","position","splitRatio","newLeaf","orientation","setDraggedPanelId","dockPanelToGroup","newRoot","dockPanelToWorkspaceEdge","r","movePanelOrder","targetIndex","insertInLeaf","remaining","index","newPanels","closeLeafGroup","removeLeafFromTree","maximizePanel","updateSplitSizes","path","updateInTree","depth","i","updateFloatingPosition","updates","saveLayout","currentPanels","excludedIds","includedPanels","dynamicValue","hasDynamicValue","effectiveProps","effectiveSerializable","gridRoot","minimized","liveActive","loadLayout","layoutJson","e","setActivePanel","setDirection","dir","isOpen","getOpenPanelIds","findPanelId","dedupeKey","customMenuGettersRef","showContextMenuFnRef","registerContextMenuFn","fn","showContextMenu","registerPanelContextMenu","getItems","getPanelContextMenuItems","actions","defaultFormatMessage","msg","text","key","value","styleClasses","syncContextValue","noopSubscribe","_cb","useWindowManagerState","selector","stateCtx","syncCtx","selectorRef","syncResult","useSyncExternalStore","snap","useWindowManagerActions","ctx","useWindowManagerActionsInternal","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","usePanelId","useFormContainer","usePanelContextMenu","items","itemsRef","React","forwardRef","useImperativeHandle","useState","useRef","useEffect","useLayoutEffect","createPortal","Fragment","jsx","jsxs","getCoords","event","resolveLabel","label","fmt","isSeparator","item","isSubMenu","SubMenuPanel","items","x","y","theme","onClose","onMouseEnter","onMouseLeave","ref","el","r","PAD","i","simple","showChk","isChecked","isDisabled","CLOSED","ContextMenu","formatMessageProvider","onShow","onHide","onOpenChange","className","style","menuState","setMenuState","submenuIndex","setSubmenuIndex","menuRef","submenuPanelRef","itemRefs","timers","close","coords","dismiss","e","onKey","submenuX","submenuY","itemEl","ir","cancelOpenTimer","cancelCloseTimer","handleItemMouseEnter","index","handleItemMouseLeave","sub","DefaultContextMenuAdapter","ContextMenuContext","ContextMenuProvider","adapter","children","componentProps","isOpen","setIsOpen","show","opts","useShowContextMenu","ctx","createContext","useContext","useState","useCallback","useMemo","useRef","jsx","idCounter","generateId","closeHandlers","initialState","PanelStateContext","PanelActionsContext","PanelProvider","children","state","setState","stateRef","registerCloseHandler","id","handler","unregisterCloseHandler","openLeftPanel","Component","props","options","currentPanel","instance","s","openRightPanel","openModal","formTitle","modalOptions","close","m","closeAll","closeAllModals","getInstance","updateInstance","updates","setDirty","dirty","actions","usePanelState","ctx","usePanelActions","useEffect","useRef","jsx","jsxs","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","useRef","useEffect","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","flipZoneHorizontal","zone","startPointerDrag","config","element","pointerId","startClientX","startClientY","captureStart","onMove","onEnd","activeClasses","el","classes","start","handleMove","e","handleEnd","computeResizedRect","dir","dx","dy","constraints","minW","minH","maxW","maxH","minX","minY","x","y","w","h","maxDx","minDx","clampedDx","maxDy","minDy","clampedDy","useEffect","useState","useColorScheme","scheme","setScheme","updateScheme","observer","Fragment","jsx","jsxs","findLeaf","node","leafId","child","found","domCache","hiddenContainerId","DefaultGridIcon","ContextMenuIcons","getOrCreateDomCacheElement","id","el","renderPanelContent","panel","registry","componentKey","registryEntry","Component","activePanelDimensions","panelLifecycleRegistry","getOrCreateLifecycleRegistry","panelId","entry","PreservedDOMWrapper","hostRef","useRef","useEffect","host","cachedEl","resizeObserver","entries","width","height","lifecycle","h","hiddenContainer","PreviewDOMWrapper","state","useWindowManagerState","useRegistry","formatMessage","useFormatMessage","regEntry","disableLivePreview","lastSize","origW","origH","scale","displayW","displayH","rawTitle","title","formatLabel","initialChar","FormContainerProviderWrapper","children","requestClosePanel","setPanelDirty","registerCloseGuard","unregisterCloseGuard","registerStateProvider","unregisterStateProvider","updatePanelTitle","minimizePanel","useWindowManagerActions","isMin","prevMinRef","isActive","prevActiveRef","wasActive","rawPanelState","derivedContainerType","prevContainerTypeRef","prevType","initialContainerTypeRef","contract","React","options","dirty","handler","getState","reg","FormContainerProvider","WorkspaceGrid","path","onTabRightClick","activeDropZone","onHoverDropZone","onTabDragStart","hoveredTab","onTabHover","defaultPanelIcon","onRequestClosePanel","updateSplitSizes","LeafGroup","isRow","handleResizerPointerDown","idx","e","resizerEl","parentEl","parentSize","startPointerDrag","dx","dy","startSizes","deltaPercentage","newSizes","size","leaf","openPanel","closeLeafGroup","setActivePanel","useWindowManagerActionsInternal","messages","usePredefinedMessages","windowClass","windowBodyClass","useStyleClasses","tabContainerRef","tabScroll","setTabScroll","useState","updateTabScroll","useCallback","ro","scrollTabs","dir","selectTab","isSelected","isGloballyActive","isHovered","isLast","isHoveredEmpty","sideClass","tabFocusClass","rect","side","pos","pct","rem","WindowManager","skin","taskbarVisibility","contextMenuAdapter","DefaultContextMenuAdapter","animations","restorePanel","maximizePanel","updateFloatingPosition","focusPanel","floatPanel","setDraggedPanelId","dockPanelToGroup","movePanelOrder","dockPanelToWorkspaceEdge","getPanelContextMenuItems","showContextMenu","registerContextMenuFn","openModal","usePanelActions","handleRequestClose","customOpts","resolve","opts","baseTitle","ConfirmationForm_default","ctxMenu","useContext","ContextMenuContext","contextMenuRef","taskbarRef","taskbarExpanded","setTaskbarExpanded","taskbarCollapseTimerRef","prevMinimizedLengthRef","hoveredMinimized","setHoveredMinimized","minimizedTooltipTimeoutRef","lastTaskbarPointerTypeRef","internalContextMenuOpen","setInternalContextMenuOpen","isContextMenuOpen","m","setActiveDropZone","activeDropZoneRef","dragPos","setDragPos","activeEdgeDrop","setActiveEdgeDropState","activeEdgeDropRef","setActiveEdgeDrop","val","activeCornerAnchor","setActiveCornerAnchorState","activeCornerAnchorRef","setActiveCornerAnchor","isRtl","WindowStateContext","setHoveredTab","hoveredTabRef","handleTabHover","index","handleHoverDropZone","position","updateHoverFromPoint","x","y","elements","foundDropZone","foundEdge","foundTab","tabIdx","LONG_PRESS_MS","CANCEL_MOVE_PX","clearDragState","flipRtl","executeDrop","me","dropZone","targetTab","edgeDrop","cornerAnchor","targetIndex","targetLeaf","currentIdx","flipZoneHorizontal","handleTabDragStart","startX","startY","pointerId","cancelled","cancel","timer","onPreMove","dragStarted","onMove","onEnd","onCancel","handleTabRightClick","items","custom","finalItems","handleMinimizedRightClick","keys","cachedId","handleWindowBlur","workspaceRef","workspaceSize","setWorkspaceSize","heightWarnShown","observer","culprit","cursor","tag","cls","who","viewW","viewH","w","winW","winH","winX","winY","newWidth","newHeight","newX","newY","changed","maxX","maxY","handlePointerDownGlobal","target","windowEl","winId","panelEl","startDrag","floatingWin","startPosX","startPosY","executeFWDrop","startResize","startRect","parsedX","parsedY","parsedW","parsedH","isRightSnapped","isBottomSnapped","start","resized","computeResizedRect","newW","newH","scrollTaskbar","direction","amount","expandTaskbar","scheduleCollapseTaskbar","currentColorScheme","useColorScheme","corner","isMaximized","isDragged","isFocused","w_","h_","stack","fw","stackOffset","i","sh","isTop","customItems","icon","onShortTap","createPortal","tooltipId","targetEl","WindowManager_default","WorkspaceClient","config","PanelRegistryClass","id","def","actions","entry","pending","fn","event","cb","idx","args","a","component","dedupeKey","json","dir","path","sizes","updates","targetLeafId","position","panelId","targetIndex","leafId","guard","provider","dirty","options","title","data","callback","d","useContext","createContext","useContext","useMemo","useState","jsx","ToolbarContext","ToolbarProvider","children","radioGroups","setRadioGroups","modifiers","setModifiers","value","group","id","prev","active","useToolbar","ctx","createContext","useCallback","useContext","useLayoutEffect","useMemo","useRef","useSyncExternalStore","jsx","createPanelContributionStore","contributions","listeners","notify","l","panelId","contribution","listener","PanelContributionContext","createContext","PanelContributionProvider","children","store","useMemo","usePanelContribution","usePanelId","useContext","cleanupRef","useRef","useLayoutEffect","useActivePanelContribution","activePanelId","useWindowManagerState","s","subscribe","useCallback","onChange","getSnapshot","useSyncExternalStore","sidebarSectionToTab","section","fallbackIcon","useMergedToolbarItems","staticItems","active","useMergedSidebarTabs","staticTabs","jsx","DockableDesktopProvider","contextMenuAdapter","DefaultContextMenuAdapter","props","existingCtxMenu","useContext","ContextMenuContext","inner","ToolbarProvider","WindowManagerProvider","PanelContributionProvider","PanelProvider","ContextMenuProvider","useCallback","useRef","useEffect","useState","useMemo","Fragment","jsx","jsxs","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","sizeClass","showCloseButton","bodyPadding","bodyPaddingStyle","useEffect","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","useCallback","useRef","useEffect","useState","useMemo","useLayoutEffect","useState","useContainerRect","anchorRef","rect","setRect","container","measure","r","resizeObserver","Fragment","jsx","jsxs","SidePanelRendererItem","panel","position","defaultWidth","containerRect","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","useRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","useState","optionsRef","baseTitle","formatLabel","handleClose","useCallback","ConfirmationForm_default","canClose","useEffect","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","useMemo","displayTitle","handleKeyDown","e","width","widthStyle","bodyPadding","bodyPaddingStyle","FormContainerProvider","SidePanelAnchor","children","anchorRef","useContainerRect","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","React","useState","useEffect","useRef","useCallback","useImperativeHandle","useContext","useMemo","createContext","forwardRef","memo","jsx","jsxs","isRailTab","entry","isRailCustom","toRailArray","value","SidebarContext","createContext","SidebarTabContext","SidebarTabProvider","tabId","onClose","onOpen","setActiveTabId","children","useMemo","otherId","renderRailEntry","index","activeTabId","onTabClick","React","isActive","SidebarTabStrip","memo","tabs","headerEntries","footerEntries","isVisible","position","i","tab","SidebarResizeHandle","currentWidth","minWidth","maxWidth","onWidthChange","onResizeStart","onResizeEnd","e","el","activeClasses","startPointerDrag","dx","_dy","startWidth","newW","Sidebar","forwardRef","headerAction","footerAction","defaultWidth","controlledActiveTabId","onActiveTabChange","visible","onVisibilityChange","stripVisible","onStripVisibilityChange","showCloseButton","hideDefaultHeader","renderHeader","isSecondary","ref","isControlled","width","setWidthState","useState","setWidth","useCallback","px","isResizing","setIsResizing","internalActiveTabId","setInternalActiveTabId","normalizedHeaderEntries","normalizedFooterEntries","headerTabs","footerTabs","allTabs","mountedTabIds","setMountedTabIds","effectiveMountedTabIds","result","activeTabIdRef","useRef","useEffect","widthRef","id","prev","next","changed","t","useImperativeHandle","handleTabClick","handleClose","hasHeaderOverride","closeButtonWarnedRef","sidebarContextValue","isSidebarVisible","isStripVisible","isDrawerOpen","drawer","isCurrent","resizeHandle","SecondarySidebar","props","primary","useContext","opposite","useSidebar","ctx","useSidebarTab","forwardRef","useImperativeHandle","useState","useRef","useEffect","useLayoutEffect","createPortal","Fragment","jsx","jsxs","flyoutPosition","rect","position","isRtl","gap","ToolbarGroupButton","item","toolbar","isOpen","setIsOpen","useState","btnRect","setBtnRect","btnRef","useRef","flyoutRef","isControlled","activeId","activeSubItem","e","isActive","displayIcon","displayLabel","handleClick","prev","useLayoutEffect","el","r","PAD","useEffect","onMouseDown","target","onKey","createPortal","entry","i","isSubActive","renderItem","index","controlled","Toolbar","forwardRef","items","visible","onVisibilityChange","className","style","ref","useToolbar","isVertical","useImperativeHandle","collapseStyle","useCallback","useEffect","useLayoutEffect","useRef","useState","createPortal","jsx","jsxs","ToastEmitter","fn","message","opts","id","patch","e","emitter","toast","msg","promise","messages","result","err","InfoIcon","SuccessIcon","WarningIcon","ErrorIcon","CloseIcon","DEFAULT_ICONS","ToastItem","options","exiting","isLeft","showProgress","pauseOnHover","animation","onDismiss","onExited","divRef","bodyRef","timerRef","remainRef","startRef","paused","setPaused","startEntry","entryClass","setEntryClass","el","body","applyHeight","observer","raf","scheduleDismiss","ms","handle","fallback","handleMouseEnter","handleMouseLeave","cls","icon","resolveOpts","raw","defaultDuration","defaultClosable","ToastContainer","position","maxVisible","newestOnTop","progressBar","width","adapter","toasts","setToasts","queueRef","toastsRef","handleDismiss","prev","t","handleExited","promoted","filtered","newEntry","rawEntry","q","merged","AdapterContainer","dirMod","React","useState","useContext","createContext","useRef","useLayoutEffect","useCallback","useMemo","useEffect","createPortal","Fragment","jsx","jsxs","stretchesInline","s","stretchesBlock","addAxis","axis","releaseAxis","bucketsFor","anchor","stretch","withInlineHalf","a","half","withBlockHalf","ANCHORS","PanelToolbarContext","createContext","PanelManagerContext","PanelOverlayContext","DROP_ZONE_SIZE","getHoveredZone","container","clientX","clientY","rect","x","y","PanelOverlayRoot","children","className","style","toolbarSizes","setToolbarSizes","useState","zOrders","setZOrders","stacks","setStacks","dockedSizes","setDockedSizes","draggingId","setDraggingId","hoveredZone","setHoveredZone","topId","setTopId","managedWindows","setManagedWindows","zCounterRef","useRef","containerRef","registerToolbar","useCallback","pos","size","prev","next","focusWindow","id","z","dockWindow","buckets","bucket","i","undockWindow","reportDockedSize","openManaged","config","closeManaged","closeAllManaged","managedWindowIds","useMemo","toolbarCtxValue","managerCtxValue","coreCtxValue","DropZoneOverlay","cfg","PanelFloatingWindow","zone","PanelToolbar","position","variant","buttonVariant","buttonSize","ctx","useContext","ref","cleanupRef","useLayoutEffect","el","measure","ro","posStyle","sideStyle","sizeStyle","ToolbarButton","icon","onClick","disabled","title","ToolbarToggle","active","onToggle","ToolbarSeparator","ToolbarSpacer","ToolbarItem","ToolbarCenter","ToolbarSearchInput","placeholder","onSearch","onSelect","expanded","setExpanded","query","setQuery","results","setResults","dropdownPos","setDropdownPos","inputRef","abortRef","debounceRef","openSearch","closeSearch","handleQueryChange","e","q","ctrl","res","r","dropW","left","handleSelect","result","handleBlur","handleKeyDown","grouped","map","g","SearchIcon","createPortal","group","items","React","item","props","FloatingWindowBody","MIN_W","MIN_H","DOCK_INSET","DOCK_GAP","SNAP_IN","SNAP_OUT","defaultAnchor","defaultWidth","defaultHeight","defaultStretch","stretchProp","onPlacementChange","stretchable","onClose","isRtl","WindowStateContext","formatMessage","useFormatMessage","messages","usePredefinedMessages","mode","setMode","currentAnchor","setCurrentAnchor","internalStretch","setInternalStretch","isStretchControlled","freePos","setFreePos","setSize","windowRef","modeRef","freePosRef","sizeRef","stretchRef","currentAnchorRef","onPlacementChangeRef","snapArmed","setSnapArmed","snapArmedRef","stackOffsetRef","applyPlacement","dragState","blockStretchWarnedRef","useEffect","neighbours","other","zOrder","isActive","getContainerBounds","dockedBand","logicalStart","logicalEnd","handleWindowPointerDown","handleHeaderPointerDown","startX","startY","elRect","cRect","handleResizePointerDown","dir","er","cr","measured","startRect","dragsInline","dragsBlock","released","armed","releaseIfNeeded","st","releasingInline","releasingBlock","nextAnchor","pinsPhysicalLeft","startPointerDrag","dx","dy","start","cw","ch","band","newX","newY","newW","newH","computeResizedRect","fullInline","fullBlock","nextArmed","handleWindowPointerMove","ds","rawZone","flipZoneHorizontal","handleWindowPointerUp","handleWindowPointerCancel","windowStyle","stackOffset","registered","stack","idx","offset","handleDirs","freeBlock","freeInline","inlineStretched","blockStretched","dirs","CloseIcon","formatLabel","usePanelFloatingWindow","isOpen","setIsOpen","open","close","EMPTY_IDS","usePanelFloatingWindowManager","ids"]}
|