History

Stabilize composer editor callbacks

Cursor Agent committed 6 months ago

Commit 14ff38c1 parent 159f13c1 file · +43 −31Browse files

Unified · Split

apps/web/src/components/chat/ChatComposer.tsx+43−31
@@ -1635,43 +1635,49 @@ export const ChatComposer = memo( · 1634 unmodified lines
1635 // ------------------------------------------------------------------1635 // ------------------------------------------------------------------
1636 // Callbacks: command key1636 // Callbacks: command key
1637 // ------------------------------------------------------------------1637 // ------------------------------------------------------------------
1638 const onComposerCommandKey = (1638 const onComposerCommandKey = useCallback(
1639 key: "ArrowDown" | "ArrowUp" | "Enter" | "Tab",1639 (key: "ArrowDown" | "ArrowUp" | "Enter" | "Tab", event: KeyboardEvent) => {
1640 event: KeyboardEvent,1640 if (key === "Tab" && event.shiftKey) {
1641 ) => {1641 toggleInteractionMode();
1642 if (key === "Tab" && event.shiftKey) {
1643 toggleInteractionMode();
1644 return true;
1645 }
1646 const { trigger } = resolveActiveComposerTrigger();
1647 const menuIsActive = composerMenuOpenRef.current || trigger !== null;
1648 if (menuIsActive) {
1649 const currentItems = composerMenuItemsRef.current;
1650 const selectedItem = activeComposerMenuItemRef.current ?? currentItems[0];
1651 if (key === "ArrowDown" && currentItems.length > 0) {
1652 nudgeComposerMenuHighlight("ArrowDown");
1653 return true;1642 return true;
1654 }1643 }
1655 if (key === "ArrowUp" && currentItems.length > 0) {1644 const { trigger } = resolveActiveComposerTrigger();
1656 nudgeComposerMenuHighlight("ArrowUp");1645 const menuIsActive = composerMenuOpenRef.current || trigger !== null;
1657 return true;1646 if (menuIsActive) {
1647 const currentItems = composerMenuItemsRef.current;
1648 const selectedItem = activeComposerMenuItemRef.current ?? currentItems[0];
1649 if (key === "ArrowDown" && currentItems.length > 0) {
1650 nudgeComposerMenuHighlight("ArrowDown");
1651 return true;
1652 }
1653 if (key === "ArrowUp" && currentItems.length > 0) {
1654 nudgeComposerMenuHighlight("ArrowUp");
1655 return true;
1656 }
1657 if ((key === "Enter" || key === "Tab") && selectedItem) {
1658 onSelectComposerItem(selectedItem);
1659 return true;
1660 }
1658 }1661 }
1659 if ((key === "Enter" || key === "Tab") && selectedItem) {1662 if (key === "Enter" && !event.shiftKey) {
1660 onSelectComposerItem(selectedItem);1663 submitComposer();
1661 return true;1664 return true;
1662 }1665 }
1663 }1666 return false;
1664 if (key === "Enter" && !event.shiftKey) {1667 },
1665 submitComposer();1668 [
1666 return true;1669 nudgeComposerMenuHighlight,
1667 }1670 onSelectComposerItem,
1668 return false;1671 resolveActiveComposerTrigger,
1669 };1672 submitComposer,
1673 toggleInteractionMode,
1674 ],
1675 );
1670 1676
1671 // ------------------------------------------------------------------1677 // ------------------------------------------------------------------
1672 // Callbacks: images1678 // Callbacks: images
1673 // ------------------------------------------------------------------1679 // ------------------------------------------------------------------
1674 const addComposerImages = (files: File[]) => {1680 const addComposerImages = useCallback((files: File[]) => {
1675 if (!activeThreadId || files.length === 0) return;1681 if (!activeThreadId || files.length === 0) return;
1676 if (pendingUserInputs.length > 0) {1682 if (pendingUserInputs.length > 0) {
1677 toastManager.add({1683 toastManager.add({
@@ -1714,7 +1720,13 @@ export const ChatComposer = memo( · 36 unmodified lines
1714 addComposerImagesToDraft(nextImages);1720 addComposerImagesToDraft(nextImages);
1715 }1721 }
1716 setThreadError(activeThreadId, error);1722 setThreadError(activeThreadId, error);
1717 };1723 }, [
1724 activeThreadId,
1725 addComposerImage,
1726 addComposerImagesToDraft,
1727 pendingUserInputs.length,
1728 setThreadError,
1729 ]);
1718 1730
1719 const removeComposerImage = (imageId: string) => {1731 const removeComposerImage = (imageId: string) => {
1720 removeComposerImageFromDraft(imageId);1732 removeComposerImageFromDraft(imageId);
@@ -1723,14 +1735,14 @@ export const ChatComposer = memo( · 2 unmodified lines
1723 // ------------------------------------------------------------------1735 // ------------------------------------------------------------------
1724 // Callbacks: paste / drag1736 // Callbacks: paste / drag
1725 // ------------------------------------------------------------------1737 // ------------------------------------------------------------------
1726 const onComposerPaste = (event: React.ClipboardEvent<HTMLElement>) => {1738 const onComposerPaste = useCallback((event: React.ClipboardEvent<HTMLElement>) => {
1727 const files = Array.from(event.clipboardData.files);1739 const files = Array.from(event.clipboardData.files);
1728 if (files.length === 0) return;1740 if (files.length === 0) return;
1729 const imageFiles = files.filter((file) => file.type.startsWith("image/"));1741 const imageFiles = files.filter((file) => file.type.startsWith("image/"));
1730 if (imageFiles.length === 0) return;1742 if (imageFiles.length === 0) return;
1731 event.preventDefault();1743 event.preventDefault();
1732 addComposerImages(imageFiles);1744 addComposerImages(imageFiles);
1733 };1745 }, [addComposerImages]);
1734 1746
1735 const onComposerDragEnter = (event: React.DragEvent<HTMLDivElement>) => {1747 const onComposerDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
1736 if (!event.dataTransfer.types.includes("Files")) return;1748 if (!event.dataTransfer.types.includes("Files")) return;