UNPKG

@happy-table/vue3

Version:

A high-performance Vue 3 table component for B2B systems with TypeScript support

569 lines (568 loc) 31.4 kB
import { Ref, ComputedRef } from 'vue'; import { TableColumn, TableRow, TableModeConfig, CellPosition, CellRange, ExcelSelectionState, ExcelSelectionOptions } from '../../types'; import { ExcelModePlugin } from './plugins/ExcelModePlugin'; import { PluginContext, TableModePlugin } from './core/TableModePlugin'; /** * 表格模式管理的统一入口 * * 职责: * - 提供简化的表格模式管理API * - 处理模式切换和插件生命周期 * - 提供向后兼容的接口 * * 遵循原则: * - Facade Pattern: 为复杂的插件系统提供简单接口 * - Single Responsibility: 只负责模式管理的高层协调 * - Composition over Inheritance: 组合插件管理器而非继承 * * 架构改进: * - 从原来的混合式架构改为清晰的插件架构 * - 提供了扩展性和可维护性 * - 遵循开闭原则,支持新模式扩展 */ export declare function useTableMode(columns: Ref<TableColumn[]>, data: Ref<TableRow[]>, config: Ref<TableModeConfig>, container?: Ref<HTMLElement | null>): { isInitialized: Ref<boolean, boolean>; currentMode: Ref<string | null, string | null>; availableModes: ComputedRef<string[]>; activePlugins: ComputedRef<{ readonly config: { name: string; version: string; description?: string | undefined; dependencies?: string[] | undefined; priority?: number | undefined; }; initialize: (context: PluginContext) => void; activate: () => Promise<void>; deactivate: () => Promise<void>; destroy: () => Promise<void>; readonly isActive: boolean; readonly isDestroyed: boolean; handleKeydown: (event: KeyboardEvent) => boolean | Promise<boolean>; onActivate: () => Promise<void>; onDeactivate: () => Promise<void>; onDestroy: () => Promise<void>; handleKeyup?: ((_event: KeyboardEvent) => boolean | Promise<boolean>) | undefined; handleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleDoubleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseDown?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseUp?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseMove?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; onSelectionChange?: ((_selection: any) => void) | undefined; onActiveSelectionChange?: ((_position: CellPosition | null) => void) | undefined; onEditStart?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; onEditEnd?: ((_position: CellPosition, _value: any) => boolean | Promise<boolean>) | undefined; onEditCancel?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; getCellClasses?: ((_position: CellPosition) => string[]) | undefined; getCellStyles?: ((_position: CellPosition) => Record<string, string>) | undefined; getCellAttributes?: ((_position: CellPosition) => Record<string, any>) | undefined; }[]>; initialize: () => Promise<void>; switchToMode: (mode: string) => Promise<boolean>; getCurrentMode: () => string | null; isModeAvailable: (mode: string) => boolean; getAvailableModes: () => string[]; getPlugin: <T = any>(name: string) => T | null; getExcelPlugin: () => ExcelModePlugin | null; registerCustomPlugin: (plugin: any) => Promise<boolean>; handleKeyboardEvent: (type: "keydown" | "keyup", event: KeyboardEvent) => Promise<boolean>; handleMouseEvent: (type: "click" | "dblclick" | "mousedown" | "mouseup" | "mousemove", event: MouseEvent, position: any) => Promise<boolean>; getCellEnhancements: (position: any) => { classes: string[]; styles: Record<string, string>; attributes: Record<string, any>; }; isExcelMode: () => boolean; getExcelSelection: () => { selectionState: Readonly<Ref<{ readonly activeCell: { readonly rowIndex: number; readonly columnKey: string; } | null; readonly selectedRange: { readonly startRowIndex: number; readonly endRowIndex: number; readonly startColumnKey: string; readonly endColumnKey: string; } | null; readonly selectionType: "cell" | "row" | "column" | "range"; readonly isEditing: boolean; }, { readonly activeCell: { readonly rowIndex: number; readonly columnKey: string; } | null; readonly selectedRange: { readonly startRowIndex: number; readonly endRowIndex: number; readonly startColumnKey: string; readonly endColumnKey: string; } | null; readonly selectionType: "cell" | "row" | "column" | "range"; readonly isEditing: boolean; }>>; selectedCells: Readonly<Ref<ReadonlySet<string>, ReadonlySet<string>>>; selectedRows: Readonly<Ref<ReadonlySet<number>, ReadonlySet<number>>>; selectedColumns: Readonly<Ref<ReadonlySet<string>, ReadonlySet<string>>>; hasSelection: ComputedRef<boolean>; isRangeSelection: ComputedRef<boolean>; selectedCellCount: ComputedRef<number>; selectableColumns: ComputedRef<string[]>; selectCell: (position: any, extend?: boolean) => boolean; selectRow: (rowIndex: number, extend?: boolean) => boolean; selectColumn: (columnKey: string, extend?: boolean) => boolean; extendSelectionTo: (targetPosition: any) => boolean; clearSelection: () => void; isCellSelected: (position: CellPosition) => boolean; isRowSelected: (rowIndex: number) => boolean; isColumnSelected: (columnKey: string) => boolean; isActiveCell: (position: CellPosition) => boolean; isCellInRange: (position: CellPosition) => boolean; getSelectedCellPositions: () => CellPosition[]; getCellBorderPosition: (position: CellPosition) => { top: boolean; bottom: boolean; left: boolean; right: boolean; } | null; getActiveCell: () => CellPosition | null; getCurrentRange: () => CellRange | null; getSelectedRowIndices: () => number[]; getSelectedColumnKeys: () => string[]; activateCellEdit: (position: CellPosition) => boolean; deactivateCellEdit: () => void; batchSelection: { selectRows: (rowIndices: number[]) => boolean; selectColumns: (columnKeys: string[]) => boolean; }; selectionStats: { getCellCount: () => number; getRowCount: () => number; getColumnCount: () => number; getSelectionType: () => "row" | "column" | "range" | "cell"; isEmpty: () => boolean; }; onSelectionChange: (callback: (state: ExcelSelectionState) => void) => () => void; _internal: { store: { selectionState: Readonly<Ref<{ readonly activeCell: { readonly rowIndex: number; readonly columnKey: string; } | null; readonly selectedRange: { readonly startRowIndex: number; readonly endRowIndex: number; readonly startColumnKey: string; readonly endColumnKey: string; } | null; readonly selectionType: "cell" | "row" | "column" | "range"; readonly isEditing: boolean; }, { readonly activeCell: { readonly rowIndex: number; readonly columnKey: string; } | null; readonly selectedRange: { readonly startRowIndex: number; readonly endRowIndex: number; readonly startColumnKey: string; readonly endColumnKey: string; } | null; readonly selectionType: "cell" | "row" | "column" | "range"; readonly isEditing: boolean; }>>; selectedCells: Readonly<Ref<ReadonlySet<string>, ReadonlySet<string>>>; selectedRows: Readonly<Ref<ReadonlySet<number>, ReadonlySet<number>>>; selectedColumns: Readonly<Ref<ReadonlySet<string>, ReadonlySet<string>>>; selectableColumns: ComputedRef<string[]>; hasSelection: ComputedRef<boolean>; isRangeSelection: ComputedRef<boolean>; selectedCellCount: ComputedRef<number>; updateSelectionState: (newState: Partial< ExcelSelectionState>) => void; clearAllSelections: () => void; updateSelectedCells: (cells: Set<string>) => void; updateSelectedRows: (rows: Set<number>) => void; updateSelectedColumns: (columns: Set<string>) => void; onSelectionChange: (callback: (state: ExcelSelectionState) => void) => () => void; notifySelectionChange: () => void; _internal: { selectionStateRef: Ref<{ activeCell: { rowIndex: number; columnKey: string; } | null; selectedRange: { startRowIndex: number; endRowIndex: number; startColumnKey: string; endColumnKey: string; } | null; selectionType: "cell" | "row" | "column" | "range"; isEditing: boolean; }, ExcelSelectionState | { activeCell: { rowIndex: number; columnKey: string; } | null; selectedRange: { startRowIndex: number; endRowIndex: number; startColumnKey: string; endColumnKey: string; } | null; selectionType: "cell" | "row" | "column" | "range"; isEditing: boolean; }>; selectedCellsRef: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>; selectedRowsRef: Ref<Set<number> & Omit<Set<number>, keyof Set<any>>, Set<number> | (Set<number> & Omit<Set<number>, keyof Set<any>>)>; selectedColumnsRef: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>; dataRef: Ref<TableRow[], TableRow[]>; columnsRef: Ref<TableColumn[], TableColumn[]>; optionsRef: Ref< ExcelSelectionOptions, ExcelSelectionOptions>; }; }; modules: { cellSelection: { isValidPosition: (position: CellPosition) => boolean; getCellKey: (position: CellPosition) => string; isCellSelected: (position: CellPosition) => boolean; isActiveCell: (position: CellPosition) => boolean; getActiveCell: () => CellPosition | null; selectCell: (position: CellPosition) => boolean; activateCellEdit: (position: CellPosition) => boolean; deactivateCellEdit: () => void; }; rangeSelection: { isCellInRange: (position: CellPosition) => boolean; getCellBorderPosition: (position: CellPosition) => { top: boolean; bottom: boolean; left: boolean; right: boolean; } | null; getSelectedCellPositions: () => CellPosition[]; getCurrentRange: () => CellRange | null; calculateRange: (startPos: CellPosition, endPos: CellPosition) => CellRange | null; extendSelectionTo: (targetPosition: CellPosition) => boolean; selectRange: (startPos: CellPosition, endPos: CellPosition) => boolean; updateRangeSelectedCells: () => void; }; rowColumnSelection: { isRowSelected: (rowIndex: number) => boolean; isColumnSelected: (columnKey: string) => boolean; getSelectedRowIndices: () => number[]; getSelectedColumnKeys: () => string[]; selectRow: (rowIndex: number, extend?: boolean) => boolean; selectColumn: (columnKey: string, extend?: boolean) => boolean; addRowToSelection: (rowIndex: number) => boolean; removeRowFromSelection: (rowIndex: number) => boolean; addColumnToSelection: (columnKey: string) => boolean; removeColumnFromSelection: (columnKey: string) => boolean; }; selectionValidation: { validateActiveCell: () => void; validateSelectedRange: () => void; validateSelectedRows: () => void; validateSelectedColumns: () => void; validateAllSelections: () => void; recalculateSelectedCells: () => void; checkAndResetIfNeeded: () => void; }; }; }; } | null; getExcelKeyboard: () => { focusPosition: Ref<{ rowIndex: number; columnKey: string; } | null, CellPosition | { rowIndex: number; columnKey: string; } | null>; navigationActive: Ref<boolean, boolean>; selectionMode: Ref<boolean, boolean>; isEditing: Ref<boolean, boolean>; editingPosition: Ref<{ rowIndex: number; columnKey: string; } | null, CellPosition | { rowIndex: number; columnKey: string; } | null>; navigableColumns: ComputedRef<string[]>; totalRows: ComputedRef<number>; totalColumns: ComputedRef<number>; hasFocus: ComputedRef<boolean>; activateNavigation: () => void; deactivateNavigation: () => void; setFocusPosition: (position: any) => boolean; moveFocus: (direction: "up" | "down" | "left" | "right") => boolean; extendSelection: (direction: "up" | "down" | "left" | "right") => boolean; tabToNext: () => boolean; enterEditMode: (position?: any) => boolean; exitEditMode: () => void; scrollToCell: (position: any) => Promise<void>; handleKeydown: (event: KeyboardEvent) => Promise<void>; handleKeyup: (event: KeyboardEvent) => void; isValidPosition: (position: CellPosition) => boolean; isPositionEditing: (position: CellPosition) => boolean; jumpToPosition: (position: CellPosition) => boolean; moveToRowStart: () => CellPosition | null; moveToRowEnd: () => CellPosition | null; moveToColumnStart: () => CellPosition | null; moveToColumnEnd: () => CellPosition | null; cancelEdit: () => boolean; saveEdit: () => boolean; updateEditingValue: (value: any) => void; scrollByPosition: (position: CellPosition) => Promise<void>; checkCellVisibility: (position: CellPosition) => void; cleanup: () => void; _internal: { modules: { navigation: { focusPosition: Ref<{ rowIndex: number; columnKey: string; } | null, CellPosition | { rowIndex: number; columnKey: string; } | null>; navigationActive: Ref<boolean, boolean>; selectionMode: Ref<boolean, boolean>; navigableColumns: ComputedRef<string[]>; totalRows: ComputedRef<number>; totalColumns: ComputedRef<number>; hasFocus: ComputedRef<boolean>; isValidPosition: (position: CellPosition) => boolean; setFocusPosition: (position: CellPosition | null) => boolean; activateNavigation: () => void; deactivateNavigation: () => void; setSelectionMode: (isSelecting: boolean) => void; calculateNextPosition: (currentPosition: CellPosition, direction: "up" | "down" | "left" | "right") => CellPosition | null; moveFocus: (direction: "up" | "down" | "left" | "right") => CellPosition | null; jumpToPosition: (position: CellPosition) => boolean; moveToRowStart: () => CellPosition | null; moveToRowEnd: () => CellPosition | null; moveToColumnStart: () => CellPosition | null; moveToColumnEnd: () => CellPosition | null; tabToNext: () => CellPosition | null; tabToPrevious: () => CellPosition | null; }; scrollManager: { detectStickyHeaderHeight: () => number; getFixedColumnInfo: () => { leftWidth: number; rightWidth: number; hasLeftFixed: boolean; hasRightFixed: boolean; }; findCellElement: (position: CellPosition) => Element | null; scrollToCell: (position: CellPosition) => Promise<void>; ensureCellVisible: (position: CellPosition) => void; scrollByPosition: (position: CellPosition) => Promise<void>; cleanup: () => void; }; eventHandler: { handleKeydown: (event: KeyboardEvent, currentPosition: CellPosition | null) => Promise<boolean>; handleKeyup: (event: KeyboardEvent) => boolean; getEventHandlers: () => { handleKeydown: (event: KeyboardEvent, currentPosition: CellPosition | null) => Promise<boolean>; handleKeyup: (event: KeyboardEvent) => boolean; }; handleArrowKeys: (event: KeyboardEvent) => Promise<boolean>; handleTabKey: (event: KeyboardEvent) => Promise<boolean>; handleHomeEndKeys: (event: KeyboardEvent) => Promise<boolean>; handleEditKeys: (event: KeyboardEvent, currentPosition: CellPosition | null) => boolean; handleSelectionKeys: (event: KeyboardEvent) => boolean; handleCharacterInput: (event: KeyboardEvent, currentPosition: CellPosition | null) => boolean; }; editMode: { isEditing: Ref<boolean, boolean>; editingPosition: Ref<{ rowIndex: number; columnKey: string; } | null, CellPosition | { rowIndex: number; columnKey: string; } | null>; editingValue: Ref<any, any>; getIsEditing: () => boolean; getEditingPosition: () => CellPosition | null; isPositionEditing: (position: CellPosition) => boolean; enterEditMode: (position: CellPosition, initialValue?: any) => boolean; exitEditMode: (saveChanges?: boolean) => boolean; cancelEdit: () => boolean; saveEdit: () => boolean; updateEditingValue: (value: any) => void; forceExitEditMode: () => void; getCellValue: (position: CellPosition) => any; findEditableCell: (position: CellPosition) => Element | null; }; }; }; } | null; selectCell: (position: any, extend?: boolean) => boolean; selectRow: (rowIndex: number, extend?: boolean) => boolean; selectColumn: (columnKey: string, extend?: boolean) => boolean; clearSelection: () => void; getSelectionState: () => Readonly<Ref<{ readonly activeCell: { readonly rowIndex: number; readonly columnKey: string; } | null; readonly selectedRange: { readonly startRowIndex: number; readonly endRowIndex: number; readonly startColumnKey: string; readonly endColumnKey: string; } | null; readonly selectionType: "cell" | "row" | "column" | "range"; readonly isEditing: boolean; }, { readonly activeCell: { readonly rowIndex: number; readonly columnKey: string; } | null; readonly selectedRange: { readonly startRowIndex: number; readonly endRowIndex: number; readonly startColumnKey: string; readonly endColumnKey: string; } | null; readonly selectionType: "cell" | "row" | "column" | "range"; readonly isEditing: boolean; }>> | null; on: (event: string, handler: (...args: any[]) => void) => (() => void); emit: (event: string, ...args: any[]) => void; cleanup: () => Promise<void>; _internal: { modeManager: { registeredPlugins: Ref<Map<string, { readonly config: { name: string; version: string; description?: string | undefined; dependencies?: string[] | undefined; priority?: number | undefined; }; initialize: (context: PluginContext) => void; activate: () => Promise<void>; deactivate: () => Promise<void>; destroy: () => Promise<void>; readonly isActive: boolean; readonly isDestroyed: boolean; handleKeydown: (event: KeyboardEvent) => boolean | Promise<boolean>; onActivate: () => Promise<void>; onDeactivate: () => Promise<void>; onDestroy: () => Promise<void>; handleKeyup?: ((_event: KeyboardEvent) => boolean | Promise<boolean>) | undefined; handleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleDoubleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseDown?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseUp?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseMove?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; onSelectionChange?: ((_selection: any) => void) | undefined; onActiveSelectionChange?: ((_position: CellPosition | null) => void) | undefined; onEditStart?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; onEditEnd?: ((_position: CellPosition, _value: any) => boolean | Promise<boolean>) | undefined; onEditCancel?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; getCellClasses?: ((_position: CellPosition) => string[]) | undefined; getCellStyles?: ((_position: CellPosition) => Record<string, string>) | undefined; getCellAttributes?: ((_position: CellPosition) => Record<string, any>) | undefined; }> & Omit<Map<string, TableModePlugin>, keyof Map<any, any>>, Map<string, TableModePlugin> | (Map<string, { readonly config: { name: string; version: string; description?: string | undefined; dependencies?: string[] | undefined; priority?: number | undefined; }; initialize: (context: PluginContext) => void; activate: () => Promise<void>; deactivate: () => Promise<void>; destroy: () => Promise<void>; readonly isActive: boolean; readonly isDestroyed: boolean; handleKeydown: (event: KeyboardEvent) => boolean | Promise<boolean>; onActivate: () => Promise<void>; onDeactivate: () => Promise<void>; onDestroy: () => Promise<void>; handleKeyup?: ((_event: KeyboardEvent) => boolean | Promise<boolean>) | undefined; handleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleDoubleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseDown?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseUp?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseMove?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; onSelectionChange?: ((_selection: any) => void) | undefined; onActiveSelectionChange?: ((_position: CellPosition | null) => void) | undefined; onEditStart?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; onEditEnd?: ((_position: CellPosition, _value: any) => boolean | Promise<boolean>) | undefined; onEditCancel?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; getCellClasses?: ((_position: CellPosition) => string[]) | undefined; getCellStyles?: ((_position: CellPosition) => Record<string, string>) | undefined; getCellAttributes?: ((_position: CellPosition) => Record<string, any>) | undefined; }> & Omit<Map<string, TableModePlugin>, keyof Map<any, any>>)>; activePlugins: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>; currentMode: Ref<string | null, string | null>; availableModes: ComputedRef<string[]>; activePluginsList: ComputedRef<{ readonly config: { name: string; version: string; description?: string | undefined; dependencies?: string[] | undefined; priority?: number | undefined; }; initialize: (context: PluginContext) => void; activate: () => Promise<void>; deactivate: () => Promise<void>; destroy: () => Promise<void>; readonly isActive: boolean; readonly isDestroyed: boolean; handleKeydown: (event: KeyboardEvent) => boolean | Promise<boolean>; onActivate: () => Promise<void>; onDeactivate: () => Promise<void>; onDestroy: () => Promise<void>; handleKeyup?: ((_event: KeyboardEvent) => boolean | Promise<boolean>) | undefined; handleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleDoubleClick?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseDown?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseUp?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; handleMouseMove?: ((_event: MouseEvent, _position: CellPosition) => boolean | Promise<boolean>) | undefined; onSelectionChange?: ((_selection: any) => void) | undefined; onActiveSelectionChange?: ((_position: CellPosition | null) => void) | undefined; onEditStart?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; onEditEnd?: ((_position: CellPosition, _value: any) => boolean | Promise<boolean>) | undefined; onEditCancel?: ((_position: CellPosition) => boolean | Promise<boolean>) | undefined; getCellClasses?: ((_position: CellPosition) => string[]) | undefined; getCellStyles?: ((_position: CellPosition) => Record<string, string>) | undefined; getCellAttributes?: ((_position: CellPosition) => Record<string, any>) | undefined; }[]>; registerPlugin: (plugin: TableModePlugin) => Promise<boolean>; unregisterPlugin: (name: string) => Promise<boolean>; activatePlugin: (name: string) => Promise<boolean>; deactivatePlugin: (name: string) => Promise<boolean>; switchToMode: (modeName: string) => Promise<boolean>; emit: (event: string, ...args: any[]) => void; on: (event: string, handler: (...args: any[]) => void) => (() => void); dispatchKeyboardEvent: (type: "keydown" | "keyup", event: KeyboardEvent) => Promise<boolean>; dispatchMouseEvent: (type: "click" | "dblclick" | "mousedown" | "mouseup" | "mousemove", event: MouseEvent, position: CellPosition) => Promise<boolean>; collectRenderEnhancements: (position: CellPosition) => { classes: string[]; styles: Record<string, string>; attributes: Record<string, any>; }; findCell: (position: CellPosition) => Element | null; findRow: (rowIndex: number) => Element | null; findColumn: (columnKey: string) => Element | null; destroyAll: () => Promise<void>; _internal: { createPluginContext: () => PluginContext; eventBus: Map<string, Set<(...args: any[]) => void>>; }; }; pluginInstances: Map<string, any>; }; }; export type TableMode = ReturnType<typeof useTableMode>;