refactor(web): extract list auto-completion logic into custom hook

- Create useListAutoCompletion hook to encapsulate list continuation logic
- Simplify handleEditorKeyDown in Editor component
- Improve code organization and testability
- Add comprehensive documentation for the hook
- Maintain all existing functionality for markdown lists

The handleEditorKeyDown function is now much cleaner, delegating
list auto-completion concerns to a dedicated, reusable hook.
This commit is contained in:
Claude 2025-11-08 16:55:22 +00:00
parent f11c355446
commit 7f8f0c753d
No known key found for this signature in database
2 changed files with 65 additions and 16 deletions

View File

@ -1,10 +1,10 @@
import { forwardRef, ReactNode, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
import { cn } from "@/lib/utils";
import { detectLastListItem, generateListContinuation } from "@/utils/markdown-list-detection";
import { Command } from "../types/command";
import CommandSuggestions from "./CommandSuggestions";
import TagSuggestions from "./TagSuggestions";
import { editorCommands } from "./commands";
import { useListAutoCompletion } from "./useListAutoCompletion";
export interface EditorRefActions {
getEditor: () => HTMLTextAreaElement | null;
@ -152,22 +152,14 @@ const Editor = forwardRef(function Editor(props: Props, ref: React.ForwardedRef<
updateEditorHeight();
}, []);
const handleEditorKeyDown = async (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (event.key === "Enter" && !isInIME) {
if (event.shiftKey || event.ctrlKey || event.metaKey || event.altKey) {
return;
}
const { handleEnterKey } = useListAutoCompletion({
editorActions,
isInIME,
});
const cursorPosition = editorActions.getCursorPosition();
const prevContent = editorActions.getContent().substring(0, cursorPosition);
// Detect list item using regex-based detection
const listInfo = detectLastListItem(prevContent);
if (listInfo.type) {
event.preventDefault();
const insertText = "\n" + generateListContinuation(listInfo);
editorActions.insertText(insertText);
}
const handleEditorKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (event.key === "Enter") {
handleEnterKey(event);
}
};

View File

@ -0,0 +1,57 @@
import { useCallback } from "react";
import { detectLastListItem, generateListContinuation } from "@/utils/markdown-list-detection";
import { EditorRefActions } from ".";
interface UseListAutoCompletionOptions {
editorActions: EditorRefActions;
isInIME: boolean;
}
/**
* Custom hook for handling markdown list auto-completion.
* When the user presses Enter on a list item, this hook automatically
* continues the list with the appropriate formatting.
*
* Supports:
* - Ordered lists (1. item, 2. item, etc.)
* - Unordered lists (- item, * item, + item)
* - Task lists (- [ ] task, - [x] task)
* - Nested lists with proper indentation
*/
export function useListAutoCompletion({ editorActions, isInIME }: UseListAutoCompletionOptions) {
/**
* Handles the Enter key press to auto-complete list items.
* Returns true if the event was handled, false otherwise.
*/
const handleEnterKey = useCallback(
(event: React.KeyboardEvent<HTMLTextAreaElement>): boolean => {
// Don't handle if in IME composition (for Asian languages)
if (isInIME) {
return false;
}
// Don't handle if modifier keys are pressed (user wants manual control)
if (event.shiftKey || event.ctrlKey || event.metaKey || event.altKey) {
return false;
}
const cursorPosition = editorActions.getCursorPosition();
const contentBeforeCursor = editorActions.getContent().substring(0, cursorPosition);
// Detect if we're on a list item
const listInfo = detectLastListItem(contentBeforeCursor);
if (listInfo.type) {
event.preventDefault();
const continuation = generateListContinuation(listInfo);
editorActions.insertText("\n" + continuation);
return true;
}
return false;
},
[editorActions, isInIME],
);
return { handleEnterKey };
}