feat(web): improve list auto-completion and tag insertion UX

Two user experience improvements based on feedback:

1. **GitHub-style empty list item handling:**
   - When pressing Enter on an empty list item (e.g., just "- "), remove
     the list marker instead of continuing the list
   - Matches GitHub's behavior for exiting list mode
   - Works for all list types: unordered (-, *, +), ordered (1., 2.),
     and task lists (- [ ])
   - Makes it easier to exit list mode without manual deletion

2. **Auto-space after tag selection:**
   - When selecting a tag from suggestions, automatically add a trailing
     space after the tag
   - Improves typing flow - users can immediately continue typing
   - Matches common expectation for autocomplete behavior

These changes make the editor feel more intuitive and reduce friction
during content creation.
This commit is contained in:
Claude 2025-11-08 17:16:06 +00:00
parent e8b0273473
commit ff745bfebe
No known key found for this signature in database
2 changed files with 24 additions and 4 deletions

View File

@ -43,9 +43,9 @@ const TagSuggestions = observer(({ editorRef, editorActions }: TagSuggestionsPro
return items.filter((tag) => tag.toLowerCase().includes(searchQuery));
},
onAutocomplete: (tag, word, index, actions) => {
// Replace the trigger word with the complete tag
// Replace the trigger word with the complete tag and add a trailing space
actions.removeText(index, word.length);
actions.insertText(`#${tag}`);
actions.insertText(`#${tag} `);
},
});

View File

@ -52,8 +52,28 @@ export function useListAutoCompletion({ editorRef, editorActions, isInIME }: Use
if (listInfo.type) {
event.preventDefault();
const continuation = generateListContinuation(listInfo);
actions.insertText("\n" + continuation);
// Check if current list item is empty (GitHub-style behavior)
// Extract the current line
const lines = contentBeforeCursor.split("\n");
const currentLine = lines[lines.length - 1];
// Check if line only contains list marker (no content after it)
const isEmptyListItem =
/^(\s*)([-*+])\s*$/.test(currentLine) || // Empty unordered list
/^(\s*)([-*+])\s+\[([ xX])\]\s*$/.test(currentLine) || // Empty task list
/^(\s*)(\d+)[.)]\s*$/.test(currentLine); // Empty ordered list
if (isEmptyListItem) {
// Remove the empty list marker and exit list mode
const lineStartPos = cursorPosition - currentLine.length;
actions.removeText(lineStartPos, currentLine.length);
actions.insertText("\n");
} else {
// Continue the list with the next item
const continuation = generateListContinuation(listInfo);
actions.insertText("\n" + continuation);
}
}
};