{"version":3,"file":"resizable-aOVGO_Os.cjs","names":[],"sources":["../components/resizable/composables/useResizablePanelState.ts","../components/resizable/composables/useResizablePanelControls.ts","../components/resizable/composables/computeLayout.ts","../components/resizable/composables/useResizableStorage.ts","../components/resizable/composables/useResizableGroup.ts","../components/resizable/composables/useResizableDrag.ts","../components/resizable/composables/useResizableAnnouncements.ts","../components/resizable/composables/useResizableOffset.ts","../components/resizable/resizable.vue"],"sourcesContent":["/**\n * Panel State Model\n *\n * Pure functions for panel state creation, constraint calculation, and validation.\n * Single source of truth for all constraint-related logic.\n *\n * Constraint math has been extracted to constraintResolver.ts.\n */\n\nimport { DEFAULT_PANEL_SIZE } from '../resizable_constants';\nimport type { ResizablePanelConfig, ResizablePanelState } from '../resizable_constants';\nimport { parseSizeToPixels } from '../resizable_utils';\nimport { clampToTier } from './constraintResolver';\n\nimport { calculateConstraintHierarchy } from './constraintResolver';\n\n// Re-export constraint types and functions from constraintResolver\nexport type { ConstraintHierarchy } from './constraintResolver';\nexport { calculateConstraintHierarchy } from './constraintResolver';\n\n/**\n * Apply constraints to a pixel size for a panel.\n *\n * Updates panel's constraint pixel values and returns the constrained size.\n *\n * @param panel - Panel state to update constraints on\n * @param pixelSize - Desired pixel size before constraints\n * @param containerSize - Current container size in pixels\n * @param constraintType - Which constraints to apply: 'user' (default) or 'system'\n * @returns Constrained pixel size respecting bounds\n */\nexport function applyPanelPixelConstraints(\n  panel: ResizablePanelState,\n  pixelSize: number,\n  containerSize: number,\n  constraintType: 'user' | 'system' = 'user'\n): number {\n  const constraints = calculateConstraintHierarchy(panel, containerSize);\n\n  panel.userMinSizePixels = constraints.userMinSizePixels;\n  panel.userMaxSizePixels = constraints.userMaxSizePixels;\n  panel.systemMinSizePixels = constraints.systemMinSizePixels;\n  panel.systemMaxSizePixels = constraints.systemMaxSizePixels;\n  panel.collapseSizePixels = constraints.collapseSizePixels;\n\n  return clampToTier(pixelSize, constraints, constraintType);\n}\n\n// ============================================================================\n// PANEL STATE CREATION\n// ============================================================================\n\nfunction applyConstraintsToSize(pixelSize: number, minSizePixels?: number, maxSizePixels?: number): number {\n  let constrained = pixelSize;\n  if (minSizePixels !== undefined) {\n    constrained = Math.max(constrained, minSizePixels);\n  }\n  if (maxSizePixels !== undefined) {\n    constrained = Math.min(constrained, maxSizePixels);\n  }\n  return constrained;\n}\n\nfunction derivePanelBehavioralState(\n  panelConfig: ResizablePanelConfig,\n  existingPanel?: ResizablePanelState\n): { collapsed: boolean; manualTargetSize: number | undefined } {\n  return {\n    collapsed: existingPanel?.collapsed ?? Boolean(panelConfig.collapsed),\n    manualTargetSize: existingPanel?.manualTargetSize,\n  };\n}\n\n/**\n * Create initial panel state from configuration.\n */\nexport function createPanelState(\n  panelConfig: ResizablePanelConfig,\n  containerSize: number,\n  existingPanel?: ResizablePanelState\n): ResizablePanelState {\n  const constraints = calculateConstraintHierarchy(panelConfig, containerSize);\n\n  const rawPixelSize = parseSizeToPixels(panelConfig.initialSize ?? DEFAULT_PANEL_SIZE, containerSize);\n  const pixelSize = applyConstraintsToSize(rawPixelSize, constraints.userMinSizePixels, constraints.userMaxSizePixels);\n\n  const behavioralState = derivePanelBehavioralState(panelConfig, existingPanel);\n  const autoCollapsed = existingPanel?.autoCollapsed;\n\n  return {\n    ...panelConfig,\n    pixelSize,\n    ...behavioralState,\n    userMinSizePixels: constraints.userMinSizePixels,\n    userMaxSizePixels: constraints.userMaxSizePixels,\n    systemMinSizePixels: constraints.systemMinSizePixels,\n    systemMaxSizePixels: constraints.systemMaxSizePixels,\n    collapseSizePixels: constraints.collapseSizePixels,\n    autoCollapsed,\n  };\n}\n\n/**\n * Create panel states for all panels in a configuration array.\n */\nexport function createBasicPanelStates(\n  allPanels: ResizablePanelConfig[],\n  containerSize: number,\n  existingPanels?: ResizablePanelState[]\n): ResizablePanelState[] {\n  return allPanels.map(panelConfig => {\n    const existingPanel = existingPanels?.find(p => p.id === panelConfig.id);\n    return createPanelState(panelConfig, containerSize, existingPanel);\n  });\n}\n\n// ============================================================================\n// PANEL STATE VALIDATION\n// ============================================================================\n\n/**\n * Check if a panel pair should be skipped during constraint processing.\n */\nexport function shouldSkipPanelPair(beforePanel: ResizablePanelState, afterPanel: ResizablePanelState): boolean {\n  return (\n    beforePanel.resizable === false ||\n    !!beforePanel.collapsed ||\n    afterPanel.resizable === false ||\n    !!afterPanel.collapsed\n  );\n}\n\n/**\n * Check if a panel pair can be reset to initial sizes.\n */\nexport function canResetPanelPair(beforePanel: ResizablePanelState, afterPanel: ResizablePanelState): boolean {\n  return (\n    beforePanel.resizable !== false && !beforePanel.collapsed && afterPanel.resizable !== false && !afterPanel.collapsed\n  );\n}\n","/**\n * Panel Controls Controller\n *\n * Operations for manipulating panel state: resize, collapse, reset.\n * Receives resizeHandler from Integration layer (single instance pattern).\n */\n\nimport type { Ref } from 'vue';\nimport { DEFAULT_PANEL_SIZE } from '../resizable_constants';\nimport type {\n  ResizablePanelState,\n  ResizableSizeValue,\n  CollapseRule,\n} from '../resizable_constants';\nimport { parseSizeToPixels } from '../resizable_utils';\nimport { applyPanelPixelConstraints, canResetPanelPair } from './useResizablePanelState';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\n/**\n * State snapshot captured before a panel is collapsed.\n */\nexport interface PreCollapseState {\n  sizes: Map<string, number>;\n  manualTargets: Map<string, number | undefined>;\n  containerSize: number;\n}\n\nexport type CollapseRequestSource =\n  | 'user'\n  | 'system'\n  | 'prop'\n  | 'storage';\n\nexport interface CollapseRequest {\n  panelId: string;\n  action: 'collapse' | 'expand';\n  source: CollapseRequestSource;\n}\n\nexport interface CollapseRequestResult {\n  success: boolean;\n  reason?: string;\n  panelId: string;\n  newState: 'collapsed' | 'expanded' | 'unchanged';\n}\n\nexport interface CollapseOptions {\n  isAutoCollapse?: boolean;\n}\n\nexport interface ResizablePanelControlsOptions {\n  panels: Ref<ResizablePanelState[]>;\n  containerSize: Ref<number>;\n  containerRef: Ref<HTMLElement | null>;\n  onPanelResize: (panelId: string, pixelSize: number) => void;\n  onPanelCollapse: (panelId: string, collapsed: boolean) => void;\n  updateSavedPanel: (panelId: string, updates: Partial<import('./useResizableStorage').SavedPanelData>) => void;\n}\n\n// ============================================================================\n// MAIN COMPOSABLE\n// ============================================================================\n\nexport function useResizablePanelControls(options: ResizablePanelControlsOptions) {\n  const {\n    panels,\n    containerSize,\n    containerRef,\n    onPanelResize,\n    onPanelCollapse,\n    updateSavedPanel,\n  } = options;\n\n  const preCollapseStates = new Map<string, PreCollapseState>();\n\n  // ---- Size Conversion ----\n\n  function convertToPixelSize(initialSize: ResizableSizeValue): number {\n    return parseSizeToPixels(initialSize, containerSize.value);\n  }\n\n  // ============================================================================\n  // CENTRALIZED COLLAPSE LOGIC\n  // ============================================================================\n\n  function processCollapseRequest(request: CollapseRequest): CollapseRequestResult {\n    const { panelId, action, source } = request;\n    const panel = panels.value.find(p => p.id === panelId);\n    const isCollapse = action === 'collapse';\n\n    const validationResult = validateCollapseRequest(panelId, panel, isCollapse);\n    if (validationResult) return validationResult;\n\n    if (isCollapse) {\n      executeCollapse(panel!, source);\n    } else {\n      executeExpand(panel!);\n    }\n\n    onPanelCollapse(panelId, isCollapse);\n    if (containerRef.value) {\n      containerRef.value.dispatchEvent(new CustomEvent('panels-updated'));\n    }\n\n    const newState = isCollapse ? 'collapsed' : 'expanded';\n\n    return { success: true, panelId, newState };\n  }\n\n  function validateCollapseRequest(\n    panelId: string,\n    panel: ResizablePanelState | undefined,\n    isCollapse: boolean\n  ): CollapseRequestResult | undefined {\n    if (!panel) {\n      return { success: false, reason: 'Panel not found', panelId, newState: 'unchanged' };\n    }\n\n    const currentlyCollapsed = panel.collapsed;\n    if (isCollapse && currentlyCollapsed) {\n      return { success: true, reason: 'Already collapsed', panelId, newState: 'unchanged' };\n    }\n    if (!isCollapse && !currentlyCollapsed) {\n      return { success: true, reason: 'Already expanded', panelId, newState: 'unchanged' };\n    }\n    if (isCollapse && !panel.collapsible) {\n      return { success: false, reason: 'Panel is not collapsible', panelId, newState: 'unchanged' };\n    }\n\n    return undefined;\n  }\n\n  function executeCollapse(panel: ResizablePanelState, source: CollapseRequestSource): void {\n    const state: PreCollapseState = {\n      sizes: new Map(),\n      manualTargets: new Map(),\n      containerSize: containerSize.value,\n    };\n    panels.value.forEach(p => {\n      state.sizes.set(p.id, p.pixelSize);\n      state.manualTargets.set(p.id, p.manualTargetSize);\n    });\n    preCollapseStates.set(panel.id, state);\n\n    updateSavedPanel(panel.id, { collapsed: true, autoCollapsed: source === 'system' });\n\n    // Clear manual ratios so remaining panels fill the freed space\n    panels.value.forEach(p => {\n      if (p.id !== panel.id && !p.collapsed) {\n        updateSavedPanel(p.id, { manualTargetRatio: undefined });\n      }\n    });\n  }\n\n  function executeExpand(panel: ResizablePanelState): void {\n    const wasAutoCollapsed = panel.autoCollapsed ?? false;\n\n    const preCollapse = preCollapseStates.get(panel.id);\n\n    if (preCollapse) {\n      const viewportChangeRatio = Math.abs(containerSize.value - preCollapse.containerSize)\n        / preCollapse.containerSize;\n      const viewportChanged = viewportChangeRatio > 0.1;\n      const shouldRestoreSizes = !viewportChanged || !wasAutoCollapsed;\n\n      if (shouldRestoreSizes) {\n        const savedPanelSize = preCollapse.sizes.get(panel.id);\n        if (savedPanelSize !== undefined) {\n          updateSavedPanel(panel.id, { pixelSize: savedPanelSize, collapsed: false, autoCollapsed: undefined });\n        } else {\n          updateSavedPanel(panel.id, { collapsed: false, autoCollapsed: undefined });\n        }\n\n        panels.value.forEach(p => {\n          if (p.id === panel.id) return;\n          const savedSize = preCollapse.sizes.get(p.id);\n          const hadManualTargetBefore = preCollapse.manualTargets.get(p.id) !== undefined;\n          const hasManualTargetNow = p.manualTargetSize !== undefined;\n\n          if (!hadManualTargetBefore && !hasManualTargetNow && savedSize !== undefined) {\n            updateSavedPanel(p.id, { pixelSize: savedSize });\n          }\n        });\n      } else {\n        updateSavedPanel(panel.id, { collapsed: false, autoCollapsed: undefined });\n      }\n\n      preCollapseStates.delete(panel.id);\n    } else {\n      const initialSize = parseSizeToPixels(panel.initialSize ?? DEFAULT_PANEL_SIZE, containerSize.value);\n      const constrainedSize = applyPanelPixelConstraints(panel, initialSize, containerSize.value, 'system');\n      updateSavedPanel(panel.id, { pixelSize: constrainedSize, collapsed: false, autoCollapsed: undefined });\n    }\n  }\n\n  // ---- Panel Operations ----\n\n  function commitPanelSize(panelId: string, pixels: number): void {\n    const rounded = Math.round(pixels);\n    const cSize = containerSize.value;\n    const ratio = cSize > 0 ? rounded / cSize : undefined;\n    updateSavedPanel(panelId, { pixelSize: rounded, manualTargetRatio: ratio });\n  }\n\n  function resizePanel(panelId: string, newPixelSize: number) {\n    const panel = panels.value.find(p => p.id === panelId);\n    if (!panel || panel.collapsed) return;\n\n    const constrainedSize = applyPanelPixelConstraints(panel, newPixelSize, containerSize.value);\n    commitPanelSize(panelId, constrainedSize);\n\n    onPanelResize(panelId, constrainedSize);\n  }\n\n  /**\n   */\n  function collapsePanel(panelId: string, collapsed: boolean, options?: CollapseOptions) {\n    const source: CollapseRequestSource = options?.isAutoCollapse ? 'system' : 'prop';\n\n    processCollapseRequest({\n      panelId,\n      action: collapsed ? 'collapse' : 'expand',\n      source,\n    });\n  }\n\n  // ---- Panel Reset Operations ----\n\n  function resetAdjacentPanels(beforePanel: ResizablePanelState, afterPanel: ResizablePanelState) {\n    const combinedSpace = beforePanel.pixelSize + afterPanel.pixelSize;\n    const beforeInitial = convertToPixelSize(beforePanel.initialSize || DEFAULT_PANEL_SIZE);\n    const afterInitial = convertToPixelSize(afterPanel.initialSize || DEFAULT_PANEL_SIZE);\n    const totalInitial = beforeInitial + afterInitial;\n\n    const beforeSize = totalInitial > 0\n      ? Math.round(combinedSpace * (beforeInitial / totalInitial))\n      : Math.round(combinedSpace / 2);\n    const afterSize = combinedSpace - beforeSize;\n\n    updateSavedPanel(beforePanel.id, {\n      pixelSize: beforeSize, manualTargetRatio: undefined,\n    });\n    updateSavedPanel(afterPanel.id, {\n      pixelSize: afterSize, manualTargetRatio: undefined,\n    });\n\n    onPanelResize(beforePanel.id, beforeSize);\n    onPanelResize(afterPanel.id, afterSize);\n  }\n\n  function resetAllPanelPairs() {\n    for (let i = 0; i < panels.value.length - 1; i++) {\n      const currentPanel = panels.value[i];\n      const nextPanel = panels.value[i + 1];\n\n      if (canResetPanelPair(currentPanel, nextPanel)) {\n        resetAdjacentPanels(currentPanel, nextPanel);\n      }\n    }\n  }\n\n  function resetSpecificPanelPair(beforePanelId?: string, afterPanelId?: string) {\n    const beforePanel = beforePanelId ? panels.value.find(p => p.id === beforePanelId) : undefined;\n    const afterPanel = afterPanelId ? panels.value.find(p => p.id === afterPanelId) : undefined;\n\n    if (beforePanel && afterPanel && canResetPanelPair(beforePanel, afterPanel)) {\n      resetAdjacentPanels(beforePanel, afterPanel);\n    }\n  }\n\n  function resetSinglePanel(panelId?: string) {\n    if (!panelId) return;\n    const panel = panels.value.find(p => p.id === panelId);\n    if (!panel || panel.collapsed || panel.resizable === false) return;\n\n    const initialSize = convertToPixelSize(panel.initialSize || DEFAULT_PANEL_SIZE);\n    const delta = initialSize - panel.pixelSize;\n\n    const panelIndex = panels.value.indexOf(panel);\n    const adjacentPanel = panels.value.find((p, i) =>\n      i !== panelIndex && !p.collapsed && p.resizable !== false\n    );\n\n    if (!adjacentPanel) return;\n\n    const newAdjacentSize = adjacentPanel.pixelSize - delta;\n\n    updateSavedPanel(panel.id, {\n      pixelSize: initialSize, manualTargetRatio: undefined,\n    });\n    updateSavedPanel(adjacentPanel.id, { pixelSize: newAdjacentSize });\n\n    onPanelResize(panel.id, initialSize);\n    onPanelResize(adjacentPanel.id, newAdjacentSize);\n  }\n\n  function resetPanels(\n    beforePanelId?: string,\n    afterPanelId?: string,\n    behavior: 'both' | 'before' | 'after' | 'all' = 'all'\n  ) {\n    try {\n      if (behavior === 'all') {\n        resetAllPanelPairs();\n      } else if (behavior === 'before') {\n        resetSinglePanel(beforePanelId);\n      } else if (behavior === 'after') {\n        resetSinglePanel(afterPanelId);\n      } else {\n        resetSpecificPanelPair(beforePanelId, afterPanelId);\n      }\n    } catch (error) {\n      console.error('[resizable] Error in resetPanels:', error);\n    }\n  }\n\n  // ---- Auto-Collapse/Expand ----\n\n  function checkAutoCollapse(): string[] {\n    const collapsedPanels: string[] = [];\n    const currentContainerSize = containerSize.value;\n\n    for (const panel of panels.value) {\n      if (panel.collapsed || !panel.collapsible || !panel.collapseSizePixels) {\n        continue;\n      }\n\n      if (currentContainerSize < panel.collapseSizePixels) {\n        const result = processCollapseRequest({\n          panelId: panel.id,\n          action: 'collapse',\n          source: 'system',\n        });\n\n        if (result.newState === 'collapsed') {\n          collapsedPanels.push(panel.id);\n        }\n      }\n    }\n\n    return collapsedPanels;\n  }\n\n  function checkAutoExpand(): string[] {\n    const expandedPanels: string[] = [];\n    const currentContainerSize = containerSize.value;\n\n    for (const panel of panels.value) {\n      if (!panel.collapsed || !panel.autoCollapsed || !panel.collapseSizePixels) {\n        continue;\n      }\n\n      if (currentContainerSize >= panel.collapseSizePixels) {\n        const result = processCollapseRequest({\n          panelId: panel.id,\n          action: 'expand',\n          source: 'system',\n        });\n\n        if (result.newState === 'expanded') {\n          expandedPanels.push(panel.id);\n        }\n      }\n    }\n\n    return expandedPanels;\n  }\n\n  function processAutoCollapseExpand(): { collapsed: string[]; expanded: string[] } {\n    const expanded = checkAutoExpand();\n    const collapsed = checkAutoCollapse();\n\n    return { collapsed, expanded };\n  }\n\n  return {\n    commitPanelSize,\n    resizePanel,\n    collapsePanel,\n    resetPanels,\n    processCollapseRequest,\n    checkAutoCollapse,\n    checkAutoExpand,\n    processAutoCollapseExpand,\n  };\n}\n\n// ============================================================================\n// COLLAPSE RULE UTILITIES\n// ============================================================================\n\n/**\n * Sorts collapse rules by priority (lower numbers collapse first).\n * Creates a new sorted array - does not mutate the original.\n * Maintains stable sort for rules with equal priority.\n */\nexport function sortCollapseRules(rules: CollapseRule[]): CollapseRule[] {\n  if (!rules || rules.length === 0) {\n    return [];\n  }\n\n  const indexed = rules.map((rule, index) => ({ rule, index }));\n\n  indexed.sort((a, b) => {\n    const priorityDiff = a.rule.priority - b.rule.priority;\n    if (priorityDiff !== 0) {\n      return priorityDiff;\n    }\n    return a.index - b.index;\n  });\n\n  return indexed.map(item => item.rule);\n}\n\n// ============================================================================\n// AUTO-COLLAPSE UTILITIES\n// ============================================================================\n\nfunction getCollapseThreshold(\n  panel: ResizablePanelState,\n  rule: CollapseRule,\n  containerSize: number\n): number | undefined {\n  if (rule.minSizeBeforeCollapse !== undefined) {\n    return parseSizeToPixels(rule.minSizeBeforeCollapse, containerSize);\n  }\n  return panel.userMinSizePixels;\n}\n\nfunction shouldPanelCollapse(\n  panels: ResizablePanelState[],\n  rule: CollapseRule,\n  containerSize: number\n): string | undefined {\n  const panel = panels.find(p => p.id === rule.panelId);\n\n  if (!panel || panel.collapsed) {\n    return undefined;\n  }\n\n  const threshold = getCollapseThreshold(panel, rule, containerSize);\n\n  if (threshold === undefined) {\n    return undefined;\n  }\n\n  return panel.pixelSize <= threshold ? panel.id : undefined;\n}\n\n/**\n * Checks which panels should auto-collapse based on their current size and collapse rules.\n * Returns panel IDs in priority order (lowest priority first = first to collapse).\n */\nexport function checkAutoCollapseRules(\n  panels: ResizablePanelState[],\n  collapseRules: CollapseRule[],\n  containerSize: number\n): string[] {\n  if (!panels || panels.length === 0 || !collapseRules || collapseRules.length === 0) {\n    return [];\n  }\n\n  const sortedRules = sortCollapseRules(collapseRules);\n\n  return sortedRules\n    .map(rule => shouldPanelCollapse(panels, rule, containerSize))\n    .filter((id): id is string => id !== undefined);\n}\n","/**\n * computeLayout — Pure Layout Engine\n *\n * Takes panel configs + container size and returns positions for every panel\n * and handle. Constraints are applied WITHIN the computation, not after.\n *\n * This is a pure function: no DOM access, no Vue reactivity, no localStorage,\n * no side effects. It takes data in and returns data out.\n *\n * Key design: proportional scaling\n * - Panels with manualTargetRatio scale to their stored ratio each render\n * - Panels without a ratio distribute remaining space proportionally\n * - Fixed panels (resizable: false) keep their exact pixel size\n * - Min/max constraints clamp results; overflow is redistributed in the same pass\n *\n * @see constraintResolver.ts\n */\n\nimport { DEFAULT_PANEL_SIZE, buildHandleId } from '../resizable_constants';\nimport type { ResizablePanelConfig } from '../resizable_constants';\nimport { parseSizeToPixels } from '../resizable_utils';\nimport { calculateConstraintHierarchy, clampToTier, type ConstraintHierarchy } from './constraintResolver';\n\n// ============================================================================\n// SAVED STATE TYPE (inlined from useResizableStorage — ported in Task #2)\n// ============================================================================\n\n/**\n * Data shape for a single panel's saved state in localStorage.\n * Defined here so computeLayout stays self-contained without depending\n * on the storage composable. useResizableStorage will re-export this\n * type when it is ported.\n */\nexport interface SavedPanelData {\n  id: string;\n  pixelSize: number;\n  collapsed?: boolean;\n  /** Whether this panel was auto-collapsed by the system (vs manually by user) */\n  autoCollapsed?: boolean;\n  /** Proportion of container this panel should occupy (set by drag, used for viewport scaling) */\n  manualTargetRatio?: number;\n}\n\n// ============================================================================\n// INPUT / OUTPUT TYPES\n// ============================================================================\n\n/**\n * Input to the layout computation.\n * All values must be resolved before calling (no lazy-loading, no Vue refs).\n */\nexport interface LayoutInput {\n  /** Registered panel configurations, in render order */\n  panels: ResizablePanelConfig[];\n  /** Current container width (row direction) or height (column direction), in pixels */\n  containerSize: number;\n  /**\n   * Saved state from localStorage (optional).\n   * When provided, sizes and collapsed state are restored from here.\n   * IDs that do not match current panels are ignored.\n   * Values that fail validation fall back to initialSize.\n   */\n  savedState?: SavedPanelData[];\n}\n\n/**\n * Computed position for a single panel.\n * All values are in pixels, relative to the container's top-left corner.\n */\nexport interface PanelPosition {\n  id: string;\n  /** Distance from the container's left edge to this panel's left edge */\n  left: number;\n  /** Distance from this panel's right edge to the container's right edge */\n  right: number;\n  /** Rendered width of the panel (0 when collapsed) */\n  width: number;\n  /** Whether the panel is currently collapsed */\n  collapsed: boolean;\n  /** Resolved constraints for this panel at the current container size */\n  constraints: ConstraintHierarchy;\n}\n\n/**\n * Computed position for a single drag handle.\n * Handles sit between adjacent visible panels.\n */\nexport interface HandlePosition {\n  /** Handle identifier: \"{beforePanelId}:{afterPanelId}\" */\n  id: string;\n  beforePanelId: string;\n  afterPanelId: string;\n  /** Pixel offset from the container's left edge to the handle's left edge */\n  left: number;\n  /**\n   * True when the handle should be non-interactive.\n   * Set when either adjacent panel is collapsed or resizable: false.\n   */\n  disabled: boolean;\n}\n\n/**\n * Output of computeLayout.\n * Immutable — create a new layout by calling computeLayout again.\n */\nexport interface LayoutResult {\n  panels: Map<string, PanelPosition>;\n  handles: HandlePosition[];\n}\n\n// ============================================================================\n// INTERNAL WORKING STATE\n// ============================================================================\n\n/**\n * Internal representation while computing sizes before positions are finalized.\n */\ninterface WorkingPanel {\n  config: ResizablePanelConfig;\n  constraints: ConstraintHierarchy;\n  width: number;\n  collapsed: boolean;\n  /** True when resizable: false — panel keeps its exact pixel size, no handle rendered */\n  isFixed: boolean;\n  /**\n   * The manual ratio stored from a previous drag (0–1, fraction of container).\n   * When present, this panel's target width = manualTargetRatio * containerSize,\n   * still subject to constraints.\n   */\n  manualTargetRatio?: number;\n}\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/**\n * Resolve initial pixel size for a panel from saved state or initialSize config.\n * Returns the raw size before constraint clamping.\n */\nfunction resolveRawSize(\n  config: ResizablePanelConfig,\n  containerSize: number,\n  savedPanel: SavedPanelData | undefined\n): number {\n  if (savedPanel !== undefined) {\n    const saved = savedPanel.pixelSize;\n    // Reject corrupted saved values\n    if (!isFinite(saved) || saved < 0 || (containerSize > 0 && saved > containerSize * 2)) {\n      return parseSizeToPixels(config.initialSize ?? DEFAULT_PANEL_SIZE, containerSize);\n    }\n    return saved;\n  }\n\n  return parseSizeToPixels(config.initialSize ?? DEFAULT_PANEL_SIZE, containerSize);\n}\n\n/**\n * Determine whether a panel should be collapsed for a given input.\n * Priority: savedState.collapsed > config.collapsed\n */\nfunction resolveCollapsed(config: ResizablePanelConfig, savedPanel: SavedPanelData | undefined): boolean {\n  if (savedPanel !== undefined && savedPanel.collapsed !== undefined) {\n    return savedPanel.collapsed;\n  }\n  return Boolean(config.collapsed);\n}\n\n/**\n * Clamp a width to the constraint window.\n * Returns the clamped value and the amount of overflow/underflow.\n *\n * @param tier - Which constraints to apply:\n *   'user'   — user-min/max (for ratio panels, user-dragged sizes)\n *   'system' — system-min/max falling back to user (for proportional panels,\n *              viewport-driven redistribution)\n */\nfunction clampToConstraints(\n  width: number,\n  constraints: ConstraintHierarchy,\n  tier: 'user' | 'system' = 'system'\n): { clamped: number; delta: number } {\n  const clamped = clampToTier(width, constraints, tier);\n  return { clamped, delta: clamped - width };\n}\n\n/**\n * Build the index of saved state for O(1) lookup during panel iteration.\n * Returns undefined if saved state is structurally incompatible with current panels.\n *\n * Incompatible = current panel IDs have entries NOT present in saved state.\n * (Panel IDs that exist in saved state but not current panels are simply ignored.)\n */\nfunction buildSavedIndex(\n  savedState: SavedPanelData[] | undefined\n): Map<string, SavedPanelData> | undefined {\n  if (!savedState) return undefined;\n  return new Map<string, SavedPanelData>(savedState.map(s => [s.id, s]));\n}\n\n// ============================================================================\n// ALGORITHM\n// ============================================================================\n\n/**\n * Step 1: Build working panels with constraints and raw sizes.\n */\nfunction buildWorkingPanels(\n  panels: ResizablePanelConfig[],\n  containerSize: number,\n  savedIndex: Map<string, SavedPanelData> | undefined\n): WorkingPanel[] {\n  return panels.map(config => {\n    const constraints = calculateConstraintHierarchy(config, containerSize);\n    const savedPanel = savedIndex?.get(config.id);\n    const collapsed = resolveCollapsed(config, savedPanel);\n    const isFixed = config.resizable === false;\n\n    const savedRatio = savedPanel?.manualTargetRatio;\n\n    let rawWidth: number;\n    if (collapsed) {\n      rawWidth = 0;\n    } else if (savedRatio !== undefined && containerSize > 0) {\n      // Scale from ratio — the panel wants (ratio * container) pixels\n      rawWidth = savedRatio * containerSize;\n    } else {\n      rawWidth = resolveRawSize(config, containerSize, savedPanel);\n    }\n\n    return {\n      config,\n      constraints,\n      width: rawWidth,\n      collapsed,\n      isFixed,\n      manualTargetRatio: savedRatio,\n    };\n  });\n}\n\n/**\n * Allocate space for Tier 1 (fixed) and Tier 2 (ratio) panels.\n * Mutates panel widths in place. Returns the total reserved space.\n */\nfunction allocateReservedPanels(visiblePanels: WorkingPanel[], containerSize: number): number {\n  // Tier 1: Fixed panels (resizable: false)\n  let reservedTotal = 0;\n  for (const p of visiblePanels) {\n    if (p.isFixed) {\n      const { clamped } = clampToConstraints(p.width, p.constraints);\n      p.width = clamped;\n      reservedTotal += clamped;\n    }\n  }\n\n  // Tier 2: Ratio panels (manualTargetRatio) — user constraints only.\n  const ratioPanels = visiblePanels.filter(p => !p.isFixed && p.manualTargetRatio !== undefined);\n  for (const p of ratioPanels) {\n    const targetWidth = (p.manualTargetRatio ?? 0) * containerSize;\n    const { clamped } = clampToConstraints(targetWidth, p.constraints, 'user');\n    p.width = clamped;\n    reservedTotal += clamped;\n  }\n\n  return reservedTotal;\n}\n\n/**\n * Iteratively clamp proportional panels to their constraint windows and\n * redistribute overflow/underflow to unclamped panels. Applies a final\n * clamp pass to catch floating-point drift.\n */\nfunction constrainAndRedistribute(propPanels: WorkingPanel[]): void {\n  const maxPasses = propPanels.length + 1;\n\n  for (let pass = 0; pass < maxPasses; pass++) {\n    let totalDelta = 0;\n    const clampedIds = new Set<string>();\n\n    for (const p of propPanels) {\n      const { clamped, delta } = clampToConstraints(p.width, p.constraints);\n      if (delta !== 0) {\n        p.width = clamped;\n        clampedIds.add(p.config.id);\n        totalDelta += delta;\n      }\n    }\n\n    if (totalDelta === 0) break;\n\n    const freePanels = propPanels.filter(p => !clampedIds.has(p.config.id));\n    if (freePanels.length === 0) break;\n\n    const changePerPanel = -totalDelta / freePanels.length;\n    for (const p of freePanels) {\n      p.width += changePerPanel;\n    }\n  }\n\n  // Final clamp to catch any floating-point drift\n  for (const p of propPanels) {\n    const { clamped } = clampToConstraints(p.width, p.constraints);\n    p.width = clamped;\n  }\n}\n\n/**\n * If total allocated width < containerSize (all proportional panels hit max),\n * expand the last non-fixed visible panel to absorb the gap.\n */\nfunction applyFillGuarantee(visiblePanels: WorkingPanel[], propPanels: WorkingPanel[], containerSize: number): void {\n  const allocatedTotal = visiblePanels.reduce((sum, p) => sum + p.width, 0);\n  const gap = containerSize - allocatedTotal;\n  if (gap > 1) {\n    const lastFlexible = [...propPanels].reverse().find(p => !p.isFixed);\n    if (lastFlexible) {\n      lastFlexible.width += gap;\n    }\n  }\n}\n\n/**\n * Step 2: Distribute container space among non-collapsed panels.\n *\n * Distribution order (priority, highest first):\n *   1. Fixed panels (`resizable: false`) — keep exact initial pixel size\n *   2. Ratio panels (`manualTargetRatio`) — target (ratio × container), constrained\n *   3. Proportional panels — share remaining space using raw widths as weights\n *\n * After initial allocation, constraints are applied.\n * When a panel is min-clamped (forced larger), the extra space it consumed is\n * taken from unclamped proportional panels. When a panel is max-clamped (forced\n * smaller), the freed space is given back to unclamped proportional panels.\n * This redistribution iterates until stable (all panels within constraints) or\n * until no unclamped panels remain.\n */\nfunction distributeSpace(working: WorkingPanel[], containerSize: number): void {\n  // Early exit for zero container\n  if (containerSize <= 0) {\n    working.forEach(p => {\n      if (!p.collapsed) p.width = 0;\n    });\n    return;\n  }\n\n  const visiblePanels = working.filter(p => !p.collapsed);\n  if (visiblePanels.length === 0) return;\n\n  // ── Tier 1 + 2: Fixed and ratio panels ────────────────────────────────────\n  const reservedTotal = allocateReservedPanels(visiblePanels, containerSize);\n\n  // ── Tier 3: Proportional panels ───────────────────────────────────────────\n  const propPanels = visiblePanels.filter(p => !p.isFixed && p.manualTargetRatio === undefined);\n  const remainingSpace = Math.max(0, containerSize - reservedTotal);\n\n  if (propPanels.length === 0) return;\n\n  // Use current raw widths as proportional weights\n  const totalPropWeight = propPanels.reduce((sum, p) => sum + Math.max(0, p.width), 0);\n\n  // Initial allocation: proportional share of remaining space\n  for (const p of propPanels) {\n    if (totalPropWeight > 0) {\n      p.width = (p.width / totalPropWeight) * remainingSpace;\n    } else {\n      // All weights are zero — distribute equally\n      p.width = remainingSpace / propPanels.length;\n    }\n  }\n\n  // ── Constraint pass with overflow redistribution ──────────────────────────\n  constrainAndRedistribute(propPanels);\n\n  // ── Fill guarantee ──────────────────────────────────────────────────────\n  applyFillGuarantee(visiblePanels, propPanels, containerSize);\n}\n\n/**\n * Distribute +1px to panels with the largest fractional remainders,\n * skipping panels that are at their max constraint or fixed.\n */\nfunction distributeShortfall(remainders: { panel: WorkingPanel; remainder: number }[], shortfall: number): void {\n  remainders.sort((a, b) => b.remainder - a.remainder);\n  let remaining = shortfall;\n  for (const { panel } of remainders) {\n    if (remaining <= 0) break;\n    const max = panel.constraints.systemMaxSizePixels ?? panel.constraints.userMaxSizePixels ?? Infinity;\n    if (panel.width < max && !panel.isFixed) {\n      panel.width += 1;\n      remaining -= 1;\n    }\n  }\n}\n\n/**\n * Step 3: Round widths to integers and fix up rounding error.\n *\n * After distributing floating-point widths, some panels get ceil'd and some\n * floor'd. We use a \"largest remainder\" approach so the total always equals\n * the container size exactly (when not fully clamped by constraints).\n */\nfunction roundWidths(working: WorkingPanel[], containerSize: number): void {\n  if (containerSize <= 0) return;\n\n  const visiblePanels = working.filter(p => !p.collapsed);\n  if (visiblePanels.length === 0) return;\n\n  // Floor all widths first, collect remainders\n  const remainders: { panel: WorkingPanel; remainder: number }[] = [];\n\n  for (const p of visiblePanels) {\n    const floored = Math.floor(p.width);\n    remainders.push({ panel: p, remainder: p.width - floored });\n    p.width = floored;\n  }\n\n  const currentTotal = visiblePanels.reduce((s, p) => s + p.width, 0);\n  const shortfall = containerSize - currentTotal;\n\n  distributeShortfall(remainders, shortfall);\n}\n\n/**\n * Step 4: Compute absolute left/right positions for each panel.\n */\nfunction computePositions(working: WorkingPanel[], containerSize: number): Map<string, PanelPosition> {\n  const result = new Map<string, PanelPosition>();\n  let cursor = 0;\n\n  for (const p of working) {\n    const width = p.collapsed ? 0 : p.width;\n    const left = cursor;\n    const right = Math.max(0, containerSize - left - width);\n\n    result.set(p.config.id, {\n      id: p.config.id,\n      left,\n      right,\n      width,\n      collapsed: p.collapsed,\n      constraints: p.constraints,\n    });\n\n    cursor += width;\n  }\n\n  return result;\n}\n\n/**\n * Step 5: Compute handle positions.\n *\n * A handle is only generated for pairs of adjacent panels where BOTH panels\n * are resizable (resizable !== false). Pairs involving a fixed panel are\n * skipped entirely — no ResizableHandle component exists between them, and\n * including them in the array would shift the autoIndex values that handle\n * components use to look up their own position.\n *\n * Its left position equals the right edge of the before-panel.\n * It is disabled when either adjacent panel is collapsed.\n */\nfunction computeHandles(\n  panels: ResizablePanelConfig[],\n  positions: Map<string, PanelPosition>,\n): HandlePosition[] {\n  const handles: HandlePosition[] = [];\n\n  for (let i = 0; i < panels.length - 1; i++) {\n    const before = panels[i];\n    const after = panels[i + 1];\n\n    // Skip pairs that involve a fixed (non-resizable) panel.\n    // No ResizableHandle component is placed between fixed panels, so\n    // generating an entry would misalign autoIndex → handles[] lookups.\n    if (before.resizable === false || after.resizable === false) continue;\n\n    const beforePos = positions.get(before.id);\n    const afterPos = positions.get(after.id);\n\n    if (!beforePos || !afterPos) continue;\n\n    const disabled = beforePos.collapsed || afterPos.collapsed;\n\n    handles.push({\n      id: buildHandleId(before.id, after.id),\n      beforePanelId: before.id,\n      afterPanelId: after.id,\n      left: beforePos.left + beforePos.width,\n      disabled,\n    });\n  }\n\n  return handles;\n}\n\n// ============================================================================\n// PUBLIC API\n// ============================================================================\n\n/**\n * Compute the complete layout for a group of resizable panels.\n *\n * This is a pure function — it has no side effects and does not read from\n * or write to the DOM, Vue reactivity, or localStorage.\n *\n * @param input - Panel configs, container size, and optional saved state\n * @returns Immutable layout result with panel positions and handle positions\n *\n * @example\n * const layout = computeLayout({\n *   panels: registeredPanels,\n *   containerSize: containerWidth,\n *   savedState: loadFromStorage(),\n * });\n * const feedPos = layout.panels.get('feed-panel');\n * // feedPos.left, feedPos.width, feedPos.right, feedPos.collapsed\n */\nexport function computeLayout(input: LayoutInput): LayoutResult {\n  const { panels, containerSize, savedState } = input;\n\n  // Degenerate cases\n  if (panels.length === 0) {\n    return { panels: new Map(), handles: [] };\n  }\n\n  // Build saved-state lookup (returns undefined if incompatible with current panels)\n  const savedIndex = buildSavedIndex(savedState);\n\n  const working = buildWorkingPanels(panels, containerSize, savedIndex);\n  distributeSpace(working, containerSize);\n  roundWidths(working, containerSize);\n  const positions = computePositions(working, containerSize);\n  const handles = computeHandles(panels, positions);\n\n  return { panels: positions, handles };\n}\n","import { DEFAULT_PANEL_SIZE } from '../resizable_constants';\nimport type { ResizablePanelConfig, ResizablePanelState } from '../resizable_constants';\nimport type { ResizableStorageAdapter, ResizableStoragePanelData } from '../resizable_constants';\nimport { parseSizeToPixels } from '../resizable_utils';\n\n// Re-export for backward compatibility\nexport type SavedPanelData = ResizableStoragePanelData;\n\n// ============================================================================\n// VALIDATION\n// ============================================================================\n\nfunction validateRequiredProperties(data: Record<string, unknown>): boolean {\n  return typeof data.id === 'string' && typeof data.pixelSize === 'number' && data.pixelSize >= 0;\n}\n\nfunction validateOptionalProperties(data: Record<string, unknown>): boolean {\n  return (\n    (data.collapsed === undefined || typeof data.collapsed === 'boolean') &&\n    (data.autoCollapsed === undefined || typeof data.autoCollapsed === 'boolean')\n  );\n}\n\nfunction isSavedPanelData(obj: unknown): obj is ResizableStoragePanelData {\n  if (typeof obj !== 'object' || obj === null) return false;\n  const data = obj as Record<string, unknown>;\n  return validateRequiredProperties(data) && validateOptionalProperties(data);\n}\n\nfunction isSavedPanelDataArray(obj: unknown): obj is ResizableStoragePanelData[] {\n  return Array.isArray(obj) && obj.every(item => isSavedPanelData(item));\n}\n\n/**\n * Validates a stored panel size against container bounds and returns a safe value.\n *\n * Checks for non-finite values, negative values, and oversized values (> 2x container).\n */\nexport function validateStoredPanelSize(\n  storedSize: number,\n  containerSize: number,\n  panelConfig: ResizablePanelConfig\n): number {\n  if (!isFinite(storedSize) || storedSize < 0) {\n    return parseSizeToPixels(panelConfig.initialSize || DEFAULT_PANEL_SIZE, containerSize);\n  }\n\n  if (containerSize > 0 && storedSize > containerSize * 2) {\n    console.warn(\n      `[resizable] Stored size ${storedSize}px for panel '${panelConfig.id}' exceeds 2x container (${containerSize}px). Resetting.`\n    );\n    return parseSizeToPixels(panelConfig.initialSize || DEFAULT_PANEL_SIZE, containerSize);\n  }\n\n  return storedSize;\n}\n\n// ============================================================================\n// LOCALSTORAGE ADAPTER\n// ============================================================================\n\n/**\n * Create a localStorage-backed storage adapter.\n *\n * @param key - The localStorage key to use\n * @returns A ResizableStorageAdapter backed by localStorage\n *\n * @example\n * ```vue\n * <dt-resizable :storage=\"localStorageAdapter('my-layout')\">\n * ```\n */\nexport function localStorageAdapter(key: string): ResizableStorageAdapter {\n  return {\n    save(data: ResizableStoragePanelData[]): void {\n      try {\n        localStorage.setItem(key, JSON.stringify(data));\n      } catch (error) {\n        console.error('[resizable] Failed to save to localStorage:', error);\n      }\n    },\n\n    load(): ResizableStoragePanelData[] | null {\n      try {\n        const saved = localStorage.getItem(key);\n        if (!saved) return null;\n\n        let parsed: unknown;\n        try {\n          parsed = JSON.parse(saved);\n        } catch {\n          localStorage.removeItem(key);\n          return null;\n        }\n\n        if (!isSavedPanelDataArray(parsed)) {\n          localStorage.removeItem(key);\n          return null;\n        }\n\n        return parsed;\n      } catch (error) {\n        console.warn('[resizable] Failed to load from localStorage:', error);\n        try { localStorage.removeItem(key); } catch { /* ignore */ }\n        return null;\n      }\n    },\n\n    clear(): void {\n      try {\n        localStorage.removeItem(key);\n      } catch { /* ignore */ }\n    },\n  };\n}\n\n// ============================================================================\n// COMPOSABLE\n// ============================================================================\n\n/**\n * Composable for managing panel persistence.\n *\n * Accepts either a storageKey (string → auto-creates localStorage adapter)\n * or a custom ResizableStorageAdapter. The adapter takes precedence.\n *\n * @param storageKeyOrAdapter - localStorage key string, or null\n * @param customAdapter - Optional custom adapter (overrides storageKey)\n */\nexport function useResizableStorage(\n  storageKeyOrAdapter: string | null,\n  customAdapter?: ResizableStorageAdapter\n) {\n  // Resolve the adapter: custom > storageKey > null\n  const adapter: ResizableStorageAdapter | null = customAdapter\n    ?? (storageKeyOrAdapter ? localStorageAdapter(storageKeyOrAdapter) : null);\n\n  function saveToStorage(panels: ResizableStoragePanelData[] | ResizablePanelState[]): void {\n    if (!adapter) return;\n\n    const data: ResizableStoragePanelData[] = panels.map(panel => ({\n      id: panel.id,\n      pixelSize: panel.pixelSize,\n      collapsed: panel.collapsed,\n      autoCollapsed: panel.autoCollapsed,\n    }));\n\n    adapter.save(data);\n  }\n\n  function loadFromStorage(): ResizableStoragePanelData[] | null {\n    if (!adapter) return null;\n\n    const data = adapter.load();\n    if (!data) return null;\n\n    // Re-validate even if adapter returned data (defense in depth)\n    if (!isSavedPanelDataArray(data)) {\n      adapter.clear();\n      return null;\n    }\n\n    return data;\n  }\n\n  function restorePanelFromStorage(panel: ResizablePanelState, savedPanel: ResizableStoragePanelData): void {\n    if (panel.restoredFromStorage) return;\n\n    if (savedPanel.pixelSize !== undefined) {\n      panel.pixelSize = savedPanel.pixelSize;\n    }\n    if (savedPanel.collapsed !== undefined) {\n      panel.collapsed = savedPanel.collapsed;\n    }\n    if (savedPanel.autoCollapsed !== undefined) {\n      panel.autoCollapsed = savedPanel.autoCollapsed;\n    }\n\n    panel.restoredFromStorage = true;\n  }\n\n  function loadFromStorageWithValidation(panels: ResizablePanelState[]): boolean {\n    const savedState = loadFromStorage();\n    if (!savedState) return false;\n\n    const currentPanelIds = new Set(panels.map(p => p.id));\n    const savedPanelIds = new Set(savedState.map(p => p.id));\n\n    // Clear if current panels don't all exist in saved (panel config changed)\n    const hasIncompatiblePanels = Array.from(currentPanelIds).some(id => !savedPanelIds.has(id));\n    if (hasIncompatiblePanels) {\n      if (adapter) adapter.clear();\n      return false;\n    }\n\n    savedState.forEach(savedPanel => {\n      const panel = panels.find(p => p.id === savedPanel.id);\n      if (panel) restorePanelFromStorage(panel, savedPanel);\n    });\n\n    return true;\n  }\n\n  function clearStorage(): void {\n    if (adapter) adapter.clear();\n  }\n\n  return {\n    saveToStorage,\n    loadFromStorage,\n    loadFromStorageWithValidation,\n    restorePanelFromStorage,\n    clearStorage,\n  };\n}\n","/**\n * useResizableGroup — Reactive Layout Controller\n *\n * Replaces the timer-based initialization flow with a Vue `computed` that\n * re-runs synchronously whenever panels or the container size change.\n *\n * Responsibilities:\n * - Maintain the `registeredPanels` ref (panels call registerPanel/unregisterPanel)\n * - Track `containerSize` via a ResizeObserver (set up here, not in the component)\n * - Load saved state ONCE synchronously at creation time\n * - Expose `layout` computed that calls `computeLayout()`\n * - Expose `syncedPanels` computed that converts `LayoutResult` to `ResizablePanelState[]`\n *\n * @see computeLayout.ts — the pure layout engine\n */\n\nimport { ref, computed, watch, nextTick, type ComputedRef, type Ref } from 'vue';\nimport type { ResizablePanelConfig, ResizablePanelState, ResizableDirection } from '../resizable_constants';\nimport type { LayoutResult } from './computeLayout';\nimport type { SavedPanelData } from './useResizableStorage';\nimport { computeLayout } from './computeLayout';\nimport { useResizableStorage } from './useResizableStorage';\nimport { calculateConstraintHierarchy } from './constraintResolver';\nimport { validateContainerSize } from '../resizable_utils';\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport interface UseResizableGroupOptions {\n  storageKey: string | null;\n  direction: ComputedRef<ResizableDirection>;\n  containerRef: Ref<HTMLElement | null>;\n  /** Custom storage adapter. Overrides storageKey when provided. */\n  storageAdapter?: import('../resizable_constants').ResizableStorageAdapter;\n}\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/** Clamp a container dimension to a valid range. Delegates to the shared utility. */\nconst clampContainerSize = validateContainerSize;\n\n/**\n * Build a `ResizablePanelState` from a panel config + the layout result.\n * Reads `manualTargetRatio` and `autoCollapsed` from savedState.\n */\nfunction buildPanelState(\n  config: ResizablePanelConfig,\n  containerSize: number,\n  layoutResult: LayoutResult,\n  saved: SavedPanelData | undefined\n): ResizablePanelState {\n  const position = layoutResult.panels.get(config.id);\n  const constraints = position?.constraints ?? calculateConstraintHierarchy(config, containerSize);\n\n  const pixelSize = position?.width ?? 0;\n  const collapsed = position?.collapsed ?? Boolean(config.collapsed);\n\n  return {\n    ...config,\n    pixelSize,\n    collapsed,\n    userMinSizePixels: constraints.userMinSizePixels,\n    userMaxSizePixels: constraints.userMaxSizePixels,\n    systemMinSizePixels: constraints.systemMinSizePixels,\n    systemMaxSizePixels: constraints.systemMaxSizePixels,\n    collapseSizePixels: constraints.collapseSizePixels,\n    manualTargetRatio: saved?.manualTargetRatio,\n    autoCollapsed: saved?.autoCollapsed,\n  };\n}\n\n// ============================================================================\n// COMPOSABLE\n// ============================================================================\n\nexport function useResizableGroup(options: UseResizableGroupOptions) {\n  const { storageKey, direction, containerRef } = options;\n\n  // ── Panel registry ──────────────────────────────────────────────────────────\n  const registeredPanels = ref<ResizablePanelConfig[]>([]);\n\n  // ── Container size ──────────────────────────────────────────────────────────\n  const containerSize = ref(0);\n\n  // ── Storage ─────────────────────────────────────────────────────────────────\n  const storage = useResizableStorage(storageKey, options.storageAdapter);\n  const savedState = ref<SavedPanelData[] | null>(storage.loadFromStorage());\n\n  // ── isInitializing ─────────────────────────────────────────────────────────\n  const isInitializing = ref(true);\n\n  // ── Layout computed ─────────────────────────────────────────────────────────\n  const layout = computed((): LayoutResult => {\n    const panels = registeredPanels.value;\n    const size = containerSize.value;\n\n    if (panels.length === 0 || size <= 0) {\n      return { panels: new Map(), handles: [] };\n    }\n\n    return computeLayout({\n      panels,\n      containerSize: size,\n      savedState: savedState.value ?? undefined,\n    });\n  });\n\n  // ── syncedPanels computed ───────────────────────────────────────────────────\n  const syncedPanels = computed((): ResizablePanelState[] => {\n    const result = layout.value;\n    const size = containerSize.value;\n    const savedMap = new Map(savedState.value?.map(s => [s.id, s]) ?? []);\n\n    return registeredPanels.value.map(config => {\n      const saved = savedMap.get(config.id);\n      return buildPanelState(config, size, result, saved);\n    });\n  });\n\n  // Flip isInitializing to false after first successful layout\n  watch(\n    layout,\n    result => {\n      if (result.panels.size > 0 && isInitializing.value) {\n        isInitializing.value = false;\n      }\n    },\n    { immediate: true }\n  );\n\n  // ── Panel index (O(1) lookup by id) ────────────────────────────────────────\n  const panelMap = computed((): Map<string, ResizablePanelState> => {\n    const map = new Map<string, ResizablePanelState>();\n    for (const p of syncedPanels.value) map.set(p.id, p);\n    return map;\n  });\n\n  // ── Panel registration ──────────────────────────────────────────────────────\n\n  let sortScheduled = false;\n\n  function registerPanel(config: ResizablePanelConfig): void {\n    if (config.id.includes(':')) {\n      console.warn(\n        `[resizable] Panel id \"${config.id}\" contains ':' which is reserved as the handle separator. Use kebab-case.`\n      );\n    }\n\n    const index = registeredPanels.value.findIndex(p => p.id === config.id);\n    if (index !== -1) {\n      registeredPanels.value = registeredPanels.value.map((p, i) => (i === index ? config : p));\n    } else {\n      registeredPanels.value = [...registeredPanels.value, config];\n\n      if (!sortScheduled) {\n        sortScheduled = true;\n        nextTick(() => {\n          registeredPanels.value = sortByDOMOrder(registeredPanels.value);\n          sortScheduled = false;\n        });\n      }\n    }\n  }\n\n  /**\n   * Sort panel configs to match DOM order inside the container element.\n   */\n  function sortByDOMOrder(panels: ResizablePanelConfig[]): ResizablePanelConfig[] {\n    const container = containerRef.value;\n    if (!container) return panels;\n\n    const panelElements = Array.from(container.querySelectorAll<HTMLElement>('.d-resizable-panel[data-panel-id]'));\n    if (panelElements.length === 0) return panels;\n\n    const domOrder = new Map<string, number>();\n    panelElements.forEach((el, i) => {\n      const id = el.getAttribute('data-panel-id');\n      if (id) domOrder.set(id, i);\n    });\n\n    return [...panels].sort((a, b) => {\n      const aPos = domOrder.get(a.id) ?? Infinity;\n      const bPos = domOrder.get(b.id) ?? Infinity;\n      return aPos - bPos;\n    });\n  }\n\n  function unregisterPanel(id: string): void {\n    registeredPanels.value = registeredPanels.value.filter(p => p.id !== id);\n  }\n\n  // ── Storage operations ──────────────────────────────────────────────────────\n\n  function saveCurrentLayout(panels: ResizablePanelState[]): void {\n    storage.saveToStorage(panels);\n    savedState.value = panels.map(p => ({\n      id: p.id,\n      pixelSize: p.pixelSize,\n      collapsed: p.collapsed,\n      autoCollapsed: p.autoCollapsed,\n      manualTargetRatio: p.manualTargetRatio,\n    }));\n  }\n\n  function updateSavedPanel(panelId: string, updates: Partial<SavedPanelData>): void {\n    if (!savedState.value) savedState.value = [];\n    const idx = savedState.value.findIndex(s => s.id === panelId);\n    if (idx >= 0) {\n      savedState.value[idx] = { ...savedState.value[idx], ...updates };\n    } else {\n      // Use current computed size as default, not 0\n      const currentPanel = syncedPanels.value.find(p => p.id === panelId);\n      const currentSize = currentPanel?.pixelSize ?? 0;\n      savedState.value.push({ id: panelId, pixelSize: currentSize, ...updates });\n    }\n    savedState.value = [...savedState.value]; // trigger reactivity\n\n    // Persist to external storage\n    storage.saveToStorage(savedState.value);\n  }\n\n  function reloadFromStorage(): void {\n    savedState.value = storage.loadFromStorage();\n  }\n\n  function clearSavedState(): void {\n    storage.clearStorage();\n    savedState.value = null;\n  }\n\n  // ── ResizeObserver ─────────────────────────────────────────────────────────\n\n  const resizeObserver = new ResizeObserver(entries => {\n    for (const entry of entries) {\n      const dim = direction.value === 'row' ? entry.contentRect.width : entry.contentRect.height;\n      containerSize.value = clampContainerSize(Math.round(dim));\n    }\n  });\n\n  function disconnectObserver(): void {\n    resizeObserver.disconnect();\n  }\n\n  watch(\n    containerRef,\n    (el, prev) => {\n      if (prev) resizeObserver.unobserve(prev);\n      if (el) {\n        const initial = direction.value === 'row' ? el.clientWidth : el.clientHeight;\n        containerSize.value = clampContainerSize(initial);\n        resizeObserver.observe(el);\n      }\n    },\n    { immediate: true }\n  );\n\n  // ── Expose ─────────────────────────────────────────────────────────────────\n\n  return {\n    layout,\n    syncedPanels,\n    panelMap,\n    containerSize,\n    isInitializing,\n\n    registerPanel,\n    unregisterPanel,\n\n    saveCurrentLayout,\n    updateSavedPanel,\n    reloadFromStorage,\n    clearSavedState,\n\n    disconnectObserver,\n  };\n}\n","/**\n * useResizableDrag — Per-group drag state composable\n *\n * Each ResizableGroup instance gets its own drag composable, so nested groups can\n * drag independently without conflict.\n *\n * Key design: shadow state during drag.\n * - proposedBeforeSize / proposedAfterSize track the \"what-if\" layout during the drag.\n * - These are applied directly to DOM elements as inline styles (performance).\n * - The reactive layout state is NOT mutated during drag.\n * - On commit (mouseup / touchend): onDragEnd callback receives the final sizes.\n * - On cancel (Escape / unmount): inline styles are removed, DOM returns to layout state.\n */\n\nimport { reactive, onUnmounted, type ComputedRef, type Ref } from 'vue';\nimport type { ResizableDirection, ResizablePanelState } from '../resizable_constants';\nimport type { ResizeHandler } from './useResizableCalculations';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport type DragState = DragStateIdle | DragStateActive;\n\nexport interface DragStateIdle {\n  isActive: false;\n  handleId: null;\n  beforePanelId: null;\n  afterPanelId: null;\n  proposedBeforeSize: 0;\n  proposedAfterSize: 0;\n}\n\nexport interface DragStateActive {\n  isActive: true;\n  handleId: string;\n  beforePanelId: string;\n  afterPanelId: string;\n  /** Proposed before-panel size during drag (shadow — not committed to layout yet) */\n  proposedBeforeSize: number;\n  /** Proposed after-panel size during drag (shadow — not committed to layout yet) */\n  proposedAfterSize: number;\n}\n\n/** Initial idle state for reactive() initialization. */\nconst IDLE_STATE: DragStateIdle = {\n  isActive: false,\n  handleId: null,\n  beforePanelId: null,\n  afterPanelId: null,\n  proposedBeforeSize: 0,\n  proposedAfterSize: 0,\n};\n\nexport interface UseResizableDragOptions {\n  direction: ComputedRef<ResizableDirection>;\n  containerRef: Ref<HTMLElement | null>;\n  panels: ComputedRef<ResizablePanelState[]> | Ref<ResizablePanelState[]>;\n  containerSize: ComputedRef<number> | Ref<number>;\n  resizeHandler: ResizeHandler;\n  onDragEnd: (\n    beforePanelId: string,\n    afterPanelId: string,\n    beforeSize: number,\n    afterSize: number,\n    sizesChanged: boolean\n  ) => void;\n  onDragStart?: (handleId: string) => void;\n}\n\n// ============================================================================\n// DOM HELPERS\n// ============================================================================\n\nfunction findPanelElement(container: HTMLElement, panelId: string): HTMLElement | null {\n  return container.querySelector<HTMLElement>(`[data-panel-id=\"${panelId}\"]`);\n}\n\nfunction findHandleElement(container: HTMLElement, handleId: string): HTMLElement | null {\n  return container.querySelector<HTMLElement>(`[data-handle-id=\"${handleId}\"]`);\n}\n\nfunction applyPanelDragStyle(element: HTMLElement, start: number, end: number): void {\n  element.style.insetInlineStart = `${start}px`;\n  element.style.insetInlineEnd = `${end}px`;\n  element.style.inlineSize = '';\n}\n\nfunction clearDragStyle(element: HTMLElement): void {\n  element.style.insetInlineStart = '';\n  element.style.insetInlineEnd = '';\n  element.style.inlineSize = '';\n}\n\nfunction applyHandleDragStyle(element: HTMLElement, position: number): void {\n  element.style.insetInlineStart = `${Math.max(0, position)}px`;\n}\n\nfunction clearHandleDragStyle(element: HTMLElement): void {\n  element.style.insetInlineStart = '';\n}\n\n// ============================================================================\n// PANEL LOOKUP\n// ============================================================================\n\n/**\n * Find the before/after panel pair for a given handle ID.\n * Handle IDs are formatted as \"{beforePanelId}:{afterPanelId}\".\n */\nexport function findPanelsForHandle(\n  handleId: string,\n  panels: ResizablePanelState[]\n): { beforePanel: ResizablePanelState | null; afterPanel: ResizablePanelState | null } {\n  const sepIndex = handleId.indexOf(':');\n  if (sepIndex === -1) return { beforePanel: null, afterPanel: null };\n\n  const beforeId = handleId.slice(0, sepIndex);\n  const afterId = handleId.slice(sepIndex + 1);\n\n  const beforePanel = panels.find(p => p.id === beforeId) ?? null;\n  const afterPanel = panels.find(p => p.id === afterId) ?? null;\n  return { beforePanel, afterPanel };\n}\n\n// ============================================================================\n// COMPOSABLE\n// ============================================================================\n\n/**\n * Must be called from component setup context (uses `onUnmounted` lifecycle hook).\n */\nexport function useResizableDrag(options: UseResizableDragOptions) {\n  const { direction, containerRef, panels, containerSize, resizeHandler, onDragEnd, onDragStart } = options;\n\n  const dragState = reactive<DragState>({ ...IDLE_STATE });\n\n  let beforePanelEl: HTMLElement | null = null;\n  let afterPanelEl: HTMLElement | null = null;\n  let handleEl: HTMLElement | null = null;\n\n  let cachedBeforePanel: ResizablePanelState | null = null;\n  let cachedAfterPanel: ResizablePanelState | null = null;\n\n  let originalBeforeSize = 0;\n  let originalAfterSize = 0;\n  let beforePanelLeft = 0;\n  let cachedContainerRect: DOMRect | null = null;\n\n  let boundPointerMove: ((e: PointerEvent) => void) | null = null;\n  let boundPointerUp: ((e: PointerEvent) => void) | null = null;\n\n  function attachDocumentListeners(): void {\n    boundPointerMove = (e: PointerEvent) => onDragMove(e);\n    boundPointerUp = () => commitDrag();\n\n    document.addEventListener('pointermove', boundPointerMove);\n    document.addEventListener('pointerup', boundPointerUp);\n    document.addEventListener('pointercancel', boundPointerUp);\n    document.addEventListener('keydown', handleKeydown);\n  }\n\n  function removeDocumentListeners(): void {\n    if (boundPointerMove) {\n      document.removeEventListener('pointermove', boundPointerMove);\n      boundPointerMove = null;\n    }\n    if (boundPointerUp) {\n      document.removeEventListener('pointerup', boundPointerUp);\n      document.removeEventListener('pointercancel', boundPointerUp);\n      boundPointerUp = null;\n    }\n    document.removeEventListener('keydown', handleKeydown);\n  }\n\n  function cleanup(): void {\n    removeDocumentListeners();\n\n    document.body.style.userSelect = '';\n    document.body.style.cursor = '';\n\n    Object.assign(dragState, IDLE_STATE);\n\n    beforePanelEl = null;\n    afterPanelEl = null;\n    handleEl = null;\n    cachedBeforePanel = null;\n    cachedAfterPanel = null;\n    originalBeforeSize = 0;\n    originalAfterSize = 0;\n    beforePanelLeft = 0;\n    cachedContainerRect = null;\n  }\n\n  function locateDragElements(\n    container: HTMLElement,\n    handleId: string,\n    panelList: ResizablePanelState[]\n  ): {\n    beforePanel: ResizablePanelState;\n    afterPanel: ResizablePanelState;\n    beforeEl: HTMLElement;\n    afterEl: HTMLElement;\n    handleElement: HTMLElement | null;\n  } | null {\n    const { beforePanel, afterPanel } = findPanelsForHandle(handleId, panelList);\n    if (!beforePanel || !afterPanel) {\n      console.warn(`[resizable] No panel pair found for handle \"${handleId}\"`);\n      return null;\n    }\n\n    const beforeEl = findPanelElement(container, beforePanel.id);\n    const afterEl = findPanelElement(container, afterPanel.id);\n    const handleElement = findHandleElement(container, handleId);\n\n    if (!beforeEl || !afterEl) {\n      console.warn(`[resizable] Panel element(s) not found for handle \"${handleId}\"`);\n      return null;\n    }\n\n    return { beforePanel, afterPanel, beforeEl, afterEl, handleElement };\n  }\n\n  function startDrag(handleId: string): void {\n    const container = containerRef.value;\n    if (!container) return;\n\n    const elements = locateDragElements(container, handleId, panels.value);\n    if (!elements) return;\n\n    beforePanelEl = elements.beforeEl;\n    afterPanelEl = elements.afterEl;\n    handleEl = elements.handleElement;\n\n    cachedBeforePanel = elements.beforePanel;\n    cachedAfterPanel = elements.afterPanel;\n\n    originalBeforeSize = elements.beforePanel.pixelSize;\n    originalAfterSize = elements.afterPanel.pixelSize;\n\n    beforePanelLeft = parseFloat(beforePanelEl.style.insetInlineStart || '0');\n    cachedContainerRect = container.getBoundingClientRect();\n\n    Object.assign(dragState, {\n      isActive: true,\n      handleId,\n      beforePanelId: elements.beforePanel.id,\n      afterPanelId: elements.afterPanel.id,\n      proposedBeforeSize: originalBeforeSize,\n      proposedAfterSize: originalAfterSize,\n    } satisfies DragStateActive);\n\n    document.body.style.userSelect = 'none';\n    document.body.style.cursor = direction.value === 'row' ? 'ew-resize' : 'ns-resize';\n\n    attachDocumentListeners();\n    onDragStart?.(handleId);\n  }\n\n  function computeDragPosition(\n    event: PointerEvent,\n    dir: ResizableDirection\n  ): number {\n    const rect = cachedContainerRect!;\n    return dir === 'row' ? event.clientX - rect.left : event.clientY - rect.top;\n  }\n\n  function isDragMoveReady(): boolean {\n    return (\n      dragState.isActive &&\n      !!containerRef.value &&\n      !!beforePanelEl &&\n      !!afterPanelEl &&\n      !!dragState.handleId &&\n      !!cachedBeforePanel &&\n      !!cachedAfterPanel\n    );\n  }\n\n  function onDragMove(event: PointerEvent): void {\n    if (!isDragMoveReady()) return;\n\n    const rawCursorPosition = computeDragPosition(event, direction.value);\n\n    const result = resizeHandler.processResizeMove(\n      rawCursorPosition,\n      cachedBeforePanel!,\n      cachedAfterPanel!,\n      containerSize.value,\n      dragState.handleId!,\n      panels.value,\n      beforePanelLeft\n    );\n\n    if (!result.isValidResize) return;\n\n    if (dragState.proposedBeforeSize !== result.beforePanelSize) {\n      dragState.proposedBeforeSize = result.beforePanelSize;\n    }\n    if (dragState.proposedAfterSize !== result.afterPanelSize) {\n      dragState.proposedAfterSize = result.afterPanelSize;\n    }\n\n    const containerSizeValue = containerSize.value;\n    const constrainedCursor = result.constrainedCursorPosition;\n    const beforeRight = containerSizeValue - constrainedCursor;\n    const handlePos = constrainedCursor - 2;\n\n    const afterRight = containerSizeValue - constrainedCursor - result.afterPanelSize;\n\n    applyPanelDragStyle(beforePanelEl!, beforePanelLeft, beforeRight);\n    applyPanelDragStyle(afterPanelEl!, constrainedCursor, Math.max(0, afterRight));\n\n    if (handleEl) {\n      applyHandleDragStyle(handleEl, handlePos);\n    }\n  }\n\n  function commitDrag(): void {\n    if (!dragState.isActive) return;\n\n    const beforePanelId = dragState.beforePanelId;\n    const afterPanelId = dragState.afterPanelId;\n    const beforeSize = dragState.proposedBeforeSize;\n    const afterSize = dragState.proposedAfterSize;\n\n    const capturedOriginalBeforeSize = originalBeforeSize;\n    const capturedOriginalAfterSize = originalAfterSize;\n\n    if (beforePanelEl) clearDragStyle(beforePanelEl);\n    if (afterPanelEl) clearDragStyle(afterPanelEl);\n    if (handleEl) clearHandleDragStyle(handleEl);\n\n    cleanup();\n\n    const sizesChanged = beforeSize !== capturedOriginalBeforeSize || afterSize !== capturedOriginalAfterSize;\n\n    if (beforePanelId && afterPanelId) {\n      onDragEnd(beforePanelId, afterPanelId, beforeSize, afterSize, sizesChanged);\n    }\n  }\n\n  function cancelDrag(): void {\n    if (!dragState.isActive) return;\n\n    if (beforePanelEl && afterPanelEl) {\n      clearDragStyle(beforePanelEl);\n      clearDragStyle(afterPanelEl);\n    }\n    if (handleEl) {\n      clearHandleDragStyle(handleEl);\n    }\n\n    cleanup();\n  }\n\n  function handleKeydown(event: KeyboardEvent): void {\n    if (event.key === 'Escape' && dragState.isActive) {\n      event.preventDefault();\n      cancelDrag();\n    }\n  }\n\n  onUnmounted(() => {\n    cancelDrag();\n  });\n\n  return {\n    dragState,\n    startDrag,\n    onDragMove,\n    commitDrag,\n    cancelDrag,\n    cleanup,\n  };\n}\n","import { onMounted, onUnmounted } from 'vue';\n\n// ─── Announcements (aria-live singleton with ref counting) ───────────────\n\nlet announcementElement: HTMLElement | null = null;\nlet announcementTimeout: ReturnType<typeof setTimeout> | undefined;\nlet announcementRefCount = 0;\n\nfunction getAnnouncementElement(): HTMLElement {\n  if (!announcementElement) {\n    announcementElement = document.getElementById('d-resizable-announcements');\n\n    if (!announcementElement) {\n      announcementElement = document.createElement('div');\n      announcementElement.id = 'd-resizable-announcements';\n      announcementElement.setAttribute('aria-live', 'polite');\n      announcementElement.setAttribute('aria-atomic', 'true');\n      announcementElement.style.position = 'absolute';\n      announcementElement.style.left = '-10000px';\n      announcementElement.style.width = '1px';\n      announcementElement.style.height = '1px';\n      announcementElement.style.overflow = 'hidden';\n      document.body.appendChild(announcementElement);\n    }\n  }\n  return announcementElement;\n}\n\nfunction announce(message: string): void {\n  if (!message.trim()) return;\n\n  if (announcementTimeout) {\n    clearTimeout(announcementTimeout);\n  }\n\n  const element = getAnnouncementElement();\n  element.textContent = '';\n\n  announcementTimeout = setTimeout(() => {\n    element.textContent = message;\n    setTimeout(() => { element.textContent = ''; }, 1000);\n  }, 100);\n}\n\n// ─── Composable ───────────────────────────────────────────────────────────\n\n/**\n * Manages a shared aria-live announcements region for all DtResizable\n * instances. Uses ref counting to create/destroy the singleton DOM element.\n */\nexport function useResizableAnnouncements() {\n  onMounted(() => {\n    announcementRefCount++;\n    getAnnouncementElement();\n  });\n\n  onUnmounted(() => {\n    if (announcementTimeout) {\n      clearTimeout(announcementTimeout);\n    }\n\n    announcementRefCount--;\n    if (announcementRefCount <= 0 && announcementElement) {\n      announcementElement.remove();\n      announcementElement = null;\n      announcementRefCount = 0;\n    }\n  });\n\n  return { announce };\n}\n","/**\n * Offset positioning composable for resize handles.\n *\n * Calculates dynamic offsets from DOM elements (e.g. a fixed header/toolbar)\n * so handles and panel content can avoid overlapping external UI.\n */\n\nimport {\n  ref,\n  computed,\n  onMounted,\n  type Ref,\n  type ComputedRef,\n} from 'vue';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\nexport interface ResizableOffsetOptions {\n  /** CSS selector for the element to measure offset from (auto-measures block-size) */\n  offsetElement?: string | null;\n  /** Explicit pixel offset. Overrides offsetElement measurement when both provided. */\n  offsetAmount?: number | null;\n  /** Which edge(s) the offset applies to (default: 'start') */\n  offsetDirection?: 'start' | 'end' | 'both';\n  /** Layout direction — affects which dimension is measured */\n  direction?: ComputedRef<'row' | 'column'> | Ref<'row' | 'column'>;\n}\n\nexport interface ResizableOffsetResult {\n  calculatedOffset: Ref<number>;\n  updateOffset: () => void;\n  handleStyles: ComputedRef<Record<string, string>>;\n  contentStyles: ComputedRef<Record<string, string>>;\n}\n\n// ─── Composable ───────────────────────────────────────────────────────────\n\nexport function useResizableOffset(\n  options: ResizableOffsetOptions = {},\n): ResizableOffsetResult {\n  const {\n    offsetElement = null,\n    offsetAmount = null,\n    offsetDirection = 'start',\n    direction = ref('row'),\n  } = options;\n\n  const calculatedOffset = ref(0);\n\n  function updateOffset(): void {\n    // Explicit amount wins over element measurement\n    if (offsetAmount != null && offsetAmount > 0) {\n      calculatedOffset.value = offsetAmount;\n      return;\n    }\n\n    if (!offsetElement) { calculatedOffset.value = 0; return; }\n\n    try {\n      const element = document.querySelector(offsetElement);\n      if (!element) { calculatedOffset.value = 0; return; }\n\n      const rect = element.getBoundingClientRect();\n      const dim = direction.value === 'row' ? rect.height : rect.width;\n      calculatedOffset.value = dim;\n    } catch (error) {\n      console.warn('[resizable] Failed to measure offset element:', error);\n      calculatedOffset.value = 0;\n    }\n  }\n\n  // ── Computed styles — logical properties rotate with writing-mode ──\n\n  const handleStyles = computed(() => {\n    const styles: Record<string, string> = {};\n    if (calculatedOffset.value <= 0) return styles;\n    const px = `${calculatedOffset.value}px`;\n    if (offsetDirection === 'start' || offsetDirection === 'both') styles.insetBlockStart = px;\n    if (offsetDirection === 'end' || offsetDirection === 'both') styles.insetBlockEnd = px;\n    return styles;\n  });\n\n  const contentStyles = computed(() => {\n    const styles: Record<string, string> = {};\n    if (calculatedOffset.value <= 0) return styles;\n    const px = `${calculatedOffset.value}px`;\n    if (offsetDirection === 'start' || offsetDirection === 'both') styles.paddingBlockStart = px;\n    if (offsetDirection === 'end' || offsetDirection === 'both') styles.paddingBlockEnd = px;\n    return styles;\n  });\n\n  onMounted(() => { updateOffset(); });\n\n  return { calculatedOffset, updateOffset, handleStyles, contentStyles };\n}\n","<template>\n  <div\n    ref=\"containerRef\"\n    :class=\"[\n      'd-resizable',\n      `d-resizable--${currentDirection}`,\n      { 'd-resizable--resizing': isResizing },\n      props.class,\n    ]\"\n    :data-storage-key=\"props.storageKey || undefined\"\n  >\n    <!-- @slot Container for panels and handles. -->\n    <slot\n      :panels=\"group.syncedPanels.value\"\n      :direction=\"currentDirection\"\n      :is-resizing=\"isResizing\"\n      :space-allocation-strategy=\"props.spaceAllocationStrategy\"\n      :resize-panel=\"resizePanel\"\n      :collapse-panel=\"collapsePanel\"\n      :start-resize=\"startResize\"\n      :stop-resize=\"stopResize\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport {\n  ref,\n  computed,\n  watch,\n  onUnmounted,\n  provide,\n} from 'vue';\nimport { RESIZABLE_CONTEXT_KEY, buildHandleId } from './resizable_constants';\nimport {\n  useResizablePanelControls,\n  useResizableGroup,\n  useResizeHandling,\n  checkAutoCollapseRules,\n  useResizableAnnouncements,\n  useResizableOffset,\n} from './composables';\nimport { useResizableDrag } from './composables/useResizableDrag';\n\nconst props = defineProps({\n  /**\n   * Layout direction. 'row' for horizontal, 'column' for vertical.\n   * @values 'row', 'column'\n   */\n  direction: {\n    type: String,\n    default: 'row',\n  },\n  /** localStorage key for persisting panel sizes across page loads. */\n  storageKey: {\n    type: String,\n    default: null,\n  },\n  /** Additional CSS classes applied to the container element. */\n  class: {\n    type: [String, Object, Array],\n    default: '',\n  },\n  /**\n   * Panel configurations array. When provided, panels are initialized\n   * from this array instead of registering via child DtResizablePanel components.\n   */\n  panels: {\n    type: Array,\n    default: () => [],\n  },\n  /**\n   * Strategy for redistributing space when panels open/close.\n   * @values 'proportional', 'preserve-manual'\n   */\n  spaceAllocationStrategy: {\n    type: String,\n    default: 'proportional',\n    validator: (val) => ['proportional', 'preserve-manual'].includes(val),\n  },\n  /** Rules defining which panels collapse first when space is constrained */\n  collapseRules: {\n    type: Array,\n    default: () => [],\n  },\n  /** Custom storage adapter. Overrides storageKey when both are provided. */\n  storage: {\n    type: Object,\n    default: null,\n  },\n  /** CSS selector for a fixed element to offset handles and panel content from. */\n  offsetElement: { type: String, default: null },\n  /** Explicit pixel offset. Overrides offsetElement measurement when both provided. */\n  offsetAmount: { type: Number, default: null },\n  /**\n   * Which edge(s) the offset applies to.\n   * @values 'start', 'end', 'both'\n   */\n  offsetDirection: { type: String, default: 'start' },\n  /**\n   * i18n message overrides for screen reader announcements.\n   * Accepts keys from ResizableKeyboardMessages.\n   */\n  messages: {\n    type: Object,\n    default: () => ({}),\n  },\n});\n\nconst emit = defineEmits(\n  /**\n   * @event panel-resize - Emitted when a panel is resized. Payload: (panelId, size).\n   * @event panel-collapse - Emitted when a panel collapses or expands. Payload: (panelId, collapsed).\n   * @event resize-start - Emitted when a resize drag begins. Payload: (handleId).\n   * @event resize-end - Emitted when a resize drag ends. Payload: (handleId).\n   */\n  ['panel-resize', 'panel-collapse', 'resize-start', 'resize-end'],\n);\n\nconst containerRef = ref(null);\n\nconst currentDirection = computed(() => props.direction);\n\n// Note: storageKey and storage are captured at mount time. If they need to\n// change dynamically in the future, useResizableGroup should accept refs.\nconst group = useResizableGroup({\n  storageKey: props.storageKey ?? null,\n  direction: currentDirection,\n  containerRef,\n  storageAdapter: props.storage ?? undefined,\n});\n\nconst isResizing = ref(false);\nconst activeHandleId = ref(undefined);\n\nconst resizeHandler = useResizeHandling(() => group.containerSize.value);\n\nconst isInitializing = group.isInitializing;\nconst registerPanel = (config) => group.registerPanel(config);\nconst unregisterPanel = (id) => group.unregisterPanel(id);\nconst saveToStorage = (panels) => group.saveCurrentLayout(panels);\n\nconst {\n  commitPanelSize,\n  resizePanel,\n  collapsePanel,\n  resetPanels: originalResetPanels,\n  processAutoCollapseExpand,\n} = useResizablePanelControls({\n  panels: group.syncedPanels,\n  containerSize: group.containerSize,\n  containerRef,\n  onPanelResize: (panelId, size) => emit('panel-resize', panelId, size),\n  onPanelCollapse: (panelId, collapsed) => emit('panel-collapse', panelId, collapsed),\n  updateSavedPanel: (panelId, updates) => group.updateSavedPanel(panelId, updates),\n});\n\nfunction resetPanels (beforePanelId, afterPanelId, behavior = 'all') {\n  originalResetPanels(beforePanelId, afterPanelId, behavior);\n\n  if (behavior === 'all') {\n    group.syncedPanels.value.forEach(p => group.updateSavedPanel(p.id, { manualTargetRatio: undefined }));\n    group.clearSavedState();\n  } else {\n    if (beforePanelId) group.updateSavedPanel(beforePanelId, { manualTargetRatio: undefined });\n    if (afterPanelId) group.updateSavedPanel(afterPanelId, { manualTargetRatio: undefined });\n  }\n}\n\nfunction processAutoCollapse () {\n  processAutoCollapseExpand();\n  if (!props.collapseRules?.length) return;\n  const panels = group.syncedPanels.value;\n  const panelsToCollapse = checkAutoCollapseRules(panels, props.collapseRules, group.containerSize.value);\n  if (panelsToCollapse.length === 0) return;\n  const panel = panels.find(p => p.id === panelsToCollapse[0]);\n  if (panel && !panel.collapsed) collapsePanel(panelsToCollapse[0], true);\n}\n\nconst { announce } = useResizableAnnouncements();\n\nconst offset = useResizableOffset({\n  offsetElement: props.offsetElement,\n  offsetAmount: props.offsetAmount,\n  offsetDirection: props.offsetDirection,\n  direction: currentDirection,\n});\n\nconst handleInstances = new Set();\nfunction registerHandle (inst) { handleInstances.add(inst); }\nfunction unregisterHandle (inst) { handleInstances.delete(inst); }\n\nconst drag = useResizableDrag({\n  direction: currentDirection,\n  containerRef,\n  panels: group.syncedPanels,\n  containerSize: group.containerSize,\n  resizeHandler,\n  onDragStart (handleId) {\n    isResizing.value = true;\n    activeHandleId.value = handleId;\n    emit('resize-start', handleId);\n  },\n  onDragEnd (beforePanelId, afterPanelId, beforeSize, afterSize, sizesChanged) {\n    const handleId = drag.dragState.handleId ?? buildHandleId(beforePanelId, afterPanelId);\n    isResizing.value = false;\n    activeHandleId.value = undefined;\n\n    if (sizesChanged) {\n      commitPanelSize(beforePanelId, beforeSize);\n      commitPanelSize(afterPanelId, afterSize);\n\n      emit('resize-end', handleId);\n      processAutoCollapse();\n    }\n  },\n});\n\nfunction startResize (handleId) { drag.startDrag(handleId); }\nfunction stopResize () { drag.cancelDrag(); }\nfunction savePanelsToStorage () { saveToStorage(group.syncedPanels.value); }\nfunction emitPanelResize (panelId, size) { emit('panel-resize', panelId, size); }\n\nwatch(group.syncedPanels, (panels) => {\n  if (panels.length > 0 && !isInitializing.value) {\n    processAutoCollapse();\n  }\n}, { flush: 'post' });\n\nonUnmounted(() => {\n  group.disconnectObserver();\n  drag.cancelDrag();\n});\n\n// Provide single context object for child components\nprovide(RESIZABLE_CONTEXT_KEY, {\n  layout: group.layout,\n  panels: group.syncedPanels,\n  panelMap: group.panelMap,\n  direction: currentDirection,\n  containerSize: group.containerSize,\n  containerElement: computed(() => containerRef.value),\n  isResizing: computed(() => isResizing.value),\n  activeHandleId: computed(() => activeHandleId.value),\n  isInitializing: computed(() => isInitializing.value),\n  messages: props.messages,\n  startResize: (handleId) => startResize(handleId),\n  resetPanels,\n  registerHandle,\n  unregisterHandle,\n  registerPanel,\n  unregisterPanel,\n  saveToStorage: savePanelsToStorage,\n  announce,\n  offsetHandleStyles: offset.handleStyles,\n  offsetContentStyles: offset.contentStyles,\n  collapsePanel,\n  emitPanelResize,\n  commitPanelSize,\n  updateSavedPanel: (panelId, updates) => group.updateSavedPanel(panelId, updates),\n});\n\n// Expose methods for programmatic control\ndefineExpose({\n  resizePanel,\n  collapsePanel,\n  resetPanels,\n  state: computed(() => ({\n    direction: currentDirection.value,\n    panels: group.syncedPanels.value,\n    containerSize: group.containerSize.value,\n    isResizing: isResizing.value,\n    activeHandleId: activeHandleId.value,\n  })),\n  panelConfigs: computed(() => props.panels),\n  allocationStrategy: computed(() => props.spaceAllocationStrategy),\n});\n</script>\n"],"mappings":"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"}