ttabs-svelte
Version:
A flexible layout management system with draggable, resizable tiles and tabs for Svelte applications. Like in VSCode
449 lines (448 loc) • 15.7 kB
TypeScript
import type { TileState, TileGridState, TileRowState, TileColumnState, TilePanelState, TileTabState, TileContentState, TileType } from './types/tile-types';
import type { Component } from 'svelte';
import type { TtabsTheme } from './types/theme-types';
import { Column, Grid, Panel, Row, Tab } from './ttabsObjects';
import { type LayoutValidator, type ValidationErrorHandler } from './validation';
/**
* Type for component registry
*/
interface ContentComponent {
component: Component<any>;
defaultProps?: Record<string, any>;
}
/**
* Type for state change callback
*/
export type StateChangeCallback = (state: Record<string, TileState>) => void;
/**
* Type for setup callback
*/
export type SetupCallback = (result: {
didResetToDefaultLayout: boolean;
}) => void;
/**
* Options for creating a ttabs instance
*/
export interface TtabsOptions {
/**
* Initial tiles state (optional)
* If provided, the instance will be initialized with these tiles
* If not provided, a default root grid will be created
*/
tiles?: Record<string, TileState> | TileState[];
/**
* Initially focused tab (optional)
* If provided, this tab will be set as the focused active tab
*/
focusedTab?: string;
/**
* Theme configuration (optional)
* If not provided, the default theme will be used
*/
theme?: TtabsTheme;
/**
* Custom validators to add to the validation middleware (optional)
* These will be run after the default validator
*/
validators?: LayoutValidator[];
/**
* Component ID to render when the grid/column/panel is empty
*/
defaultComponentIdForEmptyTiles?: string;
/**
* Function to create a default layout when validation fails (optional)
* If not provided, a minimal valid layout will be created
*/
defaultLayoutCreator?: (ttabs: TTabs) => void;
setupFromScratch?: SetupCallback;
}
/**
* Ttabs class implementation
*/
export declare class TTabs {
tiles: Record<string, TileState>;
activePanel: string | null;
focusedActiveTab: string | null;
rootGridId: string;
componentRegistry: Record<string, ContentComponent>;
theme: TtabsTheme;
stateChangeListeners: StateChangeCallback[];
debouncedStateChangeListeners: StateChangeCallback[];
pendingNotification: number | null;
pendingStateChanges: boolean;
defaultComponentIdForEmptyTiles?: string;
private validationMiddleware;
private setupFromScratchCallback?;
/**
* Find the root grid ID from the current tiles
* @returns The ID of the root grid
* @throws Error if no root grid is found
* @private
*/
private findRootGridId;
constructor(options?: TtabsOptions);
/**
* Subscribe to state changes
* @param callback Function to call when state changes
* @returns Unsubscribe function
*/
subscribe(callback: StateChangeCallback): () => void;
/**
* Subscribe to state changes with debouncing (calls at the end of the frame)
* @param callback Function to call when state changes
* @returns Unsubscribe function
*/
subscribeDebounced(callback: StateChangeCallback): () => void;
/**
* Notify all subscribers of state change
*/
private notifyStateChange;
/**
* Register a component for content rendering
* @param componentId Unique identifier for the component
* @param component Svelte component to render
* @param defaultProps Optional default props for the component
*/
registerComponent(componentId: string, component: Component<any>, defaultProps?: Record<string, any>): void;
/**
* Get a registered component by ID
* @param componentId The component identifier
* @returns The component and its default props, or null if not found
*/
getContentComponent(componentId: string): ContentComponent | null;
/**
* Check if a component is registered
* @param componentId The component identifier
* @returns True if the component is registered
*/
hasContentComponent(componentId: string): boolean;
/**
* Set component to a column or a tab
* @param parentId ID of the parent column or tab
* @param componentId ID of the registered component
* @param props Props to pass to the component
* @returns ID of the new content with component
*/
setComponent(parentId: string, componentId: string, props?: Record<string, any>): string;
/**
* Get all tiles
*/
getTiles(): Record<string, TileState>;
/**
* Get the active panel ID
*/
getActivePanel(): string | null;
/**
* Get a specific tile by ID with type casting
*/
getTile<T extends TileState = TileState>(id: string): T | null;
/**
* Get a grid by ID, throwing an error if not found
* @throws Error if the tile is not found or not a grid
*/
getGrid(id: string): TileGridState;
/**
* Get a row by ID, throwing an error if not found
* @throws Error if the tile is not found or not a row
*/
getRow(id: string): TileRowState;
/**
* Get a column by ID, throwing an error if not found
* @throws Error if the tile is not found or not a column
*/
getColumn(id: string): TileColumnState;
/**
* Get a panel by ID, throwing an error if not found
* @throws Error if the tile is not found or not a panel
*/
getPanel(id: string): TilePanelState;
/**
* Get a tab by ID, throwing an error if not found
* @throws Error if the tile is not found or not a tab
*/
getTab(id: string): TileTabState;
/**
* Get children of a tile filtered by type
*/
getChildren(parentId: string, tileType?: TileType | null): TileState[];
/**
* Get the currently active panel
*/
getActivePanelTile(): TilePanelState | null;
/**
* Get the active tab of the active panel
*/
getActivePanelTab(): TileTabState | null;
/**
* Get the content associated with a tab
*/
getTabContent(tabId: string): TileContentState | null;
/**
* Add a new tile to the layout
* @param tile Tile to add (requires type property)
* @returns ID of the new tile
*/
addTile<T extends TileState>(tile: Partial<T> & {
type: T['type'];
}): string;
/**
* Update a tile with the given changes
* @param id ID of the tile to update
* @param updates Changes to apply
* @returns True if successful
*/
updateTile<T extends TileState>(id: string, updates: Partial<T>): boolean;
/**
* Find all tiles that reference the specified tile
* @param tileId ID of the tile to find references to
* @returns Array of tiles that reference the specified tile
*/
private findTilesReferencingTile;
/**
* Remove a tile from the layout
* @param id ID of the tile to remove
* @returns True if successful
*/
removeTile(id: string): boolean;
/**
* Set the active panel
*/
setActivePanel(id: string): boolean;
/**
* Set the active tab
*/
setActiveTab(tabId: string): boolean;
/**
* Set the focused active tab
* @param tabId ID of the tab to focus
* @returns True if successful
*/
setFocusedActiveTab(tabId: string): boolean;
/**
* Get the focused active tab
*/
getFocusedActiveTabTile(): TileTabState | null;
/**
* Reorder tabs within a panel
*/
reorderTabs(panelId: string, oldIndex: number, newIndex: number): boolean;
/**
* Move a tab from one panel to another
* @param tabId The tab to move
* @param targetPanelId The panel to move the tab to
* @param targetIndex Optional index where to insert the tab in the target panel
* @returns boolean True if the operation was successful
*/
moveTab(tabId: string, targetPanelId: string, targetIndex?: number): boolean;
/**
* Split a panel to create a new layout
* @param tabId The tab to move to the new panel
* @param targetPanelId The panel being split
* @param direction The direction to split ('top', 'right', 'bottom', 'left')
* @returns boolean True if the split operation was successful
*/
splitPanel(tabId: string, targetPanelId: string, direction: 'top' | 'right' | 'bottom' | 'left'): boolean;
/**
* Recursively checks and cleans up empty containers
* Traverses up the hierarchy to remove unnecessary container structures
*/
cleanupContainers(tileId: string): void;
/**
* Redistributes width from a removed column to its sibling columns
* @param removedColumnId ID of the column being removed
*/
redistributeWidths(removedColumn: TileColumnState): void;
/**
* Redistributes height from a removed row to its sibling rows
* @param removedRow The row being removed
*/
redistributeHeights(removedRow: TileRowState): void;
/**
* Reset the layout (but keeping the theme, components, etc.)
*/
/**
* Reset the layout (but keeping the theme, components, etc.)
*/
resetTiles(): void;
/**
* Validate the current layout
* @returns True if layout is valid, false otherwise
*/
validateLayout(): boolean;
/**
* Reset to the default layout
*/
resetToDefaultLayout(): void;
/**
* Add a custom validator to the validation middleware
* @param validator The validator to add
*/
addValidator(validator: LayoutValidator): void;
/**
* Set the default layout creator function
* @param creator Function that creates a default layout
*/
setDefaultLayoutCreator(creator: (ttabs: TTabs) => void): void;
/**
* Subscribe to layout validation errors
* @param handler Function to call when validation errors occur
* @returns Unsubscribe function
*/
onValidationError(handler: ValidationErrorHandler): () => void;
/**
* Adds a grid to the layout
* @param parentId Optional parent column ID
* @returns ID of the new grid
* @throws Error if parent hierarchy rules are violated
*/
addGrid(parentId?: string | null): string;
/**
* Adds a row to a grid
* @param parentId ID of the parent grid
* @param height Height of the row as a string (e.g., "100%", "260px")
* @returns ID of the new row
* @throws Error if parent hierarchy rules are violated
*/
addRow(parentId: string, height?: string): string;
/**
* Adds a column to a row
* @param parentId ID of the parent row
* @param width Width of the column as a string (e.g., "100%", "260px")
* @returns ID of the new column
* @throws Error if parent hierarchy rules are violated
*/
addColumn(parentId: string, width?: string): string;
/**
* Adds a panel to a column
* @param parentId ID of the parent column
* @returns ID of the new panel
* @throws Error if parent hierarchy rules are violated
*/
addPanel(parentId: string): string;
/**
* Adds a tab to a panel
* @param panelId ID of the parent panel
* @param name Name of the tab
* @param setActive Whether to set this tab as active
* @param isLazy Whether to add the tab as lazy
* @returns ID of the new tab
* @throws Error if parent hierarchy rules are violated
*/
private addTabToPanel;
/**
* Adds a tab to a panel. If the parent is a grid, it will be added to the first row and column of the grid.
* @param parentId ID of the parent container (grid, column, or panel)
* @param name Name of the tab
* @param setActive Whether to set this tab as active
* @param isLazy Whether to add the tab as lazy
* @returns ID of the new tab
*/
addTab(parentId: string, name: string, setActive?: boolean, isLazy?: boolean): string;
/**
* Finds an existing panel in a grid or creates a new one
* @param gridId ID of the grid
* @returns ID of a panel in the grid
*/
private findOrCreatePanelInGrid;
/**
* Ads a new tab in the active panel
* @param name Name of the tab
* @returns ID of the new tab, or null if no active panel exists
*/
addTabInActivePanel(name: string, setActive?: boolean, isLazy?: boolean): string | null;
/**
* Serialize the layout to JSON
*/
serializeLayout(): string;
/**
* Setup the ttabs instance with the given tiles
* This will validate the layout and reset to default if invalid
* @param tiles The tiles to set up
* @param options Optional settings for active panel and focused tab
*/
setup(tiles: TileState[], { activePanel, focusedActiveTab }?: {
activePanel?: string;
focusedActiveTab?: string;
}): void;
/**
* Setup the ttabs instance with the given tiles as a record
* @param tiles The tiles to set up as a record
* @param callback Optional callback that will be called when setup is complete with information about the result
*/
setupWithRecord(tiles: Record<string, TileState>): void;
/**
* Deserialize a layout from JSON
* @param json The JSON string to deserialize
* @param callback Optional callback that will be called when setup is complete with information about the result
* @returns True if deserialization was successful, false otherwise
*/
deserializeLayout(json: string): boolean;
/**
* Find and set a default focused tab when none is specified
* Used after deserializing older layouts
*/
private findAndSetDefaultFocusedTab;
/**
* Close a tab and remove it
* @param tabId The ID of the tab to close
* @returns True if successful
*/
closeTab(tabId: string): boolean;
/**
* Set or update the theme
*/
setTheme(theme: TtabsTheme): void;
/**
* Get all lazy tabs in a panel, grid, or across the entire layout
* @param containerId Optional ID of a panel or grid to search within. If not provided, searches all panels.
* @returns Array of lazy tab tiles
*/
getLazyTabs(containerId?: string): TileTabState[];
/**
* Recalculates the layout for a container and its children
* @param containerId ID of the container to recalculate
*/
recalculateLayout(containerId: string): void;
/**
* Gets the parent column of a tile
* @param tileId ID of the tile to find the parent column for
* @returns The parent column if found, or null if not found
*/
getParentColumn(tileId: string): TileColumnState | null;
/**
* Create a new grid or get the existing root grid as an object
* @returns A Grid object for the root grid
*/
newGrid(): Grid;
/**
* Get a grid object for an existing grid
* @param id ID of the grid
* @returns A Grid object
*/
getGridObject(id: string): Grid;
/**
* Get a row object for an existing row
* @param id ID of the row
* @returns A Row object
*/
getRowObject(id: string): Row;
/**
* Get a column object for an existing column
* @param id ID of the column
* @returns A Column object
*/
getColumnObject(id: string): Column;
/**
* Get a panel object for an existing panel
* @param id ID of the panel
* @returns A TtabsPanel object
*/
getPanelObject(id: string): Panel;
/**
* Get a tab object for an existing tab
* @param id ID of the tab
* @returns A Tab object
*/
getTabObject(id: string): Tab;
}
export {};