feat: Add WYSIWYG editor components and utilities
- Implemented WysiwygModalManager for managing modals related to code blocks and block settings. - Created WysiwygSelection for handling text selection across Shadow DOM boundaries. - Introduced WysiwygShortcuts for managing keyboard shortcuts and slash menu items. - Developed wysiwygStyles for consistent styling of the WYSIWYG editor. - Defined types for blocks, slash menu items, and shortcut patterns in wysiwyg.types.ts.
This commit is contained in:
89
ts_web/elements/dees-input-wysiwyg/wysiwyg.interfaces.ts
Normal file
89
ts_web/elements/dees-input-wysiwyg/wysiwyg.interfaces.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { type TemplateResult } from '@design.estate/dees-element';
|
||||
import { type IBlock } from './wysiwyg.types.js';
|
||||
import { DeesSlashMenu } from './dees-slash-menu.js';
|
||||
import { DeesFormattingMenu } from './dees-formatting-menu.js';
|
||||
|
||||
/**
|
||||
* Interface for the main wysiwyg component
|
||||
*/
|
||||
export interface IWysiwygComponent {
|
||||
// State
|
||||
blocks: IBlock[];
|
||||
selectedBlockId: string | null;
|
||||
shadowRoot: ShadowRoot | null;
|
||||
editorContentRef: HTMLDivElement;
|
||||
draggedBlockId: string | null;
|
||||
dragOverBlockId: string | null;
|
||||
dragOverPosition: 'before' | 'after' | null;
|
||||
isComposing: boolean;
|
||||
|
||||
// Menus
|
||||
slashMenu: DeesSlashMenu;
|
||||
formattingMenu: DeesFormattingMenu;
|
||||
|
||||
// Methods
|
||||
updateValue(): void;
|
||||
requestUpdate(): void;
|
||||
updateComplete: Promise<boolean>;
|
||||
insertBlock(type: string): Promise<void>;
|
||||
closeSlashMenu(clearSlash?: boolean): void;
|
||||
applyFormat(command: string): Promise<void>;
|
||||
handleSlashMenuKeyboard(e: KeyboardEvent): void;
|
||||
createBlockElement(block: IBlock): HTMLElement;
|
||||
updateBlockElement(blockId: string): void;
|
||||
handleDrop(e: DragEvent, targetBlock: IBlock): void;
|
||||
renderBlocksProgrammatically(): void;
|
||||
saveToHistory(debounce?: boolean): void;
|
||||
|
||||
// Handlers
|
||||
blockOperations: IBlockOperations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for block operations
|
||||
*/
|
||||
export interface IBlockOperations {
|
||||
createBlock(type?: IBlock['type'], content?: string, metadata?: any): IBlock;
|
||||
insertBlockAfter(afterBlock: IBlock, newBlock: IBlock, focusNewBlock?: boolean): Promise<void>;
|
||||
removeBlock(blockId: string): void;
|
||||
findBlock(blockId: string): IBlock | undefined;
|
||||
getBlockIndex(blockId: string): number;
|
||||
focusBlock(blockId: string, cursorPosition?: 'start' | 'end' | number): Promise<void>;
|
||||
updateBlockContent(blockId: string, content: string): void;
|
||||
transformBlock(blockId: string, newType: IBlock['type'], metadata?: any): void;
|
||||
moveBlock(blockId: string, targetIndex: number): void;
|
||||
getPreviousBlock(blockId: string): IBlock | null;
|
||||
getNextBlock(blockId: string): IBlock | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for block component
|
||||
*/
|
||||
export interface IWysiwygBlockComponent {
|
||||
block: IBlock;
|
||||
isSelected: boolean;
|
||||
blockElement: HTMLDivElement | null;
|
||||
|
||||
focus(): void;
|
||||
focusWithCursor(position: 'start' | 'end' | number): void;
|
||||
getContent(): string;
|
||||
setContent(content: string): void;
|
||||
setCursorToStart(): void;
|
||||
setCursorToEnd(): void;
|
||||
focusListItem(): void;
|
||||
getSplitContent(splitPosition: number): { before: string; after: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler interfaces
|
||||
*/
|
||||
export interface IBlockEventHandlers {
|
||||
onInput: (e: InputEvent) => void;
|
||||
onKeyDown: (e: KeyboardEvent) => void;
|
||||
onFocus: () => void;
|
||||
onBlur: () => void;
|
||||
onCompositionStart: () => void;
|
||||
onCompositionEnd: () => void;
|
||||
onMouseUp?: (e: MouseEvent) => void;
|
||||
onRequestUpdate?: () => void; // Request immediate re-render of the block
|
||||
}
|
Reference in New Issue
Block a user