"""Prism Component Wrapper.
User-facing wrapper for the Prism component with comprehensive documentation.
This file provides a clean Python API that wraps the auto-generated PrismComponent.
"""
from __future__ import annotations
from typing import Any, Literal, Sequence
from dash.development.base_component import Component
from .PrismComponent import PrismComponent
# Sentinel to distinguish "not provided" from an explicit None
_UNSET: Any = type("_Unset", (), {"__repr__": lambda self: "_UNSET"})()
[docs]
class Prism(PrismComponent):
"""Advanced multi-panel workspace manager for Plotly Dash.
Prism provides a powerful tabbed workspace with drag-and-drop functionality,
allowing users to create, organize, and manage multiple layouts in a single
application. It supports multi-panel splits, persistent state, and dynamic
layout loading with full async support.
**Features:**
- **Dynamic Tab Management**: Create, close, rename, and reorder tabs
- **Multi-Panel Layouts**: Split workspace into multiple panels via drag-and-drop
- **Persistent State**: Save workspace configuration across browser sessions
- **Layout Registry**: Register static or dynamic layouts with parameters
- **Async Support**: Full support for async layout callbacks
- **Type-Safe**: Complete type hints for Python 3.10+
:param id: Unique identifier for this component in Dash callbacks.
Use this ID to read workspace state or update component properties.
:type id: str or None
:param serverSessionId: Server session identifier used to invalidate
stale persisted workspaces after server restarts. Automatically set
by :func:`dash_prism.init` unless explicitly provided.
:type serverSessionId: str or None
:param theme: Visual theme for the workspace. Controls colors, backgrounds,
and overall appearance. Defaults to ``'light'``.
:type theme: str
:param size: Size variant affecting spacing, typography, and UI element sizing.
Options: ``'sm'`` (small), ``'md'`` (medium, default), ``'lg'`` (large).
Defaults to ``'md'``.
:type size: str
:param maxTabs: Maximum number of tabs allowed in the workspace. Prevents users
from creating too many tabs which could impact performance. Values less than
``1`` (e.g., ``0`` or ``-1``) mean unlimited tabs. Defaults to ``16``.
:type maxTabs: int
:param searchBarPlaceholder: Placeholder text shown in the layout search bar.
Defaults to ``'Search layouts...'``.
:type searchBarPlaceholder: str
:param layoutTimeout: Timeout in seconds for layout loading. If a layout callback
doesn't respond within this time, an error state is shown. Defaults to ``30``.
:type layoutTimeout: int
:param statusBarPosition: Position of the status bar relative to the workspace.
Options: ``'top'`` or ``'bottom'``. Defaults to ``'bottom'``.
:type statusBarPosition: str
:param actions: Array of :class:`Action` components to display in the status bar.
Each action is a clickable button with its own ``n_clicks`` for callbacks.
:type actions: list[Action] or None
:param persistence: If ``True``, workspace state is persisted across browser sessions.
The persistence method is controlled by ``persistence_type``. Defaults to ``False``.
:type persistence: bool
:param persistence_type: Where to persist workspace state. Options:
``'local'`` (localStorage, persists across browser sessions),
``'session'`` (sessionStorage, persists only for current tab session),
``'memory'`` (no persistence, state lost on page refresh).
Defaults to ``'memory'``.
:type persistence_type: str
:param initialLayout: Layout ID to automatically load in the first tab on
initial page load. Must match a layout registered via
:func:`dash_prism.register_layout` before calling :func:`dash_prism.init`.
Only applies on the very first load; if ``persistence`` is enabled and a
saved workspace exists, the persisted state takes precedence.
:type initialLayout: str or None
:param newTabOpensDropdown: Whether opening a new tab should automatically
focus the SearchBar and open the layout dropdown. If ``True`` (default),
new tabs instantly show the layout dropdown for quick selection. If
``False``, users must click the SearchBar to see available layouts.
:type newTabOpensDropdown: bool
:param readWorkspace: Read-only workspace state. Use as an ``Input`` or
``State`` in Dash callbacks to react to workspace changes.
The workspace dict contains: ``tabs`` (list of dict), ``panel`` (dict),
``activePanelId`` (str), ``activeTabIds`` (dict).
:type readWorkspace: dict or None
:param updateWorkspace: Write-only workspace state. Use as an ``Output``
in Dash callbacks to programmatically update the workspace.
Partial updates are supported.
:type updateWorkspace: dict or None
:param children: Child components (typically :class:`PrismContent` instances).
**Advanced** - Usually managed automatically by :func:`dash_prism.init`.
:type children: list or None
:param registeredLayouts: Registry of available layouts that can be rendered in tabs.
**Advanced** - Automatically populated by :func:`dash_prism.init`.
:type registeredLayouts: dict or None
:param className: CSS class name(s) to add to the root container.
Appended to Prism's internal classes. Useful for custom sizing or layout.
:type className: str or None
:param style: Inline CSS styles for the root container.
:type style: dict or None
.. rubric:: Examples
Basic usage with registered layouts:
.. code-block:: python
import dash_prism
from dash import Dash, html
app = Dash(__name__)
# Register layouts
@dash_prism.register_layout(id='home', name='Home')
def home_layout():
return html.Div('Welcome to Prism!')
@dash_prism.register_layout(id='about', name='About')
def about_layout():
return html.Div('About page')
# Create app layout
app.layout = html.Div([
dash_prism.Prism(
id='workspace',
theme='light',
maxTabs=10,
persistence=True,
persistence_type='local',
)
])
# Initialize Prism (injects layouts and creates callbacks)
dash_prism.init('workspace', app)
if __name__ == '__main__':
app.run_server(debug=True)
With status bar actions:
.. code-block:: python
from dash import Input, Output
app.layout = html.Div([
dash_prism.Prism(
id='workspace',
actions=[
dash_prism.Action(
id='save-btn',
label='Save',
icon='Save',
tooltip='Save current workspace'
),
dash_prism.Action(
id='export-btn',
label='Export',
icon='Download',
tooltip='Export workspace data'
),
],
)
])
@app.callback(
Output('save-btn', 'loading'),
Input('save-btn', 'n_clicks'),
prevent_initial_call=True
)
def handle_save(n_clicks):
# Perform save operation
return False # Stop loading spinner
Reading workspace state:
.. code-block:: python
@app.callback(
Output('workspace-info', 'children'),
Input('workspace', 'readWorkspace')
)
def display_workspace_info(workspace):
if not workspace:
return "No workspace data"
num_tabs = len(workspace.get('tabs', []))
active_panel = workspace.get('activePanelId', 'none')
return f"Tabs: {num_tabs}, Active Panel: {active_panel}"
.. seealso::
:class:`Action`
Action button component for the status bar
:func:`dash_prism.register_layout`
Decorator/function to register layouts
:func:`dash_prism.init`
Initialize Prism with Dash app
.. note::
- This component requires initialization via :func:`dash_prism.init`
- Layouts must be registered before calling ``init()``
- The workspace state is managed internally and synced with Dash via callbacks
- For best performance, limit ``maxTabs`` to a reasonable number (8-12)
"""
# Override _type to match what init.py expects
_type = "Prism"
def __init__(
self,
# Identity
id: str | None = _UNSET,
className: str | None = _UNSET,
style: dict[str, Any] | None = _UNSET,
# Appearance
theme: Literal["light", "dark"] = _UNSET,
size: Literal["sm", "md", "lg"] = _UNSET,
actions: Sequence[Component] | None = _UNSET,
statusBarPosition: Literal["top", "bottom"] = _UNSET,
# Persistence
persistence: bool = _UNSET,
persistence_type: Literal["memory", "session", "local"] = _UNSET,
# Behavior
maxTabs: int = _UNSET,
initialLayout: str | None = _UNSET,
newTabOpensDropdown: bool = _UNSET,
searchBarPlaceholder: str = _UNSET,
layoutTimeout: int = _UNSET,
# Advanced — typically managed by dash_prism.init()
children: list[Component] | None = _UNSET,
serverSessionId: str | None = _UNSET,
registeredLayouts: dict[str, Any] | None = _UNSET,
readWorkspace: dict[str, Any] | None = _UNSET,
updateWorkspace: dict[str, Any] | None = _UNSET,
**kwargs: Any,
):
# Only forward args the caller actually provided so that
# _explicitize_args on the base class sees the correct set.
_locals = locals()
explicit = {
k: v
for k, v in _locals.items()
if k not in ("self", "kwargs", "_locals", "__class__") and v is not _UNSET
}
explicit.update(kwargs)
super().__init__(**explicit)