Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 124 lines 3.9 kB view raw
1/** 2 * Block Handle — Notion-style drag handle and context menu 3 * 4 * Pure logic module: handle state, context menu actions, and turn-into items. 5 * No DOM dependencies — rendering is handled in main.js. 6 */ 7import type { BlockHandlePosition, BlockHandleAction, TurnIntoItem, BlockHandleMode } from './types.js'; 8 9// ============================================================ 10// Icons 11// ============================================================ 12 13/** 6-dot grip icon for the drag handle */ 14export const BLOCK_HANDLE_ICON = '\u2807'; 15 16/** Plus icon for the add-block button */ 17export const BLOCK_HANDLE_ADD_ICON = '+'; 18 19// ============================================================ 20// Context Menu Actions 21// ============================================================ 22 23export const BLOCK_HANDLE_ACTIONS: BlockHandleAction[] = [ 24 { id: 'turnInto', label: 'Turn into...', icon: '\u21C4' }, 25 { id: 'delete', label: 'Delete', icon: '\uD83D\uDDD1' }, 26 { id: 'duplicate', label: 'Duplicate', icon: '\u2398' }, 27 { id: 'moveUp', label: 'Move up', icon: '\u2191' }, 28 { id: 'moveDown', label: 'Move down', icon: '\u2193' }, 29]; 30 31// ============================================================ 32// Turn Into Items (block type conversion targets) 33// ============================================================ 34 35export const TURN_INTO_ITEMS: TurnIntoItem[] = [ 36 { id: 'paragraph', name: 'Paragraph', icon: '\u00B6' }, 37 { id: 'heading1', name: 'Heading 1', icon: 'H1' }, 38 { id: 'heading2', name: 'Heading 2', icon: 'H2' }, 39 { id: 'heading3', name: 'Heading 3', icon: 'H3' }, 40 { id: 'bulletList', name: 'Bullet List', icon: '\u2022' }, 41 { id: 'numberedList', name: 'Numbered List', icon: '1.' }, 42 { id: 'taskList', name: 'Task List', icon: '\u2611' }, 43 { id: 'blockquote', name: 'Blockquote', icon: '\u201C' }, 44 { id: 'codeBlock', name: 'Code Block', icon: '</>' }, 45]; 46 47/** 48 * Filter turn-into items by a search query. 49 */ 50export function filterTurnIntoItems(query: string): TurnIntoItem[] { 51 const q = (query || '').trim().toLowerCase(); 52 if (!q) return [...TURN_INTO_ITEMS]; 53 return TURN_INTO_ITEMS.filter(item => item.name.toLowerCase().includes(q)); 54} 55 56// ============================================================ 57// Block Handle State 58// ============================================================ 59 60/** 61 * Manages the state of the block drag handle and its context menus. 62 * Pure state object — no DOM coupling. 63 */ 64export class BlockHandleState { 65 visible: boolean; 66 position: BlockHandlePosition | null; 67 blockPos: number | null; 68 contextMenuOpen: boolean; 69 turnIntoMenuOpen: boolean; 70 71 constructor() { 72 this.visible = false; 73 this.position = null; 74 this.blockPos = null; 75 this.contextMenuOpen = false; 76 this.turnIntoMenuOpen = false; 77 } 78 79 /** 80 * Show the handle at a position, associated with a block at the given 81 * ProseMirror document position. 82 */ 83 show(position: BlockHandlePosition, blockPos: number): void { 84 this.visible = true; 85 this.position = { ...position }; 86 this.blockPos = blockPos; 87 } 88 89 hide(): void { 90 this.visible = false; 91 this.position = null; 92 this.blockPos = null; 93 this.contextMenuOpen = false; 94 this.turnIntoMenuOpen = false; 95 } 96 97 updatePosition(position: BlockHandlePosition): void { 98 this.position = { ...position }; 99 } 100 101 openContextMenu(): void { 102 this.contextMenuOpen = true; 103 } 104 105 closeContextMenu(): void { 106 this.contextMenuOpen = false; 107 this.turnIntoMenuOpen = false; 108 } 109 110 openTurnIntoMenu(): void { 111 this.turnIntoMenuOpen = true; 112 } 113 114 closeTurnIntoMenu(): void { 115 this.turnIntoMenuOpen = false; 116 } 117 118 /** 119 * Determine if the handle should be hidden in a given mode. 120 */ 121 isHiddenInMode(mode: BlockHandleMode): boolean { 122 return mode === 'zen' || mode === 'print'; 123 } 124}