PanelContainer
PanelContainer.svelte
Module: Panel Frontend
Path: src/lib/components/panels/PanelContainer.svelte
Props
| Prop | Type | Required | Description |
|---|---|---|---|
position |
DockedPanelPosition |
yes | Which docked slot this container occupies ('left', 'right', or 'bottom') |
Reactive State
| Variable | Type | Source | Description |
|---|---|---|---|
assignedIds |
string[] |
$userPreferences.panelLayout[position].components |
Component IDs assigned to this position |
assignedComponents |
PanelComponentConfig[] |
getComponentsForIds(assignedIds) |
Resolved and sorted configs |
activeTabId |
string |
$state, persisted in uiState |
Currently active tab's component ID |
loadedComponents |
Map<string, Component> |
$state |
Cache of lazily loaded Svelte components |
loadingIds |
Set<string> |
$state |
Component IDs currently being loaded |
errorIds |
Map<string, string> |
$state |
Component IDs that failed to load, with error messages |
contextMenu |
{ x, y, componentId } | null |
$state |
Right-click context menu state |
Behavior
Tab Management
If multiple components are assigned to a position, a tab bar renders at the top with one tab per component. Each tab shows the component's icon (resolved via LucideIcons[config.icon]) and name. Single-component positions show the title without a tab bar. The active tab is persisted across sessions via userPreferences.updateUIState({ ['activeTab_' + position]: id }).
Lazy-Loading
Components are loaded via dynamic import() only when their tab first becomes active. The loading sequence:
- Tab activated -> check
loadedComponentscache - If cached, render immediately
- If not cached, add to
loadingIdsset, show spinner - Call
config.component()(the lazy-load function from registration) - On success: add to
loadedComponentscache, remove fromloadingIds - On error: add to
errorIdswith error message, remove fromloadingIds, show retry button
Collapse
The collapse button (position-specific icon: PanelLeftClose, PanelRightClose, or PanelBottomClose) calls userPreferences.collapsePanel(position). This sets uiState.collapsedPanels[position] = true. ResizableLayout detects this and switches from rendering PanelContainer to MiniPanel.
Pop-Out Context Menu
Right-clicking a tab opens a context menu with "Pop Out" option, but only if the component's allowedPositions includes 'floating'. Clicking "Pop Out" calls userPreferences.popOutPanel(componentId, position, { x, y }), which:
- Removes the component from this position's
componentsarray - Creates a new
FloatingPanelInstancewith the component - The FloatingPanelManager reactively picks up the new instance
The context menu closes on any click outside or on Escape key.
Decision Points
| Condition | Branch |
|---|---|
assignedComponents.length === 0 |
Renders nothing (empty position) |
assignedComponents.length === 1 |
Shows title bar without tab strip |
assignedComponents.length > 1 |
Shows full tab bar |
loadedComponents.has(activeTabId) |
Renders cached component |
loadingIds.has(activeTabId) |
Shows loading spinner |
errorIds.has(activeTabId) |
Shows error message with retry button |
!isAllowedAtPosition(id, 'floating') |
Hides "Pop Out" from context menu |
Imports / Dependencies
| Import | Source | Purpose |
|---|---|---|
LucideIcons |
lucide-svelte |
Dynamic icon resolution for tabs |
ExternalLink |
lucide-svelte |
Pop-out context menu icon |
PanelLeftClose, PanelRightClose, PanelBottomClose |
lucide-svelte |
Position-specific collapse icons |
Component |
svelte |
Generic component type for rendering |
userPreferences |
$lib/stores/preferences |
State store for layout and UI state |
getComponentsForIds, PanelComponentConfig, PanelPosition, DockedPanelPosition |
./PanelRegistry |
Registry lookups and types |
createLogger |
$lib/services/loggerService |
Logger ('panel-container') |
Side Effects
- Persists active tab to
uiStateon tab change (debounced viaupdateUIState) - Collapse action modifies
uiState.collapsedPanels(immediate save) - Pop-out action modifies
panelLayout(immediate save) -- removes from docked, creates floating