UNPKG

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
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 {};