@@ -38,7 +38,12 @@ import { useLanguage } from "@/context/language"
3838import { usePlatform } from "@/context/platform"
3939import { createTextFragment , getCursorPosition , setCursorPosition , setRangeEdge } from "./prompt-input/editor-dom"
4040import { createPromptAttachments , ACCEPTED_FILE_TYPES } from "./prompt-input/attachments"
41- import { navigatePromptHistory , prependHistoryEntry , promptLength } from "./prompt-input/history"
41+ import {
42+ canNavigateHistoryAtCursor ,
43+ navigatePromptHistory ,
44+ prependHistoryEntry ,
45+ promptLength ,
46+ } from "./prompt-input/history"
4247import { createPromptSubmit } from "./prompt-input/submit"
4348import { PromptPopover , type AtOption , type SlashCommand } from "./prompt-input/slash-popover"
4449import { PromptContextItems } from "./prompt-input/context-items"
@@ -473,10 +478,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
473478 const prev = node . previousSibling
474479 const next = node . nextSibling
475480 const prevIsBr = prev ?. nodeType === Node . ELEMENT_NODE && ( prev as HTMLElement ) . tagName === "BR"
476- const nextIsBr = next ?. nodeType === Node . ELEMENT_NODE && ( next as HTMLElement ) . tagName === "BR"
477- if ( ! prevIsBr && ! nextIsBr ) return false
478- if ( nextIsBr && ! prevIsBr && prev ) return false
479- return true
481+ return ! ! prevIsBr && ! next
480482 }
481483 if ( node . nodeType !== Node . ELEMENT_NODE ) return false
482484 const el = node as HTMLElement
@@ -496,6 +498,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
496498 editorRef . appendChild ( createPill ( part ) )
497499 }
498500 }
501+
502+ const last = editorRef . lastChild
503+ if ( last ?. nodeType === Node . ELEMENT_NODE && ( last as HTMLElement ) . tagName === "BR" ) {
504+ editorRef . appendChild ( document . createTextNode ( "\u200B" ) )
505+ }
499506 }
500507
501508 createEffect (
@@ -729,7 +736,17 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
729736 }
730737 }
731738 if ( last . nodeType !== Node . TEXT_NODE ) {
732- range . setStartAfter ( last )
739+ const isBreak = last . nodeType === Node . ELEMENT_NODE && ( last as HTMLElement ) . tagName === "BR"
740+ const next = last . nextSibling
741+ const emptyText = next ?. nodeType === Node . TEXT_NODE && ( next . textContent ?? "" ) === ""
742+ if ( isBreak && ( ! next || emptyText ) ) {
743+ const placeholder = next && emptyText ? next : document . createTextNode ( "\u200B" )
744+ if ( ! next ) last . parentNode ?. insertBefore ( placeholder , null )
745+ placeholder . textContent = "\u200B"
746+ range . setStart ( placeholder , 0 )
747+ } else {
748+ range . setStartAfter ( last )
749+ }
733750 }
734751 }
735752 range . collapse ( true )
@@ -899,6 +916,8 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
899916 . current ( )
900917 . map ( ( part ) => ( "content" in part ? part . content : "" ) )
901918 . join ( "" )
919+ const direction = event . key === "ArrowUp" ? "up" : "down"
920+ if ( ! canNavigateHistoryAtCursor ( direction , textContent , cursorPosition ) ) return
902921 const isEmpty = textContent . trim ( ) === "" || textLength <= 1
903922 const hasNewlines = textContent . includes ( "\n" )
904923 const inHistory = store . historyIndex >= 0
@@ -907,7 +926,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
907926 const allowUp = isEmpty || atStart || ( ! hasNewlines && ! inHistory ) || ( inHistory && atEnd )
908927 const allowDown = isEmpty || atEnd || ( ! hasNewlines && ! inHistory ) || ( inHistory && atStart )
909928
910- if ( event . key === "ArrowUp " ) {
929+ if ( direction === "up " ) {
911930 if ( ! allowUp ) return
912931 if ( navigateHistory ( "up" ) ) {
913932 event . preventDefault ( )
0 commit comments