feat(workspace): split bulletpoint paragraph at cursor position on Enter
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 59s

This commit is contained in:
sandrodach committed 2026-10-27 21:17:12 +01:00
1 parent 5cf6b59377
commit fdbf691a8d
2 files changed
+26 -7

No files matched your search

@@ -55,7 +55,7 @@ export interface OutlinerBlockProps {
levelOffset?: number; levelOffset?: number;
onZoomBlock?: (blockId: string) => void; onZoomBlock?: (blockId: string) => void;
onUpdateBlock: (updated: DocumentBlock, immediate?: boolean) => void; onUpdateBlock: (updated: DocumentBlock, immediate?: boolean) => void;
onCreateBlockBelow: (afterBlockId: string, currentContent: string) => void; onCreateBlockBelow: (afterBlockId: string, newContent?: string) => void;
onDeleteBlock: (blockId: string, deleteSubtree?: boolean) => void; onDeleteBlock: (blockId: string, deleteSubtree?: boolean) => void;
onIndentBlock: (blockId: string, delta: 1 | -1) => void; onIndentBlock: (blockId: string, delta: 1 | -1) => void;
onNavigateFocus: (blockId: string, direction: 'up' | 'down') => void; onNavigateFocus: (blockId: string, direction: 'up' | 'down') => void;
@@ -366,7 +366,7 @@ export const OutlinerBlock: React.FC<OutlinerBlockProps> = ({
// 2. Enter (without Shift) -> If block is completely empty: // 2. Enter (without Shift) -> If block is completely empty:
// - If level > minLevel, outdent (Shift+Tab behaviour) // - If level > minLevel, outdent (Shift+Tab behaviour)
// - If already at minLevel and is the last block, do NOT create another empty block below // - If already at minLevel and is the last block, do NOT create another empty block below
// - Otherwise create new block below // - Otherwise split paragraph at cursor and create new block below
if (e.key === 'Enter' && !e.shiftKey && block.type !== 'code') { if (e.key === 'Enter' && !e.shiftKey && block.type !== 'code') {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@@ -385,8 +385,27 @@ export const OutlinerBlock: React.FC<OutlinerBlockProps> = ({
} }
} }
flushDebounce(localContent); const start = e.currentTarget.selectionStart ?? localContent.length;
onCreateBlockBelowRef.current(block.id, localContent); const end = e.currentTarget.selectionEnd ?? start;
let beforeText = localContent.slice(0, start);
let afterText = localContent.slice(end);
// Clean linebreaks at the split boundary if present
if (beforeText.endsWith('\r\n')) {
beforeText = beforeText.slice(0, -2);
} else if (beforeText.endsWith('\n')) {
beforeText = beforeText.slice(0, -1);
}
if (afterText.startsWith('\r\n')) {
afterText = afterText.slice(2);
} else if (afterText.startsWith('\n')) {
afterText = afterText.slice(1);
}
setLocalContent(beforeText);
localContentRef.current = beforeText;
flushDebounce(beforeText);
onCreateBlockBelowRef.current(block.id, afterText);
return; return;
} }
@@ -196,7 +196,7 @@ export const OutlinerTree = forwardRef<OutlinerTreeHandle, OutlinerTreeProps>(({
}, [blocks, levelOffset]); }, [blocks, levelOffset]);
const handleCreateBlockBelow = useCallback( const handleCreateBlockBelow = useCallback(
(afterBlockId: string, _currentContent: string) => { (afterBlockId: string, newContent: string = '') => {
if (!canEdit) return; if (!canEdit) return;
const idx = blocks.findIndex((b) => b.id === afterBlockId); const idx = blocks.findIndex((b) => b.id === afterBlockId);
const currentBlock = idx >= 0 ? blocks[idx] : null; const currentBlock = idx >= 0 ? blocks[idx] : null;
@@ -207,7 +207,7 @@ export const OutlinerTree = forwardRef<OutlinerTreeHandle, OutlinerTreeProps>(({
id: `blk_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`, id: `blk_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`,
documentId: docId, documentId: docId,
type: inheritedType, type: inheritedType,
content: '', content: newContent,
level, level,
checked: false, checked: false,
collapsed: false, collapsed: false,
@@ -464,7 +464,7 @@ export const OutlinerTree = forwardRef<OutlinerTreeHandle, OutlinerTreeProps>(({
} else { } else {
const lastBlock = blocks[blocks.length - 1]; const lastBlock = blocks[blocks.length - 1];
if (lastBlock.content && lastBlock.content.trim() !== '') { if (lastBlock.content && lastBlock.content.trim() !== '') {
handleCreateBlockBelow(lastBlock.id, lastBlock.content); handleCreateBlockBelow(lastBlock.id, '');
} else { } else {
focusBlockInput(lastBlock.id, 'end'); focusBlockInput(lastBlock.id, 'end');
} }