react-dockable-desktop 5.3.2 → 5.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/WindowManager.tsx","../src/components/WindowManagerContext.tsx","../src/components/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/hooks/useAnimationScrollGuard.ts","../src/components/SidePanelRenderer.tsx","../src/components/Sidebar.tsx","../src/components/Toolbar.tsx","../src/components/Toast.tsx","../src/components/PanelOverlay.tsx"],"sourcesContent":["/**\n * @file index.ts\n * @description Core entry point for react-dockable-desktop.\n * Exports public window manager components, contexts, hooks, type definitions, sidebar layouts, and overlay renderers.\n */\n\n// Core Components and Layouts\nexport { default as WindowManager } from './components/WindowManager';\nexport type { WindowManagerProps, TaskbarVisibility } from './components/WindowManager';\nexport { PanelRegistry, PanelRegistryClass } from './components/PanelRegistry';\nexport type { PanelRegistryEntry } from './components/PanelRegistry';\n\n// WorkspaceClient — primary configuration and imperative API object\nexport { WorkspaceClient } from './WorkspaceClient';\nexport type { WorkspaceClientConfig, PanelDefinition, BuiltInPanelEvents } from './WorkspaceClient';\n\n// Composite provider — wraps WindowManagerProvider + PanelProvider in correct order\nexport { DockableDesktopProvider } from './components/DockableDesktopProvider';\nexport type { DockableDesktopProviderProps } from './components/DockableDesktopProvider';\n\n// State Actions and Context Providers\nexport {\n WindowManagerProvider,\n useWindowManagerState,\n useWindowManagerActions,\n useRegistry,\n useFormatMessage,\n formatLabel,\n usePanelContext,\n usePredefinedMessages,\n defaultPredefinedMessages,\n useStyleClasses,\n usePanelId,\n usePanelContextMenu\n} from './components/WindowManagerContext';\n\n// Runtime serializability check — used internally to decide whether a panel's props can be\n// included in WorkspaceClient.saveLayout()'s output; exported so apps can apply the same check\n// themselves (e.g. before calling openPanel, to warn early rather than discover it at save time).\nexport { isSerializable } from './components/serializable';\n\n// TypeScript Types and Interfaces\nexport type {\n SplitOrientation,\n SplitDirection,\n DropPosition,\n DropTarget,\n LayoutGridNode,\n LayoutLeafNode,\n LayoutNode,\n FloatingWindow,\n PanelInfo,\n OpenPanelOptions,\n WindowState,\n WindowActions,\n SerializedLayout,\n ContextMenuPredefinedMessage,\n MessageFormatter,\n PredefinedMessageKey,\n StyleClasses,\n WindowManagerProviderProps,\n} from './components/WindowManagerContext';\n\n// Context menu — built-in component, types, and adapter interface\nexport {\n ContextMenu,\n DefaultContextMenuAdapter,\n ContextMenuProvider,\n useShowContextMenu,\n} from './components/ContextMenu';\nexport type {\n ContextMenuItem,\n ContextMenuSimpleItem,\n ContextMenuSeparator,\n ContextMenuSubMenu,\n ContextMenuCheckbox,\n ContextMenuLabel,\n MenuItemAction,\n ContextMenuHandle,\n ShowContextMenuOptions,\n ContextMenuAdapter,\n ContextMenuProps,\n} from './components/ContextMenu';\n\n// Form Container Context Contract\nexport {\n FormContainerContext,\n FormContainerProvider,\n useFormContainer,\n usePanelSize\n} from './components/FormContainerContext';\n\nexport type {\n CloseOptions,\n FormContainerContract\n} from './components/FormContainerContext';\n\n// Side Panels and Modal Stack Context\nexport {\n PanelProvider,\n usePanelState,\n usePanelActions\n} from './components/PanelProviderContext';\n\nexport type {\n PanelInstanceId,\n PanelTitle,\n SidePanelOptions,\n ModalOptions,\n PanelInstance,\n PanelState,\n PanelActions\n} from './components/PanelProviderContext';\n\n// Overlay Renderers\nexport { default as ModalStackRenderer } from './components/ModalStackRenderer';\nexport {\n default as SidePanelRenderer,\n LeftPanelRenderer,\n RightPanelRenderer\n} from './components/SidePanelRenderer';\nexport type { SidePanelRendererProps } from './components/SidePanelRenderer';\n\n// Reusable Forms\nexport { default as ConfirmationForm } from './forms/ConfirmationForm';\nexport type { ConfirmationFormProps } from './forms/ConfirmationForm';\n\n// Sidebar\nexport { Sidebar, useSidebar, useSidebarTab } from './components/Sidebar';\nexport type { SidebarTab, SidebarProps, SidebarHandle, SidebarContextValue, SidebarTabContextValue, SidebarHeaderAction, SidebarHeaderActionButton, SidebarHeaderActionCustom } from './components/Sidebar';\n\n// Toolbar\nexport { Toolbar, useToolbar, ToolbarProvider } from './components/Toolbar';\nexport type {\n ToolbarItem,\n ToolbarActionItem,\n ToolbarRadioItem,\n ToolbarToggleItem,\n ToolbarGroupItem,\n ToolbarGroupSubItem,\n ToolbarGroupEntry,\n ToolbarSeparator,\n ToolbarProps,\n ToolbarHandle,\n ToolbarContextValue,\n} from './components/Toolbar';\n\n// ─── Toast — imperative notification API, zero dependencies ──────────────────\nexport { toast, ToastContainer } from './components/Toast';\nexport type {\n ToastFunction,\n ToastOptions,\n ToastType,\n ToastPosition,\n ToastContainerProps,\n ToastAdapter,\n ResolvedToastOptions,\n ToastPromiseMessages,\n} from './components/Toast';\n\n// ─── Panel Overlay — optional; tree-shaken when unused ───────────────────────\nexport {\n PanelOverlayRoot,\n PanelToolbar,\n ToolbarButton,\n ToolbarToggle,\n ToolbarSearchInput,\n ToolbarSeparator as PanelToolbarSeparator,\n ToolbarSpacer,\n ToolbarCenter,\n ToolbarItem as PanelToolbarItem,\n PanelFloatingWindow,\n usePanelFloatingWindow,\n usePanelFloatingWindowManager,\n} from './components/PanelOverlay';\nexport type {\n PanelOverlayRootProps,\n PanelToolbarProps,\n ToolbarButtonProps,\n ToolbarToggleProps,\n ToolbarSearchInputProps,\n SearchResult,\n PanelFloatingWindowProps,\n ToolbarVariant,\n ButtonVariant,\n ToolbarPosition,\n FloatAnchor,\n ManagedWindowConfig,\n PanelFloatingWindowManagerHandle,\n UsePanelFloatingWindowReturn,\n} from './components/PanelOverlay';\n\n// ─── Panel Contributions — optional; active-panel-driven Toolbar/Sidebar content ───\nexport {\n PanelContributionProvider,\n usePanelContribution,\n useActivePanelContribution,\n sidebarSectionToTab,\n useMergedToolbarItems,\n useMergedSidebarTabs,\n} from './components/PanelContributionContext';\nexport type { PanelContribution, PanelSidebarSection } from './components/PanelContributionContext';\n\n// ─── Drag-resize primitives — build custom resizable UI inside your own panel content ───\nexport { startPointerDrag, computeResizedRect } from './components/dragResize';\nexport type { PointerDragConfig, ResizeDir, ResizeRect, ResizeConstraints } from './components/dragResize';\n\n// ─── Color scheme — reactive read of the workspace's current data-color-scheme ───\nexport { useColorScheme } from './hooks/useColorScheme';\n\n","/**\n * @file WindowManager.tsx\n * @description Core component for react-dockable-desktop layout engine.\n * Renders the workspace desktop containing docked splits, tabbed panels, floated windows,\n * resize handles, context menus, and taskbar docks. Exposes lifecycle event listeners.\n */\n\nimport React, { useState, useRef, useEffect, 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 >&#8249;</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 >&#8250;</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 `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 /** The ID of the active/focused panel. */\n activePanelId: string | null;\n /** Current layout direction ('ltr' or 'rtl') */\n dir: 'ltr' | 'rtl';\n /** Convenient boolean flag indicating RTL direction */\n isRtl: boolean;\n /** 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, and panel metadata.\n * @returns JSON string suitable for storage and later restoration via {@link loadLayout}.\n * @example\n * ```ts\n * localStorage.setItem('layout', actions.saveLayout());\n * ```\n */\n saveLayout: () => string;\n /**\n * Restores a previously serialized workspace from a JSON string.\n * Replaces the entire current layout — all panels not in the snapshot are closed.\n * @param layoutJson - JSON string produced by {@link saveLayout}.\n * @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 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\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 */\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 return { gridRoot: parsed.gridRoot, floating, minimized: parsed.minimized, panels: parsed.panels };\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) {\n return {\n ...payload,\n activePanelId: Object.keys(payload.panels)[0] ?? null,\n };\n }\n } catch {\n // fall through to empty canvas\n }\n }\n return { gridRoot: EMPTY_LEAF, floating: [], minimized: [], panels: {}, activePanelId: null };\n}\n\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 cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: prev.minimized.filter(m => m.id !== id),\n panels: nextPanels\n };\n });\n 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 cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: [...prev.minimized, { id, title: panel.title, component: panel.component }],\n panels: {\n ...prev.panels,\n [id]: {\n ...panel,\n state: 'minimized',\n previousState: panel.state,\n lastFloatingRect,\n lastLeafId\n }\n }\n };\n });\n 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 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 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 const firstActive = Object.keys(payload.panels)[0] || null;\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: firstActive\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 style={{ position: 'fixed', left: x, top: y, zIndex: 9501 }}\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 style={{ position: 'fixed', left: menuState.x, top: menuState.y, zIndex: 9500, ...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\n/** Configuration options applied when opening a Modal. */\nexport interface ModalOptions {\n /** Display title for the modal header. */\n title?: PanelTitle;\n /** Icon displayed in the modal title bar. */\n icon?: React.ReactNode;\n /** Size modifier affecting CSS max-width rules. */\n size?: 'small' | 'medium' | 'large' | 'fullscreen' | 'auto';\n /** If false, hides the modal backdrop exit click and header close button. */\n closable?: boolean;\n}\n\n/**\n * Represents a rendered instance of a panel or modal in the layout.\n */\nexport interface PanelInstance {\n /** Unique ID generated for this instance. */\n id: PanelInstanceId;\n /** React Component to mount inside the panel. */\n Component: ComponentType<any>;\n /** Property props passed to the Component. */\n props: Record<string, any>;\n /** The target rendering layout zone. */\n containerType: 'left-panel' | 'right-panel' | 'modal';\n /** Configuration metadata settings. */\n options: SidePanelOptions | ModalOptions;\n /** True if the form container has unsaved user edits. */\n dirty?: boolean;\n /** Custom warning options applied to the automatic unsaved changes modal. */\n dirtyOptions?: DirtyStateOptions;\n}\n\n/** Stores the active layout structures for floating overlays. */\nexport interface PanelState {\n /** The currently open left drawer panel instance, or null. */\n leftPanel: PanelInstance | null;\n /** The currently open right drawer panel instance, or null. */\n rightPanel: PanelInstance | null;\n /** Stack containing all active floating modal instances. */\n modals: PanelInstance[];\n}\n\n/** Exposes methods to trigger state actions on drawers and modals. */\nexport interface PanelActions {\n /** Mounts a panel in the left-side container drawer. */\n openLeftPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Mounts a panel in the right-side container drawer. */\n openRightPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Pushes a new modal component instance to the top of the stack. */\n openModal: <P extends object>(Component: ComponentType<P>, props: P, options?: ModalOptions) => PanelInstanceId;\n /** Closes an instance by ID. */\n close: (id: PanelInstanceId) => void;\n /** Closes all drawers and modals in a single action. */\n closeAll: () => void;\n /** Closes all open modals. */\n closeAllModals: () => void;\n /** Retrieves metadata for an active instance by ID. */\n getInstance: (id: PanelInstanceId) => PanelInstance | undefined;\n /** Updates the props, configuration options, or dirty flag of an active panel. */\n updateInstance: (id: PanelInstanceId, updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>) => void;\n /** Flags an instance as dirty (contains unsaved changes). */\n setDirty: (id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => void;\n /** Subscribes a custom close confirmation intercept handler. */\n registerCloseHandler: (id: PanelInstanceId, handler: () => Promise<boolean>) => void;\n /** Unsubscribes close confirmation handler. */\n unregisterCloseHandler: (id: PanelInstanceId) => void;\n}\n\nlet idCounter = 0;\nconst generateId = (): PanelInstanceId => `panel-${++idCounter}-${Date.now()}`;\n\nconst closeHandlers = new Map<PanelInstanceId, () => Promise<boolean>>();\n\nconst initialState: PanelState = {\n leftPanel: null,\n rightPanel: null,\n modals: [],\n};\n\nconst PanelStateContext = createContext<PanelState | null>(null);\nconst PanelActionsContext = createContext<PanelActions | null>(null);\n\n/**\n * PanelProvider component manages the state and action handlers\n * for drawers (left/right) and active stacked modal overlays.\n */\nexport const PanelProvider: React.FC<{ children: ReactNode }> = ({ children }) => {\n const [state, setState] = useState<PanelState>(initialState);\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const registerCloseHandler = useCallback((id: PanelInstanceId, handler: () => Promise<boolean>) => {\n closeHandlers.set(id, handler);\n }, []);\n\n const unregisterCloseHandler = useCallback((id: PanelInstanceId) => {\n closeHandlers.delete(id);\n }, []);\n\n const openLeftPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.leftPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'left-panel',\n options,\n };\n setState(s => ({ ...s, leftPanel: instance }));\n return id;\n },\n []\n );\n\n const openRightPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.rightPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'right-panel',\n options,\n };\n setState(s => ({ ...s, rightPanel: instance }));\n return id;\n },\n []\n );\n\n const openModal = useCallback(\n <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: ModalOptions = {}\n ): PanelInstanceId => {\n const id = generateId();\n const formTitle = (props as any).title;\n \n const modalOptions: ModalOptions = {\n ...options,\n title: options.title || formTitle || 'Confirmation',\n };\n\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'modal',\n options: modalOptions,\n };\n setState(s => ({ ...s, modals: [...s.modals, instance] }));\n return id;\n },\n []\n );\n\n const close = useCallback((id: PanelInstanceId) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? null : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? null : s.rightPanel,\n modals: s.modals.filter(m => m.id !== id),\n }));\n }, []);\n\n const closeAll = useCallback(() => {\n setState(initialState);\n }, []);\n\n const closeAllModals = useCallback(() => {\n setState(s => ({ ...s, modals: [] }));\n }, []);\n\n const getInstance = useCallback(\n (id: PanelInstanceId): PanelInstance | undefined => {\n if (state.leftPanel?.id === id) return state.leftPanel;\n if (state.rightPanel?.id === id) return state.rightPanel;\n return state.modals.find(m => m.id === id);\n },\n [state]\n );\n\n const updateInstance = useCallback(\n (\n id: PanelInstanceId,\n updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>\n ) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? { ...s.leftPanel, ...updates } : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? { ...s.rightPanel, ...updates } : s.rightPanel,\n modals: s.modals.map(m => m.id === id ? { ...m, ...updates } : m),\n }));\n },\n []\n );\n\n const setDirty = useCallback((id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => {\n updateInstance(id, { dirty, dirtyOptions: options });\n }, [updateInstance]);\n\n const actions = useMemo<PanelActions>(\n () => ({\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n }),\n [\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n ]\n );\n\n return (\n <PanelStateContext.Provider value={state}>\n <PanelActionsContext.Provider value={actions}>\n {children}\n </PanelActionsContext.Provider>\n </PanelStateContext.Provider>\n );\n};\n\n/**\n * React hook to retrieve the active floating/drawer panels state.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelState = (): PanelState => {\n const ctx = useContext(PanelStateContext);\n if (!ctx) throw new Error('usePanelState must be used within PanelProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve actions enabling drawer toggles and modal push actions.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelActions = (): PanelActions => {\n const ctx = useContext(PanelActionsContext);\n if (!ctx) throw new Error('usePanelActions must be used within PanelProvider');\n return ctx;\n};\n","import React, { useEffect, useRef } from 'react';\nimport { useFormContainer } from '../components/FormContainerContext';\nimport { useFormatMessage, usePredefinedMessages } from '../components/WindowManagerContext';\n\n/**\n * Props for the {@link ConfirmationForm} component.\n */\nexport interface ConfirmationFormProps {\n /** Optional custom title text or localizable descriptor for the dialog container. */\n title?: string | { id: string; defaultMessage?: string; values?: any };\n /** Main message text or localizable descriptor to display. */\n message: string | { id: string; defaultMessage?: string; values?: any };\n /** Optional auxiliary top alert notification text. */\n alert?: string;\n /** Type style classification for the alert notice banner. */\n alertType?: 'info' | 'warning' | 'success' | 'danger';\n /** If true, changes action button labels to 'Yes' and 'No' instead of 'OK' and 'Cancel'. */\n useYesNoTitles?: boolean;\n /** Callback fired when the user selects the confirm button. */\n onOK?: () => void;\n /** Callback fired when the user selects the cancel button. */\n onCancel?: () => void;\n}\n\n/**\n * ConfirmationForm component renders a standard dialog content layout,\n * allowing users to confirm actions or abort them. Exposes action callbacks.\n */\nexport const ConfirmationForm: React.FC<ConfirmationFormProps> = ({\n title,\n message,\n alert,\n alertType = 'info',\n useYesNoTitles = false,\n onOK,\n onCancel,\n}) => {\n const { requestClose, setIcon, setTitle } = useFormContainer();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const confirmButtonRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (title) {\n const resolvedTitle = typeof title === 'string' ? title : formatMessage(title);\n setTitle(resolvedTitle);\n }\n \n if (setIcon) {\n setIcon(<span>❓</span>);\n }\n }, [title, setTitle, setIcon, formatMessage]);\n\n useEffect(() => {\n confirmButtonRef.current?.focus({ 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 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 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 required, so supply `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';\nimport { useAnimationScrollGuard } from '../hooks/useAnimationScrollGuard';\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 // Matches the 0.18s scaleUp/fadeIn animation below — see useAnimationScrollGuard.\n useAnimationScrollGuard(180);\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 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 className={`rdd-modal-body ${modalBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\n/**\n * ModalStackRenderer component acts as the global container rendering\n * all active stacked modal windows in the workspace.\n */\nexport const ModalStackRenderer: React.FC = () => {\n const { modals } = usePanelState();\n\n if (modals.length === 0) return null;\n\n return (\n <>\n {modals.map((modal, index) => (\n <ModalRenderer\n key={modal.id}\n modal={modal}\n index={index}\n isTopmost={index === modals.length - 1}\n />\n ))}\n </>\n );\n};\n\nexport default ModalStackRenderer;\n","import { useEffect } from 'react';\n\n/**\n * Snaps the document back to its scroll position for `durationMs` after mount.\n *\n * Some enter-animated overlays (side panels, modals) mount their content in the\n * same commit as the animation that slides/scales them into view, so a child that\n * autofocuses on mount (native `autofocus`, MUI's `autoFocus`, or the library's\n * own internal `.focus()` calls) is still a real, focusable, laid-out DOM node\n * while visually off-screen — triggering the browser's native focus-scroll-into-view,\n * which has no scrollable containing block to stop at and walks up to the document.\n * That's the page jump. This hook doesn't know or care what caused the scroll; it\n * just undoes any scroll that happens during the animation window.\n */\nexport function useAnimationScrollGuard(durationMs: number): void {\n useEffect(() => {\n const x = window.scrollX;\n const y = window.scrollY;\n\n const handleScroll = () => window.scrollTo(x, y);\n window.addEventListener('scroll', handleScroll);\n\n const timeoutId = window.setTimeout(() => {\n window.removeEventListener('scroll', handleScroll);\n }, durationMs);\n\n return () => {\n window.clearTimeout(timeoutId);\n window.removeEventListener('scroll', handleScroll);\n };\n }, [durationMs]);\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, SidePanelOptions, PanelTitle } from './PanelProviderContext';\nimport type { DirtyStateOptions } from './dirtyOptions';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\nimport { useAnimationScrollGuard } from '../hooks/useAnimationScrollGuard';\n\n/**\n * Props for the internal {@link SidePanelRendererItem} component.\n */\ninterface SidePanelRendererItemProps {\n /** The panel instance containing metadata, component type, and rendering state. */\n panel: PanelInstance;\n /** Floating anchor edge side for the drawer panel. */\n position: 'left' | 'right';\n /** Default width applied if no panel override configuration is provided. */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRendererItem component renders an individual left or right drawer panel instance\n * wrapped inside the FormContainerProvider context. Handles dirty state verification before close.\n */\nconst SidePanelRendererItem: React.FC<SidePanelRendererItemProps> = ({ panel, position, defaultWidth }) => {\n const { close, openModal, updateInstance, setDirty, registerCloseHandler, unregisterCloseHandler } = usePanelActions();\n const { modals } = usePanelState();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const { dir } = useWindowManagerState();\n const { sidePanelClass, sidePanelBodyClass } = useStyleClasses();\n const closeHandlerRef = useRef<(() => boolean | Promise<boolean>) | null>(null);\n\n const { id, Component, props, options, dirty, dirtyOptions } = panel;\n const panelOptions = options as SidePanelOptions;\n const [icon, setIconState] = useState<React.ReactNode>(panelOptions.icon || null);\n\n const optionsRef = useRef(panelOptions);\n optionsRef.current = panelOptions;\n\n // Matches the 0.25s slideInLeft/slideInRight animation below — see useAnimationScrollGuard.\n useAnimationScrollGuard(250);\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 return (\n <div \n className={`rdd-side-panel rdd-side-panel-${position} rdd-side-panel-visible ${sidePanelClass ?? ''}`}\n style={{ width: widthStyle }}\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 className={`rdd-side-panel-body ${sidePanelBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\nexport interface SidePanelRendererProps {\n /**\n * Default panel width applied when openLeftPanel/openRightPanel do not specify one.\n * Accepts a number (treated as px) or any CSS width string (e.g. '40vw').\n * Falls back to 400px if omitted.\n */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRenderer component acts as the global container rendering both\n * left and right side drawers if they are currently active.\n */\nexport const SidePanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel, rightPanel } = usePanelState();\n return (\n <>\n {leftPanel && <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />}\n {rightPanel && <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />}\n </>\n );\n};\n\n/**\n * LeftPanelRenderer component renders ONLY the left side drawer if it is currently active.\n */\nexport const LeftPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel } = usePanelState();\n if (!leftPanel) return null;\n return <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />;\n};\n\n/**\n * RightPanelRenderer component renders ONLY the right side drawer if it is currently active.\n */\nexport const RightPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { rightPanel } = usePanelState();\n if (!rightPanel) return null;\n return <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />;\n};\n\nexport default SidePanelRenderer;\n","/**\n * @file Sidebar.tsx\n * @description Sidebar 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 icon: React.ReactNode;\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 */\n showCloseButton?: 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}\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 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 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 rootRef: React.RefObject<HTMLDivElement | null>;\n}\n\nfunction SidebarResizeHandle({\n position,\n currentWidth,\n minWidth,\n maxWidth,\n onWidthChange,\n rootRef,\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.\n if (rootRef.current) activeClasses.push({ el: rootRef.current, classes: ['rdd-sidebar-resizing'] });\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 });\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 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 // 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 // Ref to the root flex container — used by SidebarResizeHandle to toggle\n // the rdd-sidebar-resizing class that suppresses the CSS width transition during drag\n const rootRef = useRef<HTMLDivElement | null>(null);\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\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 }), [setActiveTabId]);\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 // transition is suppressed during drag via .rdd-sidebar-resizing on the root\n transition: '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 <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 {/* 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 rootRef={rootRef}\n />\n ) : null;\n\n return (\n <SidebarContext.Provider value={sidebarContextValue}>\n <div\n ref={rootRef}\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// 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 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 // Lock max-height for exit collapse animation\n useLayoutEffect(() => {\n if (divRef.current) {\n divRef.current.style.maxHeight = `${divRef.current.offsetHeight}px`;\n }\n }, []);\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 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\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\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): 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 insetTop: number;\n insetBottom: 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): void => {\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 next[anchor] = [...next[anchor], id];\n return 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 }), [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 >\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 style={{ position: 'fixed', top: dropdownPos.top, left: dropdownPos.left, width: dropdownPos.width, zIndex: 9502 }}\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. */\n defaultWidth: number;\n /** Initial height in pixels. */\n defaultHeight: number;\n children?: React.ReactNode;\n}\n\n/**\n * Declarative floating window anchored inside a `PanelOverlayRoot`.\n * Supports 8-direction resize, drag-to-free, and drag-to-dock at any corner.\n * Multiple windows docked to the same corner stack vertically with animated offsets.\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 */\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\nfunction FloatingWindowBody({ id, title, icon, defaultAnchor, defaultWidth, defaultHeight, 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 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\n const dragState = useRef<{ mouseX: number; mouseY: number; posX: number; posY: number; hasDragged: boolean } | null>(null);\n\n // Register in stack on mount; unregister on unmount (close).\n // Close resets to defaultAnchor on next open (fresh mount = fresh state).\n useLayoutEffect(() => {\n ctx?.dockWindow(id, defaultAnchor);\n return () => { ctx?.undockWindow(id); };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\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 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 rendered position before undocking so there's no visual jump\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 ctx?.undockWindow(id);\n setMode('free');\n setFreePos({ x: startX, y: startY });\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 document.body.classList.add('rdd-dragging-active');\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 const startRect = { x: startX, y: startY, w: sizeRef.current.w, h: sizeRef.current.h };\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 const { x: newX, y: newY, w: newW, h: newH } = computeResizedRect(dir, dx, dy, start, {\n minW: MIN_W, minH: MIN_H,\n maxW: cw - start.x, maxH: ch - start.y,\n minX: 0, minY: 0,\n });\n setSize({ w: newW, h: newH });\n if (modeRef.current === 'free') {\n setFreePos({ x: newX, y: newY });\n }\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 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) {\n const zone = ctx?.hoveredZone;\n if (zone) {\n ctx?.dockWindow(id, zone);\n setCurrentAnchor(zone);\n setMode('docked');\n setFreePos(null);\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) {\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 const stack = ctx.stacks[currentAnchor] ?? [];\n const idx = stack.indexOf(id);\n let stackOffset = 0;\n for (let i = 0; i < idx; i++) {\n stackOffset += (ctx.dockedSizes[stack[i]] ?? defaultHeight) + DOCK_GAP;\n }\n\n windowStyle = {\n width: size.w,\n height: size.h,\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: idx === -1 ? 0 : undefined,\n pointerEvents: idx === -1 ? 'none' : undefined,\n };\n\n windowStyle[currentAnchor.endsWith('-right') ? 'insetInlineEnd' : 'insetInlineStart'] = DOCK_INSET;\n\n if (currentAnchor.startsWith('top-')) {\n windowStyle.top = ctx.insetTop + stackOffset;\n } else {\n windowStyle.bottom = ctx.insetBottom + stackOffset;\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 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={`rdd-panel-float${isActive ? ' rdd-panel-float--active' : ''}`}\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 {mode === 'free' && <>\n <div className=\"rdd-resize-handle rdd-resize-n\" onPointerDown={handleResizePointerDown('n')} />\n <div className=\"rdd-resize-handle rdd-resize-ne\" onPointerDown={handleResizePointerDown('ne')} />\n <div className=\"rdd-resize-handle rdd-resize-nw\" onPointerDown={handleResizePointerDown('nw')} />\n </>}\n <div className=\"rdd-resize-handle rdd-resize-e\" onPointerDown={handleResizePointerDown('e')} />\n <div className=\"rdd-resize-handle rdd-resize-se\" onPointerDown={handleResizePointerDown('se')} />\n <div className=\"rdd-resize-handle rdd-resize-s\" onPointerDown={handleResizePointerDown('s')} />\n <div className=\"rdd-resize-handle rdd-resize-sw\" onPointerDown={handleResizePointerDown('sw')} />\n <div className=\"rdd-resize-handle rdd-resize-w\" onPointerDown={handleResizePointerDown('w')} />\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 *\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 */\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":["index_exports","__export","ConfirmationForm_default","ContextMenu","ContextMenuProvider","DefaultContextMenuAdapter","DockableDesktopProvider","FormContainerContext","FormContainerProvider","LeftPanelRenderer","ModalStackRenderer_default","PanelContributionProvider","PanelFloatingWindow","PanelOverlayRoot","PanelProvider","PanelRegistry","PanelRegistryClass","PanelToolbar","ToolbarItem","ToolbarSeparator","RightPanelRenderer","SidePanelRenderer_default","Sidebar","ToastContainer","Toolbar","ToolbarButton","ToolbarCenter","ToolbarProvider","ToolbarSearchInput","ToolbarSpacer","ToolbarToggle","WindowManager_default","WindowManagerProvider","WorkspaceClient","computeResizedRect","defaultPredefinedMessages","formatLabel","isSerializable","sidebarSectionToTab","startPointerDrag","toast","useActivePanelContribution","useColorScheme","useFormContainer","useFormatMessage","useMergedSidebarTabs","useMergedToolbarItems","usePanelActions","usePanelContext","usePanelContextMenu","usePanelContribution","usePanelFloatingWindow","usePanelFloatingWindowManager","usePanelId","usePanelSize","usePanelState","usePredefinedMessages","useRegistry","useShowContextMenu","useSidebar","useSidebarTab","useStyleClasses","useToolbar","useWindowManagerActions","useWindowManagerState","__toCommonJS","import_react","import_react_dom","import_react","import_react","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","usePanelSize","onResize","getDimensions","onStoreChange","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","import_react","isSerializable","value","type","proto","import_jsx_runtime","WindowStateContext","WindowActionsContext","WindowI18nContext","WindowStoreSyncContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","RegistryContext","PanelRegistry","useRegistry","PanelEventBus","event","callback","cb","data","EMPTY_LEAF","parseLayoutPayload","parsed","floating","fw","anchor","_sr","_sb","rest","parseInitialState","json","payload","WindowManagerProvider","children","client","formatMessage","predefinedMessages","dirProp","modalClass","modalBodyClass","sidePanelClass","sidePanelBodyClass","windowClass","windowBodyClass","zIndexBaseProp","registry","effectiveFormatMessage","effectivePredefinedMessages","effectiveDir","effectiveZIndexBase","state","setState","stateRef","stateSubscribersRef","getSnapshot","subscribeToState","closeGuardsRef","stateProvidersRef","mergedMessages","eventBusRef","maxZRef","subscribe","publish","getCascadedPosition","fav","currentFloating","x","y","width","height","isOverlapping","pos","w","wx","wy","attempts","viewW","viewH","focusPanel","id","prev","panel","win","alreadyTop","selectActiveInTree","node","removePanelFromTree","idx","panels","p","activePanelId","updatedLeaf","c","sizes","sum","a","b","s","addPanelToLeaf","leafId","panelId","findFirstLeafId","child","openPanel","component","options","resolvedId","match","isNew","isRedirect","shouldFocus","serializable","isSerializable","exists","entry","title","target","favPos","nextMinimized","m","cascaded","firstLeaf","newPanelInfo","nextPanels","closePanel","cleanRoot","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","dockPanel","nextFloating","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","info","dynamicValue","hasDynamicValue","effectiveProps","effectiveSerializable","gridRoot","minimized","loadLayout","layoutJson","firstActive","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","snap","useWindowManagerActions","ctx","useWindowManagerActionsInternal","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","usePanelId","useFormContainer","usePanelContextMenu","items","itemsRef","import_react","import_react_dom","import_jsx_runtime","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","React","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","import_react","import_jsx_runtime","idCounter","generateId","closeHandlers","initialState","PanelStateContext","PanelActionsContext","PanelProvider","children","state","setState","stateRef","registerCloseHandler","id","handler","unregisterCloseHandler","openLeftPanel","Component","props","options","currentPanel","instance","s","openRightPanel","openModal","formTitle","modalOptions","close","m","closeAll","closeAllModals","getInstance","updateInstance","updates","setDirty","dirty","actions","usePanelState","ctx","usePanelActions","import_react","import_jsx_runtime","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","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","import_react","useColorScheme","scheme","setScheme","updateScheme","observer","import_jsx_runtime","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","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","updateTabScroll","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","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","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","import_react","import_react","import_jsx_runtime","ToolbarContext","ToolbarProvider","children","radioGroups","setRadioGroups","modifiers","setModifiers","value","group","id","prev","active","useToolbar","ctx","import_react","import_jsx_runtime","createPanelContributionStore","contributions","listeners","notify","l","panelId","contribution","listener","PanelContributionContext","PanelContributionProvider","children","store","usePanelContribution","usePanelId","cleanupRef","useActivePanelContribution","activePanelId","useWindowManagerState","s","subscribe","onChange","getSnapshot","sidebarSectionToTab","section","fallbackIcon","useMergedToolbarItems","staticItems","active","useMergedSidebarTabs","staticTabs","import_jsx_runtime","DockableDesktopProvider","contextMenuAdapter","DefaultContextMenuAdapter","props","existingCtxMenu","ContextMenuContext","inner","ToolbarProvider","WindowManagerProvider","PanelContributionProvider","PanelProvider","ContextMenuProvider","import_react","import_react","useAnimationScrollGuard","durationMs","x","y","handleScroll","timeoutId","import_jsx_runtime","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","optionsRef","useAnimationScrollGuard","baseTitle","formatLabel","handleClose","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","sizeClass","showCloseButton","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","import_react","import_jsx_runtime","SidePanelRendererItem","panel","position","defaultWidth","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","optionsRef","useAnimationScrollGuard","baseTitle","formatLabel","handleClose","ConfirmationForm_default","canClose","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","handleKeyDown","e","width","widthStyle","FormContainerProvider","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","import_react","import_jsx_runtime","isRailTab","entry","isRailCustom","toRailArray","value","SidebarContext","SidebarTabContext","SidebarTabProvider","tabId","onClose","onOpen","setActiveTabId","children","otherId","renderRailEntry","index","activeTabId","onTabClick","React","isActive","SidebarTabStrip","tabs","headerEntries","footerEntries","isVisible","position","i","tab","SidebarResizeHandle","currentWidth","minWidth","maxWidth","onWidthChange","rootRef","e","el","activeClasses","startPointerDrag","dx","_dy","startWidth","newW","Sidebar","headerAction","footerAction","defaultWidth","controlledActiveTabId","onActiveTabChange","visible","onVisibilityChange","stripVisible","onStripVisibilityChange","showCloseButton","ref","isControlled","width","setWidthState","setWidth","px","internalActiveTabId","setInternalActiveTabId","normalizedHeaderEntries","normalizedFooterEntries","headerTabs","footerTabs","allTabs","mountedTabIds","setMountedTabIds","effectiveMountedTabIds","result","activeTabIdRef","widthRef","id","prev","next","changed","t","handleTabClick","handleClose","sidebarContextValue","isSidebarVisible","isStripVisible","isDrawerOpen","drawer","isCurrent","resizeHandle","useSidebar","ctx","useSidebarTab","import_react","import_react_dom","import_jsx_runtime","flyoutPosition","rect","position","isRtl","gap","ToolbarGroupButton","item","toolbar","isOpen","setIsOpen","btnRect","setBtnRect","btnRef","flyoutRef","isControlled","activeId","activeSubItem","e","isActive","displayIcon","displayLabel","handleClick","prev","el","r","PAD","onMouseDown","target","onKey","entry","i","isSubActive","renderItem","index","controlled","Toolbar","items","visible","onVisibilityChange","className","style","ref","useToolbar","isVertical","collapseStyle","import_react","import_react_dom","import_jsx_runtime","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","timerRef","remainRef","startRef","paused","setPaused","startEntry","entryClass","setEntryClass","raf","scheduleDismiss","ms","el","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","import_react","import_react_dom","import_jsx_runtime","ANCHORS","PanelToolbarContext","PanelManagerContext","PanelOverlayContext","DROP_ZONE_SIZE","getHoveredZone","container","clientX","clientY","rect","x","y","PanelOverlayRoot","children","className","style","toolbarSizes","setToolbarSizes","zOrders","setZOrders","stacks","setStacks","dockedSizes","setDockedSizes","draggingId","setDraggingId","hoveredZone","setHoveredZone","topId","setTopId","managedWindows","setManagedWindows","zCounterRef","containerRef","registerToolbar","pos","size","prev","next","focusWindow","id","z","dockWindow","anchor","undockWindow","reportDockedSize","openManaged","config","closeManaged","closeAllManaged","managedWindowIds","toolbarCtxValue","managerCtxValue","coreCtxValue","DropZoneOverlay","cfg","PanelFloatingWindow","zone","PanelToolbar","position","variant","buttonVariant","buttonSize","ctx","ref","cleanupRef","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","group","items","React","item","props","FloatingWindowBody","MIN_W","MIN_H","DOCK_INSET","DOCK_GAP","defaultAnchor","defaultWidth","defaultHeight","onClose","isRtl","WindowStateContext","mode","setMode","currentAnchor","setCurrentAnchor","freePos","setFreePos","setSize","windowRef","modeRef","freePosRef","sizeRef","dragState","zOrder","isActive","getContainerBounds","handleWindowPointerDown","handleHeaderPointerDown","startX","startY","elRect","cRect","handleResizePointerDown","dir","er","cr","startRect","startPointerDrag","dx","dy","start","cw","ch","newX","newY","newW","newH","computeResizedRect","handleWindowPointerMove","ds","rawZone","flipZoneHorizontal","handleWindowPointerUp","handleWindowPointerCancel","windowStyle","stack","idx","stackOffset","i","usePanelFloatingWindow","isOpen","setIsOpen","open","close","EMPTY_IDS","usePanelFloatingWindowManager","ids"]}
1
+ {"version":3,"sources":["../src/index.ts","../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/hooks/useAnimationScrollGuard.ts","../src/components/SidePanelRenderer.tsx","../src/components/Sidebar.tsx","../src/components/Toolbar.tsx","../src/components/Toast.tsx","../src/components/PanelOverlay.tsx"],"sourcesContent":["/**\n * @file index.ts\n * @description Core entry point for react-dockable-desktop.\n * Exports public window manager components, contexts, hooks, type definitions, sidebar layouts, and overlay renderers.\n */\n\n// Core Components and Layouts\nexport { default as WindowManager } from './components/WindowManager';\nexport type { WindowManagerProps, TaskbarVisibility } from './components/WindowManager';\nexport { PanelRegistry, PanelRegistryClass } from './components/PanelRegistry';\nexport type { PanelRegistryEntry } from './components/PanelRegistry';\n\n// WorkspaceClient — primary configuration and imperative API object\nexport { WorkspaceClient } from './WorkspaceClient';\nexport type { WorkspaceClientConfig, PanelDefinition, BuiltInPanelEvents } from './WorkspaceClient';\n\n// Composite provider — wraps WindowManagerProvider + PanelProvider in correct order\nexport { DockableDesktopProvider } from './components/DockableDesktopProvider';\nexport type { DockableDesktopProviderProps } from './components/DockableDesktopProvider';\n\n// State Actions and Context Providers\nexport {\n WindowManagerProvider,\n useWindowManagerState,\n useWindowManagerActions,\n useRegistry,\n useFormatMessage,\n formatLabel,\n usePanelContext,\n usePredefinedMessages,\n defaultPredefinedMessages,\n useStyleClasses,\n usePanelId,\n usePanelContextMenu\n} from './components/WindowManagerContext';\n\n// Runtime serializability check — used internally to decide whether a panel's props can be\n// included in WorkspaceClient.saveLayout()'s output; exported so apps can apply the same check\n// themselves (e.g. before calling openPanel, to warn early rather than discover it at save time).\nexport { isSerializable } from './components/serializable';\n\n// TypeScript Types and Interfaces\nexport type {\n SplitOrientation,\n SplitDirection,\n DropPosition,\n DropTarget,\n LayoutGridNode,\n LayoutLeafNode,\n LayoutNode,\n FloatingWindow,\n PanelInfo,\n OpenPanelOptions,\n WindowState,\n WindowActions,\n SerializedLayout,\n ContextMenuPredefinedMessage,\n MessageFormatter,\n PredefinedMessageKey,\n StyleClasses,\n WindowManagerProviderProps,\n} from './components/WindowManagerContext';\n\n// Context menu — built-in component, types, and adapter interface\nexport {\n ContextMenu,\n DefaultContextMenuAdapter,\n ContextMenuProvider,\n useShowContextMenu,\n} from './components/ContextMenu';\nexport type {\n ContextMenuItem,\n ContextMenuSimpleItem,\n ContextMenuSeparator,\n ContextMenuSubMenu,\n ContextMenuCheckbox,\n ContextMenuLabel,\n MenuItemAction,\n ContextMenuHandle,\n ShowContextMenuOptions,\n ContextMenuAdapter,\n ContextMenuProps,\n} from './components/ContextMenu';\n\n// Form Container Context Contract\nexport {\n FormContainerContext,\n FormContainerProvider,\n useFormContainer,\n usePanelSize\n} from './components/FormContainerContext';\n\nexport type {\n CloseOptions,\n FormContainerContract\n} from './components/FormContainerContext';\n\n// Side Panels and Modal Stack Context\nexport {\n PanelProvider,\n usePanelState,\n usePanelActions\n} from './components/PanelProviderContext';\n\nexport type {\n PanelInstanceId,\n PanelTitle,\n SidePanelOptions,\n ModalOptions,\n PanelInstance,\n PanelState,\n PanelActions\n} from './components/PanelProviderContext';\n\n// Overlay Renderers\nexport { default as ModalStackRenderer } from './components/ModalStackRenderer';\nexport {\n default as SidePanelRenderer,\n LeftPanelRenderer,\n RightPanelRenderer\n} from './components/SidePanelRenderer';\nexport type { SidePanelRendererProps } from './components/SidePanelRenderer';\n\n// Reusable Forms\nexport { default as ConfirmationForm } from './forms/ConfirmationForm';\nexport type { ConfirmationFormProps } from './forms/ConfirmationForm';\n\n// Sidebar\nexport { Sidebar, useSidebar, useSidebarTab } from './components/Sidebar';\nexport type { SidebarTab, SidebarProps, SidebarHandle, SidebarContextValue, SidebarTabContextValue, SidebarHeaderAction, SidebarHeaderActionButton, SidebarHeaderActionCustom } from './components/Sidebar';\n\n// Toolbar\nexport { Toolbar, useToolbar, ToolbarProvider } from './components/Toolbar';\nexport type {\n ToolbarItem,\n ToolbarActionItem,\n ToolbarRadioItem,\n ToolbarToggleItem,\n ToolbarGroupItem,\n ToolbarGroupSubItem,\n ToolbarGroupEntry,\n ToolbarSeparator,\n ToolbarProps,\n ToolbarHandle,\n ToolbarContextValue,\n} from './components/Toolbar';\n\n// ─── Toast — imperative notification API, zero dependencies ──────────────────\nexport { toast, ToastContainer } from './components/Toast';\nexport type {\n ToastFunction,\n ToastOptions,\n ToastType,\n ToastPosition,\n ToastContainerProps,\n ToastAdapter,\n ResolvedToastOptions,\n ToastPromiseMessages,\n} from './components/Toast';\n\n// ─── Panel Overlay — optional; tree-shaken when unused ───────────────────────\nexport {\n PanelOverlayRoot,\n PanelToolbar,\n ToolbarButton,\n ToolbarToggle,\n ToolbarSearchInput,\n ToolbarSeparator as PanelToolbarSeparator,\n ToolbarSpacer,\n ToolbarCenter,\n ToolbarItem as PanelToolbarItem,\n PanelFloatingWindow,\n usePanelFloatingWindow,\n usePanelFloatingWindowManager,\n} from './components/PanelOverlay';\nexport type {\n PanelOverlayRootProps,\n PanelToolbarProps,\n ToolbarButtonProps,\n ToolbarToggleProps,\n ToolbarSearchInputProps,\n SearchResult,\n PanelFloatingWindowProps,\n ToolbarVariant,\n ButtonVariant,\n ToolbarPosition,\n FloatAnchor,\n ManagedWindowConfig,\n PanelFloatingWindowManagerHandle,\n UsePanelFloatingWindowReturn,\n} from './components/PanelOverlay';\n\n// ─── Panel Contributions — optional; active-panel-driven Toolbar/Sidebar content ───\nexport {\n PanelContributionProvider,\n usePanelContribution,\n useActivePanelContribution,\n sidebarSectionToTab,\n useMergedToolbarItems,\n useMergedSidebarTabs,\n} from './components/PanelContributionContext';\nexport type { PanelContribution, PanelSidebarSection } from './components/PanelContributionContext';\n\n// ─── Drag-resize primitives — build custom resizable UI inside your own panel content ───\nexport { startPointerDrag, computeResizedRect } from './components/dragResize';\nexport type { PointerDragConfig, ResizeDir, ResizeRect, ResizeConstraints } from './components/dragResize';\n\n// ─── Color scheme — reactive read of the workspace's current data-color-scheme ───\nexport { useColorScheme } from './hooks/useColorScheme';\n\n","/**\n * @file WindowManager.tsx\n * @description Core component for react-dockable-desktop layout engine.\n * Renders the workspace desktop containing docked splits, tabbed panels, floated windows,\n * resize handles, context menus, and taskbar docks. Exposes lifecycle event listeners.\n */\n\nimport React, { useState, useRef, useEffect, 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 >&#8249;</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 >&#8250;</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 `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 /** The ID of the active/focused panel. */\n activePanelId: string | null;\n /** Current layout direction ('ltr' or 'rtl') */\n dir: 'ltr' | 'rtl';\n /** Convenient boolean flag indicating RTL direction */\n isRtl: boolean;\n /** 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, and panel metadata.\n * @returns JSON string suitable for storage and later restoration via {@link loadLayout}.\n * @example\n * ```ts\n * localStorage.setItem('layout', actions.saveLayout());\n * ```\n */\n saveLayout: () => string;\n /**\n * Restores a previously serialized workspace from a JSON string.\n * Replaces the entire current layout — all panels not in the snapshot are closed.\n * @param layoutJson - JSON string produced by {@link saveLayout}.\n * @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 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\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 */\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 return { gridRoot: parsed.gridRoot, floating, minimized: parsed.minimized, panels: parsed.panels };\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) {\n return {\n ...payload,\n activePanelId: Object.keys(payload.panels)[0] ?? null,\n };\n }\n } catch {\n // fall through to empty canvas\n }\n }\n return { gridRoot: EMPTY_LEAF, floating: [], minimized: [], panels: {}, activePanelId: null };\n}\n\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 cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: prev.minimized.filter(m => m.id !== id),\n panels: nextPanels\n };\n });\n 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 cleanRoot = removePanelFromTree(prev.gridRoot, id);\n return {\n ...prev,\n gridRoot: cleanRoot || { type: 'leaf', id: 'group-default', panels: [], activePanelId: null },\n floating: prev.floating.filter(w => w.id !== id),\n minimized: [...prev.minimized, { id, title: panel.title, component: panel.component }],\n panels: {\n ...prev.panels,\n [id]: {\n ...panel,\n state: 'minimized',\n previousState: panel.state,\n lastFloatingRect,\n lastLeafId\n }\n }\n };\n });\n 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 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 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 const firstActive = Object.keys(payload.panels)[0] || null;\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: firstActive\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 style={{ position: 'fixed', left: x, top: y, zIndex: 9501 }}\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 style={{ position: 'fixed', left: menuState.x, top: menuState.y, zIndex: 9500, ...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\n/** Configuration options applied when opening a Modal. */\nexport interface ModalOptions {\n /** Display title for the modal header. */\n title?: PanelTitle;\n /** Icon displayed in the modal title bar. */\n icon?: React.ReactNode;\n /** Size modifier affecting CSS max-width rules. */\n size?: 'small' | 'medium' | 'large' | 'fullscreen' | 'auto';\n /** If false, hides the modal backdrop exit click and header close button. */\n closable?: boolean;\n}\n\n/**\n * Represents a rendered instance of a panel or modal in the layout.\n */\nexport interface PanelInstance {\n /** Unique ID generated for this instance. */\n id: PanelInstanceId;\n /** React Component to mount inside the panel. */\n Component: ComponentType<any>;\n /** Property props passed to the Component. */\n props: Record<string, any>;\n /** The target rendering layout zone. */\n containerType: 'left-panel' | 'right-panel' | 'modal';\n /** Configuration metadata settings. */\n options: SidePanelOptions | ModalOptions;\n /** True if the form container has unsaved user edits. */\n dirty?: boolean;\n /** Custom warning options applied to the automatic unsaved changes modal. */\n dirtyOptions?: DirtyStateOptions;\n}\n\n/** Stores the active layout structures for floating overlays. */\nexport interface PanelState {\n /** The currently open left drawer panel instance, or null. */\n leftPanel: PanelInstance | null;\n /** The currently open right drawer panel instance, or null. */\n rightPanel: PanelInstance | null;\n /** Stack containing all active floating modal instances. */\n modals: PanelInstance[];\n}\n\n/** Exposes methods to trigger state actions on drawers and modals. */\nexport interface PanelActions {\n /** Mounts a panel in the left-side container drawer. */\n openLeftPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Mounts a panel in the right-side container drawer. */\n openRightPanel: <P extends object>(Component: ComponentType<P>, props: P, options?: SidePanelOptions) => Promise<PanelInstanceId | null>;\n /** Pushes a new modal component instance to the top of the stack. */\n openModal: <P extends object>(Component: ComponentType<P>, props: P, options?: ModalOptions) => PanelInstanceId;\n /** Closes an instance by ID. */\n close: (id: PanelInstanceId) => void;\n /** Closes all drawers and modals in a single action. */\n closeAll: () => void;\n /** Closes all open modals. */\n closeAllModals: () => void;\n /** Retrieves metadata for an active instance by ID. */\n getInstance: (id: PanelInstanceId) => PanelInstance | undefined;\n /** Updates the props, configuration options, or dirty flag of an active panel. */\n updateInstance: (id: PanelInstanceId, updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>) => void;\n /** Flags an instance as dirty (contains unsaved changes). */\n setDirty: (id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => void;\n /** Subscribes a custom close confirmation intercept handler. */\n registerCloseHandler: (id: PanelInstanceId, handler: () => Promise<boolean>) => void;\n /** Unsubscribes close confirmation handler. */\n unregisterCloseHandler: (id: PanelInstanceId) => void;\n}\n\nlet idCounter = 0;\nconst generateId = (): PanelInstanceId => `panel-${++idCounter}-${Date.now()}`;\n\nconst closeHandlers = new Map<PanelInstanceId, () => Promise<boolean>>();\n\nconst initialState: PanelState = {\n leftPanel: null,\n rightPanel: null,\n modals: [],\n};\n\nconst PanelStateContext = createContext<PanelState | null>(null);\nconst PanelActionsContext = createContext<PanelActions | null>(null);\n\n/**\n * PanelProvider component manages the state and action handlers\n * for drawers (left/right) and active stacked modal overlays.\n */\nexport const PanelProvider: React.FC<{ children: ReactNode }> = ({ children }) => {\n const [state, setState] = useState<PanelState>(initialState);\n\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const registerCloseHandler = useCallback((id: PanelInstanceId, handler: () => Promise<boolean>) => {\n closeHandlers.set(id, handler);\n }, []);\n\n const unregisterCloseHandler = useCallback((id: PanelInstanceId) => {\n closeHandlers.delete(id);\n }, []);\n\n const openLeftPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.leftPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'left-panel',\n options,\n };\n setState(s => ({ ...s, leftPanel: instance }));\n return id;\n },\n []\n );\n\n const openRightPanel = useCallback(\n async <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: SidePanelOptions = {}\n ): Promise<PanelInstanceId | null> => {\n const currentPanel = stateRef.current.rightPanel;\n if (currentPanel) {\n const handler = closeHandlers.get(currentPanel.id);\n if (handler) {\n const canClose = await handler();\n if (!canClose) return null;\n }\n }\n\n const id = generateId();\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'right-panel',\n options,\n };\n setState(s => ({ ...s, rightPanel: instance }));\n return id;\n },\n []\n );\n\n const openModal = useCallback(\n <P extends object>(\n Component: ComponentType<P>,\n props: P,\n options: ModalOptions = {}\n ): PanelInstanceId => {\n const id = generateId();\n const formTitle = (props as any).title;\n \n const modalOptions: ModalOptions = {\n ...options,\n title: options.title || formTitle || 'Confirmation',\n };\n\n const instance: PanelInstance = {\n id,\n Component: Component as ComponentType<any>,\n props: props as Record<string, any>,\n containerType: 'modal',\n options: modalOptions,\n };\n setState(s => ({ ...s, modals: [...s.modals, instance] }));\n return id;\n },\n []\n );\n\n const close = useCallback((id: PanelInstanceId) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? null : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? null : s.rightPanel,\n modals: s.modals.filter(m => m.id !== id),\n }));\n }, []);\n\n const closeAll = useCallback(() => {\n setState(initialState);\n }, []);\n\n const closeAllModals = useCallback(() => {\n setState(s => ({ ...s, modals: [] }));\n }, []);\n\n const getInstance = useCallback(\n (id: PanelInstanceId): PanelInstance | undefined => {\n if (state.leftPanel?.id === id) return state.leftPanel;\n if (state.rightPanel?.id === id) return state.rightPanel;\n return state.modals.find(m => m.id === id);\n },\n [state]\n );\n\n const updateInstance = useCallback(\n (\n id: PanelInstanceId,\n updates: Partial<Pick<PanelInstance, 'props' | 'options' | 'dirty' | 'dirtyOptions'>>\n ) => {\n setState(s => ({\n leftPanel: s.leftPanel?.id === id ? { ...s.leftPanel, ...updates } : s.leftPanel,\n rightPanel: s.rightPanel?.id === id ? { ...s.rightPanel, ...updates } : s.rightPanel,\n modals: s.modals.map(m => m.id === id ? { ...m, ...updates } : m),\n }));\n },\n []\n );\n\n const setDirty = useCallback((id: PanelInstanceId, dirty: boolean, options?: DirtyStateOptions) => {\n updateInstance(id, { dirty, dirtyOptions: options });\n }, [updateInstance]);\n\n const actions = useMemo<PanelActions>(\n () => ({\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n }),\n [\n openLeftPanel,\n openRightPanel,\n openModal,\n close,\n closeAll,\n closeAllModals,\n getInstance,\n updateInstance,\n setDirty,\n registerCloseHandler,\n unregisterCloseHandler,\n ]\n );\n\n return (\n <PanelStateContext.Provider value={state}>\n <PanelActionsContext.Provider value={actions}>\n {children}\n </PanelActionsContext.Provider>\n </PanelStateContext.Provider>\n );\n};\n\n/**\n * React hook to retrieve the active floating/drawer panels state.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelState = (): PanelState => {\n const ctx = useContext(PanelStateContext);\n if (!ctx) throw new Error('usePanelState must be used within PanelProvider');\n return ctx;\n};\n\n/**\n * React hook to retrieve actions enabling drawer toggles and modal push actions.\n * @throws Error if used outside of a {@link PanelProvider}.\n */\nexport const usePanelActions = (): PanelActions => {\n const ctx = useContext(PanelActionsContext);\n if (!ctx) throw new Error('usePanelActions must be used within PanelProvider');\n return ctx;\n};\n","import React, { useEffect, useRef } from 'react';\nimport { useFormContainer } from '../components/FormContainerContext';\nimport { useFormatMessage, usePredefinedMessages } from '../components/WindowManagerContext';\n\n/**\n * Props for the {@link ConfirmationForm} component.\n */\nexport interface ConfirmationFormProps {\n /** Optional custom title text or localizable descriptor for the dialog container. */\n title?: string | { id: string; defaultMessage?: string; values?: any };\n /** Main message text or localizable descriptor to display. */\n message: string | { id: string; defaultMessage?: string; values?: any };\n /** Optional auxiliary top alert notification text. */\n alert?: string;\n /** Type style classification for the alert notice banner. */\n alertType?: 'info' | 'warning' | 'success' | 'danger';\n /** If true, changes action button labels to 'Yes' and 'No' instead of 'OK' and 'Cancel'. */\n useYesNoTitles?: boolean;\n /** Callback fired when the user selects the confirm button. */\n onOK?: () => void;\n /** Callback fired when the user selects the cancel button. */\n onCancel?: () => void;\n}\n\n/**\n * ConfirmationForm component renders a standard dialog content layout,\n * allowing users to confirm actions or abort them. Exposes action callbacks.\n */\nexport const ConfirmationForm: React.FC<ConfirmationFormProps> = ({\n title,\n message,\n alert,\n alertType = 'info',\n useYesNoTitles = false,\n onOK,\n onCancel,\n}) => {\n const { requestClose, setIcon, setTitle } = useFormContainer();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const confirmButtonRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (title) {\n const resolvedTitle = typeof title === 'string' ? title : formatMessage(title);\n setTitle(resolvedTitle);\n }\n \n if (setIcon) {\n setIcon(<span>❓</span>);\n }\n }, [title, setTitle, setIcon, formatMessage]);\n\n useEffect(() => {\n confirmButtonRef.current?.focus({ 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 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 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 required, so supply `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';\nimport { useAnimationScrollGuard } from '../hooks/useAnimationScrollGuard';\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 // Matches the 0.18s scaleUp/fadeIn animation below — see useAnimationScrollGuard.\n useAnimationScrollGuard(180);\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 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 className={`rdd-modal-body ${modalBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\n/**\n * ModalStackRenderer component acts as the global container rendering\n * all active stacked modal windows in the workspace.\n */\nexport const ModalStackRenderer: React.FC = () => {\n const { modals } = usePanelState();\n\n if (modals.length === 0) return null;\n\n return (\n <>\n {modals.map((modal, index) => (\n <ModalRenderer\n key={modal.id}\n modal={modal}\n index={index}\n isTopmost={index === modals.length - 1}\n />\n ))}\n </>\n );\n};\n\nexport default ModalStackRenderer;\n","import { useEffect, useState } from 'react';\n\n/**\n * Snaps the document back to its scroll position for `durationMs` after mount.\n *\n * Some enter-animated overlays (side panels, modals) mount their content in the\n * same commit as the animation that slides/scales them into view, so a child that\n * autofocuses on mount (native `autofocus`, MUI's `autoFocus`, or the library's\n * own internal `.focus()` calls) is still a real, focusable, laid-out DOM node\n * while visually off-screen — triggering the browser's native focus-scroll-into-view,\n * which has no scrollable containing block to stop at and walks up to the document.\n * That's the page jump. This hook doesn't know or care what caused the scroll; it\n * just undoes any scroll that happens during the animation window.\n *\n * The baseline MUST be captured in a `useState` initializer, not inside this\n * hook's own `useEffect`: React always flushes every layout effect in the\n * subtree (e.g. MUI's `InputBase` autofocus, which fires from `useLayoutEffect`)\n * before any passive effect runs, tree-wide, regardless of nesting. Capturing in\n * a plain effect here would run after that autofocus-triggered scroll already\n * happened, recording the post-jump position as \"correct\" and never catching the\n * one jump that matters. A render-time initializer is the only capture point\n * guaranteed to precede every effect in the subtree.\n */\nexport function useAnimationScrollGuard(durationMs: number): void {\n const [{ x, y }] = useState(() => ({ x: window.scrollX, y: window.scrollY }));\n\n useEffect(() => {\n const handleScroll = () => window.scrollTo(x, y);\n window.addEventListener('scroll', handleScroll);\n\n const timeoutId = window.setTimeout(() => {\n window.removeEventListener('scroll', handleScroll);\n }, durationMs);\n\n return () => {\n window.clearTimeout(timeoutId);\n window.removeEventListener('scroll', handleScroll);\n };\n }, [durationMs, x, y]);\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, SidePanelOptions, PanelTitle } from './PanelProviderContext';\nimport type { DirtyStateOptions } from './dirtyOptions';\nimport { useFormatMessage, formatLabel, useStyleClasses, usePredefinedMessages, useWindowManagerState } from './WindowManagerContext';\nimport ConfirmationForm from '../forms/ConfirmationForm';\nimport { useAnimationScrollGuard } from '../hooks/useAnimationScrollGuard';\n\n/**\n * Props for the internal {@link SidePanelRendererItem} component.\n */\ninterface SidePanelRendererItemProps {\n /** The panel instance containing metadata, component type, and rendering state. */\n panel: PanelInstance;\n /** Floating anchor edge side for the drawer panel. */\n position: 'left' | 'right';\n /** Default width applied if no panel override configuration is provided. */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRendererItem component renders an individual left or right drawer panel instance\n * wrapped inside the FormContainerProvider context. Handles dirty state verification before close.\n */\nconst SidePanelRendererItem: React.FC<SidePanelRendererItemProps> = ({ panel, position, defaultWidth }) => {\n const { close, openModal, updateInstance, setDirty, registerCloseHandler, unregisterCloseHandler } = usePanelActions();\n const { modals } = usePanelState();\n const formatMessage = useFormatMessage();\n const predefinedMessages = usePredefinedMessages();\n const { dir } = useWindowManagerState();\n const { sidePanelClass, sidePanelBodyClass } = useStyleClasses();\n const closeHandlerRef = useRef<(() => boolean | Promise<boolean>) | null>(null);\n\n const { id, Component, props, options, dirty, dirtyOptions } = panel;\n const panelOptions = options as SidePanelOptions;\n const [icon, setIconState] = useState<React.ReactNode>(panelOptions.icon || null);\n\n const optionsRef = useRef(panelOptions);\n optionsRef.current = panelOptions;\n\n // Matches the 0.25s slideInLeft/slideInRight animation below — see useAnimationScrollGuard.\n useAnimationScrollGuard(250);\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 return (\n <div \n className={`rdd-side-panel rdd-side-panel-${position} rdd-side-panel-visible ${sidePanelClass ?? ''}`}\n style={{ width: widthStyle }}\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 className={`rdd-side-panel-body ${sidePanelBodyClass ?? ''}`}>\n <FormContainerProvider value={contract}>\n <Component {...props} panelId={id} />\n </FormContainerProvider>\n </div>\n </div>\n </div>\n );\n};\n\nexport interface SidePanelRendererProps {\n /**\n * Default panel width applied when openLeftPanel/openRightPanel do not specify one.\n * Accepts a number (treated as px) or any CSS width string (e.g. '40vw').\n * Falls back to 400px if omitted.\n */\n defaultWidth?: number | string;\n}\n\n/**\n * SidePanelRenderer component acts as the global container rendering both\n * left and right side drawers if they are currently active.\n */\nexport const SidePanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel, rightPanel } = usePanelState();\n return (\n <>\n {leftPanel && <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />}\n {rightPanel && <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />}\n </>\n );\n};\n\n/**\n * LeftPanelRenderer component renders ONLY the left side drawer if it is currently active.\n */\nexport const LeftPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { leftPanel } = usePanelState();\n if (!leftPanel) return null;\n return <SidePanelRendererItem key={leftPanel.id} panel={leftPanel} position=\"left\" defaultWidth={defaultWidth} />;\n};\n\n/**\n * RightPanelRenderer component renders ONLY the right side drawer if it is currently active.\n */\nexport const RightPanelRenderer: React.FC<SidePanelRendererProps> = ({ defaultWidth }) => {\n const { rightPanel } = usePanelState();\n if (!rightPanel) return null;\n return <SidePanelRendererItem key={rightPanel.id} panel={rightPanel} position=\"right\" defaultWidth={defaultWidth} />;\n};\n\nexport default SidePanelRenderer;\n","/**\n * @file Sidebar.tsx\n * @description Sidebar 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 icon: React.ReactNode;\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 */\n showCloseButton?: 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}\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 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 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 rootRef: React.RefObject<HTMLDivElement | null>;\n}\n\nfunction SidebarResizeHandle({\n position,\n currentWidth,\n minWidth,\n maxWidth,\n onWidthChange,\n rootRef,\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.\n if (rootRef.current) activeClasses.push({ el: rootRef.current, classes: ['rdd-sidebar-resizing'] });\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 });\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 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 // 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 // Ref to the root flex container — used by SidebarResizeHandle to toggle\n // the rdd-sidebar-resizing class that suppresses the CSS width transition during drag\n const rootRef = useRef<HTMLDivElement | null>(null);\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\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 }), [setActiveTabId]);\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 // transition is suppressed during drag via .rdd-sidebar-resizing on the root\n transition: '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 <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 {/* 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 rootRef={rootRef}\n />\n ) : null;\n\n return (\n <SidebarContext.Provider value={sidebarContextValue}>\n <div\n ref={rootRef}\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// 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 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 // Lock max-height for exit collapse animation\n useLayoutEffect(() => {\n if (divRef.current) {\n divRef.current.style.maxHeight = `${divRef.current.offsetHeight}px`;\n }\n }, []);\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 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\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\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): 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 insetTop: number;\n insetBottom: 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): void => {\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 next[anchor] = [...next[anchor], id];\n return 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 }), [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 >\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 style={{ position: 'fixed', top: dropdownPos.top, left: dropdownPos.left, width: dropdownPos.width, zIndex: 9502 }}\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. */\n defaultWidth: number;\n /** Initial height in pixels. */\n defaultHeight: number;\n children?: React.ReactNode;\n}\n\n/**\n * Declarative floating window anchored inside a `PanelOverlayRoot`.\n * Supports 8-direction resize, drag-to-free, and drag-to-dock at any corner.\n * Multiple windows docked to the same corner stack vertically with animated offsets.\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 */\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\nfunction FloatingWindowBody({ id, title, icon, defaultAnchor, defaultWidth, defaultHeight, 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 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\n const dragState = useRef<{ mouseX: number; mouseY: number; posX: number; posY: number; hasDragged: boolean } | null>(null);\n\n // Register in stack on mount; unregister on unmount (close).\n // Close resets to defaultAnchor on next open (fresh mount = fresh state).\n useLayoutEffect(() => {\n ctx?.dockWindow(id, defaultAnchor);\n return () => { ctx?.undockWindow(id); };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\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 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 rendered position before undocking so there's no visual jump\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 ctx?.undockWindow(id);\n setMode('free');\n setFreePos({ x: startX, y: startY });\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 document.body.classList.add('rdd-dragging-active');\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 const startRect = { x: startX, y: startY, w: sizeRef.current.w, h: sizeRef.current.h };\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 const { x: newX, y: newY, w: newW, h: newH } = computeResizedRect(dir, dx, dy, start, {\n minW: MIN_W, minH: MIN_H,\n maxW: cw - start.x, maxH: ch - start.y,\n minX: 0, minY: 0,\n });\n setSize({ w: newW, h: newH });\n if (modeRef.current === 'free') {\n setFreePos({ x: newX, y: newY });\n }\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 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) {\n const zone = ctx?.hoveredZone;\n if (zone) {\n ctx?.dockWindow(id, zone);\n setCurrentAnchor(zone);\n setMode('docked');\n setFreePos(null);\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) {\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 const stack = ctx.stacks[currentAnchor] ?? [];\n const idx = stack.indexOf(id);\n let stackOffset = 0;\n for (let i = 0; i < idx; i++) {\n stackOffset += (ctx.dockedSizes[stack[i]] ?? defaultHeight) + DOCK_GAP;\n }\n\n windowStyle = {\n width: size.w,\n height: size.h,\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: idx === -1 ? 0 : undefined,\n pointerEvents: idx === -1 ? 'none' : undefined,\n };\n\n windowStyle[currentAnchor.endsWith('-right') ? 'insetInlineEnd' : 'insetInlineStart'] = DOCK_INSET;\n\n if (currentAnchor.startsWith('top-')) {\n windowStyle.top = ctx.insetTop + stackOffset;\n } else {\n windowStyle.bottom = ctx.insetBottom + stackOffset;\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 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={`rdd-panel-float${isActive ? ' rdd-panel-float--active' : ''}`}\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 {mode === 'free' && <>\n <div className=\"rdd-resize-handle rdd-resize-n\" onPointerDown={handleResizePointerDown('n')} />\n <div className=\"rdd-resize-handle rdd-resize-ne\" onPointerDown={handleResizePointerDown('ne')} />\n <div className=\"rdd-resize-handle rdd-resize-nw\" onPointerDown={handleResizePointerDown('nw')} />\n </>}\n <div className=\"rdd-resize-handle rdd-resize-e\" onPointerDown={handleResizePointerDown('e')} />\n <div className=\"rdd-resize-handle rdd-resize-se\" onPointerDown={handleResizePointerDown('se')} />\n <div className=\"rdd-resize-handle rdd-resize-s\" onPointerDown={handleResizePointerDown('s')} />\n <div className=\"rdd-resize-handle rdd-resize-sw\" onPointerDown={handleResizePointerDown('sw')} />\n <div className=\"rdd-resize-handle rdd-resize-w\" onPointerDown={handleResizePointerDown('w')} />\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 *\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 */\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":["index_exports","__export","ConfirmationForm_default","ContextMenu","ContextMenuProvider","DefaultContextMenuAdapter","DockableDesktopProvider","FormContainerContext","FormContainerProvider","LeftPanelRenderer","ModalStackRenderer_default","PanelContributionProvider","PanelFloatingWindow","PanelOverlayRoot","PanelProvider","PanelRegistry","PanelRegistryClass","PanelToolbar","ToolbarItem","ToolbarSeparator","RightPanelRenderer","SidePanelRenderer_default","Sidebar","ToastContainer","Toolbar","ToolbarButton","ToolbarCenter","ToolbarProvider","ToolbarSearchInput","ToolbarSpacer","ToolbarToggle","WindowManager_default","WindowManagerProvider","WorkspaceClient","computeResizedRect","defaultPredefinedMessages","formatLabel","isSerializable","sidebarSectionToTab","startPointerDrag","toast","useActivePanelContribution","useColorScheme","useFormContainer","useFormatMessage","useMergedSidebarTabs","useMergedToolbarItems","usePanelActions","usePanelContext","usePanelContextMenu","usePanelContribution","usePanelFloatingWindow","usePanelFloatingWindowManager","usePanelId","usePanelSize","usePanelState","usePredefinedMessages","useRegistry","useShowContextMenu","useSidebar","useSidebarTab","useStyleClasses","useToolbar","useWindowManagerActions","useWindowManagerState","__toCommonJS","import_react","import_react_dom","import_react","import_react","defaultContract","FormContainerContext","FormContainerProvider","useFormContainer","usePanelSize","onResize","getDimensions","onStoreChange","PanelRegistryClass","id","Component","defaultOptions","PanelRegistry","defaultPredefinedMessages","import_react","isSerializable","value","type","proto","import_jsx_runtime","WindowStateContext","WindowActionsContext","WindowI18nContext","WindowStoreSyncContext","WindowPredefinedMessagesContext","defaultPredefinedMessages","StyleClassContext","useStyleClasses","RegistryContext","PanelRegistry","useRegistry","PanelEventBus","event","callback","cb","data","EMPTY_LEAF","parseLayoutPayload","parsed","floating","fw","anchor","_sr","_sb","rest","parseInitialState","json","payload","WindowManagerProvider","children","client","formatMessage","predefinedMessages","dirProp","modalClass","modalBodyClass","sidePanelClass","sidePanelBodyClass","windowClass","windowBodyClass","zIndexBaseProp","registry","effectiveFormatMessage","effectivePredefinedMessages","effectiveDir","effectiveZIndexBase","state","setState","stateRef","stateSubscribersRef","getSnapshot","subscribeToState","closeGuardsRef","stateProvidersRef","mergedMessages","eventBusRef","maxZRef","subscribe","publish","getCascadedPosition","fav","currentFloating","x","y","width","height","isOverlapping","pos","w","wx","wy","attempts","viewW","viewH","focusPanel","id","prev","panel","win","alreadyTop","selectActiveInTree","node","removePanelFromTree","idx","panels","p","activePanelId","updatedLeaf","c","sizes","sum","a","b","s","addPanelToLeaf","leafId","panelId","findFirstLeafId","child","openPanel","component","options","resolvedId","match","isNew","isRedirect","shouldFocus","serializable","isSerializable","exists","entry","title","target","favPos","nextMinimized","m","cascaded","firstLeaf","newPanelInfo","nextPanels","closePanel","cleanRoot","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","dockPanel","nextFloating","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","info","dynamicValue","hasDynamicValue","effectiveProps","effectiveSerializable","gridRoot","minimized","loadLayout","layoutJson","firstActive","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","snap","useWindowManagerActions","ctx","useWindowManagerActionsInternal","useFormatMessage","formatLabel","label","formatter","usePanelContext","usePredefinedMessages","usePanelId","useFormContainer","usePanelContextMenu","items","itemsRef","import_react","import_react_dom","import_jsx_runtime","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","React","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","import_react","import_jsx_runtime","idCounter","generateId","closeHandlers","initialState","PanelStateContext","PanelActionsContext","PanelProvider","children","state","setState","stateRef","registerCloseHandler","id","handler","unregisterCloseHandler","openLeftPanel","Component","props","options","currentPanel","instance","s","openRightPanel","openModal","formTitle","modalOptions","close","m","closeAll","closeAllModals","getInstance","updateInstance","updates","setDirty","dirty","actions","usePanelState","ctx","usePanelActions","import_react","import_jsx_runtime","ConfirmationForm","title","message","alert","alertType","useYesNoTitles","onOK","onCancel","requestClose","setIcon","setTitle","useFormContainer","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","confirmButtonRef","resolvedTitle","resolvedMessage","cancelLabel","confirmLabel","handleSubmit","e","handleCancel","ConfirmationForm_default","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","import_react","useColorScheme","scheme","setScheme","updateScheme","observer","import_jsx_runtime","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","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","updateTabScroll","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","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","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","import_react","import_react","import_jsx_runtime","ToolbarContext","ToolbarProvider","children","radioGroups","setRadioGroups","modifiers","setModifiers","value","group","id","prev","active","useToolbar","ctx","import_react","import_jsx_runtime","createPanelContributionStore","contributions","listeners","notify","l","panelId","contribution","listener","PanelContributionContext","PanelContributionProvider","children","store","usePanelContribution","usePanelId","cleanupRef","useActivePanelContribution","activePanelId","useWindowManagerState","s","subscribe","onChange","getSnapshot","sidebarSectionToTab","section","fallbackIcon","useMergedToolbarItems","staticItems","active","useMergedSidebarTabs","staticTabs","import_jsx_runtime","DockableDesktopProvider","contextMenuAdapter","DefaultContextMenuAdapter","props","existingCtxMenu","ContextMenuContext","inner","ToolbarProvider","WindowManagerProvider","PanelContributionProvider","PanelProvider","ContextMenuProvider","import_react","import_react","useAnimationScrollGuard","durationMs","x","y","handleScroll","timeoutId","import_jsx_runtime","ModalRenderer","modal","index","isTopmost","close","openModal","updateInstance","setDirty","usePanelActions","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","modalClass","modalBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","modalOptions","icon","setIconState","optionsRef","useAnimationScrollGuard","baseTitle","formatLabel","handleClose","ConfirmationForm_default","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","sizeClass","showCloseButton","handleKeyDown","e","modalZIndex","FormContainerProvider","ModalStackRenderer","modals","usePanelState","ModalStackRenderer_default","import_react","import_jsx_runtime","SidePanelRendererItem","panel","position","defaultWidth","close","openModal","updateInstance","setDirty","registerCloseHandler","unregisterCloseHandler","usePanelActions","modals","usePanelState","formatMessage","useFormatMessage","predefinedMessages","usePredefinedMessages","dir","useWindowManagerState","sidePanelClass","sidePanelBodyClass","useStyleClasses","closeHandlerRef","id","Component","props","options","dirty","dirtyOptions","panelOptions","icon","setIconState","optionsRef","useAnimationScrollGuard","baseTitle","formatLabel","handleClose","ConfirmationForm_default","canClose","handleSetDirty","handleSetTitle","title","handleSetIcon","newIcon","handleOnCloseRequested","handler","contract","displayTitle","handleKeyDown","e","width","widthStyle","FormContainerProvider","SidePanelRenderer","leftPanel","rightPanel","LeftPanelRenderer","RightPanelRenderer","SidePanelRenderer_default","import_react","import_jsx_runtime","isRailTab","entry","isRailCustom","toRailArray","value","SidebarContext","SidebarTabContext","SidebarTabProvider","tabId","onClose","onOpen","setActiveTabId","children","otherId","renderRailEntry","index","activeTabId","onTabClick","React","isActive","SidebarTabStrip","tabs","headerEntries","footerEntries","isVisible","position","i","tab","SidebarResizeHandle","currentWidth","minWidth","maxWidth","onWidthChange","rootRef","e","el","activeClasses","startPointerDrag","dx","_dy","startWidth","newW","Sidebar","headerAction","footerAction","defaultWidth","controlledActiveTabId","onActiveTabChange","visible","onVisibilityChange","stripVisible","onStripVisibilityChange","showCloseButton","ref","isControlled","width","setWidthState","setWidth","px","internalActiveTabId","setInternalActiveTabId","normalizedHeaderEntries","normalizedFooterEntries","headerTabs","footerTabs","allTabs","mountedTabIds","setMountedTabIds","effectiveMountedTabIds","result","activeTabIdRef","widthRef","id","prev","next","changed","t","handleTabClick","handleClose","sidebarContextValue","isSidebarVisible","isStripVisible","isDrawerOpen","drawer","isCurrent","resizeHandle","useSidebar","ctx","useSidebarTab","import_react","import_react_dom","import_jsx_runtime","flyoutPosition","rect","position","isRtl","gap","ToolbarGroupButton","item","toolbar","isOpen","setIsOpen","btnRect","setBtnRect","btnRef","flyoutRef","isControlled","activeId","activeSubItem","e","isActive","displayIcon","displayLabel","handleClick","prev","el","r","PAD","onMouseDown","target","onKey","entry","i","isSubActive","renderItem","index","controlled","Toolbar","items","visible","onVisibilityChange","className","style","ref","useToolbar","isVertical","collapseStyle","import_react","import_react_dom","import_jsx_runtime","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","timerRef","remainRef","startRef","paused","setPaused","startEntry","entryClass","setEntryClass","raf","scheduleDismiss","ms","el","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","import_react","import_react_dom","import_jsx_runtime","ANCHORS","PanelToolbarContext","PanelManagerContext","PanelOverlayContext","DROP_ZONE_SIZE","getHoveredZone","container","clientX","clientY","rect","x","y","PanelOverlayRoot","children","className","style","toolbarSizes","setToolbarSizes","zOrders","setZOrders","stacks","setStacks","dockedSizes","setDockedSizes","draggingId","setDraggingId","hoveredZone","setHoveredZone","topId","setTopId","managedWindows","setManagedWindows","zCounterRef","containerRef","registerToolbar","pos","size","prev","next","focusWindow","id","z","dockWindow","anchor","undockWindow","reportDockedSize","openManaged","config","closeManaged","closeAllManaged","managedWindowIds","toolbarCtxValue","managerCtxValue","coreCtxValue","DropZoneOverlay","cfg","PanelFloatingWindow","zone","PanelToolbar","position","variant","buttonVariant","buttonSize","ctx","ref","cleanupRef","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","group","items","React","item","props","FloatingWindowBody","MIN_W","MIN_H","DOCK_INSET","DOCK_GAP","defaultAnchor","defaultWidth","defaultHeight","onClose","isRtl","WindowStateContext","mode","setMode","currentAnchor","setCurrentAnchor","freePos","setFreePos","setSize","windowRef","modeRef","freePosRef","sizeRef","dragState","zOrder","isActive","getContainerBounds","handleWindowPointerDown","handleHeaderPointerDown","startX","startY","elRect","cRect","handleResizePointerDown","dir","er","cr","startRect","startPointerDrag","dx","dy","start","cw","ch","newX","newY","newW","newH","computeResizedRect","handleWindowPointerMove","ds","rawZone","flipZoneHorizontal","handleWindowPointerUp","handleWindowPointerCancel","windowStyle","stack","idx","stackOffset","i","usePanelFloatingWindow","isOpen","setIsOpen","open","close","EMPTY_IDS","usePanelFloatingWindowManager","ids"]}