فهرست منبع

fix(app): support bidi text input (#42413)

Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
opencode-agent[bot] 2 روز پیش
والد
کامیت
8f3e86cf4e

+ 6 - 1
packages/app/src/components/prompt-input.tsx

@@ -1518,6 +1518,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
               role="textbox"
               aria-multiline="true"
               aria-label={placeholder()}
+              dir={store.mode === "normal" ? "auto" : "ltr"}
               contenteditable="true"
               autocapitalize={store.mode === "normal" ? "sentences" : "off"}
               autocorrect={store.mode === "normal" ? "on" : "off"}
@@ -1539,7 +1540,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
                 "[&_[data-type=agent]]:text-syntax-type": true,
                 "font-mono!": store.mode === "shell",
               }}
-              style={{ "padding-bottom": space }}
+              style={{
+                "padding-bottom": space,
+                "unicode-bidi": store.mode === "normal" ? "plaintext" : undefined,
+                "text-align": "start",
+              }}
             />
             <div
               class="absolute top-0 inset-x-0 pl-3 pr-2 pt-2 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate"

+ 1 - 0
packages/app/src/components/titlebar-tab-nav.tsx

@@ -251,6 +251,7 @@ export function TabNavItem(props: {
           }}
           data-slot="tab-title"
           data-titlebar-tab-title
+          dir="auto"
           class="min-w-0 flex-1 outline-none leading-4"
           classList={{
             "overflow-hidden text-clip whitespace-nowrap": !editing(),

+ 5 - 1
packages/app/src/pages/session/composer/session-question-dock.tsx

@@ -601,7 +601,9 @@ export const SessionQuestionDock: Component<{ request: FormInfo; onSubmit: () =>
                 <Mark multi={multi()} picked={on()} onClick={toggleCustomMark} />
                 <span data-slot="question-option-main">
                   <span data-slot="option-label">{customLabel()}</span>
-                  <span data-slot="option-description">{input() || customPlaceholder()}</span>
+                  <span data-slot="option-description" dir="auto">
+                    {input() || customPlaceholder()}
+                  </span>
                 </span>
               </button>
             }
@@ -632,10 +634,12 @@ export const SessionQuestionDock: Component<{ request: FormInfo; onSubmit: () =>
                 <textarea
                   ref={focusCustom}
                   data-slot="question-custom-input"
+                  dir="auto"
                   placeholder={customPlaceholder()}
                   value={input()}
                   rows={1}
                   disabled={sending()}
+                  style={{ "unicode-bidi": "plaintext", "text-align": "start" }}
                   onKeyDown={(e) => {
                     if (e.key === "Escape") {
                       e.preventDefault()

+ 2 - 0
packages/app/src/pages/session/timeline/message-timeline.tsx

@@ -1159,6 +1159,7 @@ function MessageTimelineView(
                           titleRef = el
                         }}
                         data-slot="session-title-child"
+                        dir="auto"
                         value={title.draft}
                         disabled={props.pending.rename()}
                         classList={{
@@ -1170,6 +1171,7 @@ function MessageTimelineView(
                           "--inline-input-shadow": props.data.newLayoutDesigns()
                             ? "none"
                             : "var(--shadow-xs-border-select)",
+                          "text-align": "start",
                         }}
                         onInput={(event) => setTitle("draft", event.currentTarget.value)}
                         onKeyDown={(event) => {

+ 2 - 0
packages/session-ui/src/components/line-comment.tsx

@@ -296,9 +296,11 @@ export const LineCommentEditor = (props: LineCommentEditorProps) => {
             refs.textarea = el
           }}
           data-slot="line-comment-textarea"
+          dir="auto"
           rows={split.rows ?? 3}
           placeholder={split.placeholder ?? i18n.t("ui.lineComment.placeholder")}
           value={split.value}
+          style={{ "unicode-bidi": "plaintext", "text-align": "start" }}
           on:input={(e) => {
             const value = (e.currentTarget as HTMLTextAreaElement).value
             split.onInput(value)

+ 5 - 0
packages/session-ui/src/v2/components/prompt-input/index.tsx

@@ -154,6 +154,7 @@ export function PromptInputV2(props: PromptInputV2Props) {
             role="textbox"
             aria-multiline="true"
             aria-label={i18n.t("ui.promptInput.label")}
+            dir={state.mode === "normal" ? "auto" : "ltr"}
             contenteditable={!props.disabled && !props.readOnly}
             autocapitalize={state.mode === "normal" ? "sentences" : "off"}
             autocorrect={state.mode === "normal" ? "on" : "off"}
@@ -162,6 +163,10 @@ export function PromptInputV2(props: PromptInputV2Props) {
             autocomplete="off"
             class="relative z-10 block min-h-[60px] max-h-[180px] w-full overflow-y-auto whitespace-pre-wrap bg-transparent px-4 pt-4 pb-2 text-[13px] font-[440] leading-5 text-v2-text-text-base focus:outline-none empty:before:content-['\200B'] [&_[data-mention=file]]:text-syntax-property [&_[data-mention=agent]]:text-syntax-type [&_[data-mention=reference]]:text-syntax-keyword"
             classList={{ "font-mono!": state.mode === "shell", "opacity-50": props.disabled }}
+            style={{
+              "unicode-bidi": state.mode === "normal" ? "plaintext" : undefined,
+              "text-align": "start",
+            }}
             onInput={(event) => {
               const cursor = promptInputV2Cursor(event.currentTarget)
               const prompt = parsePromptInputV2Editor(event.currentTarget)

+ 2 - 0
packages/ui/src/v2/components/line-comment-v2.tsx

@@ -212,9 +212,11 @@ export function LineCommentEditorV2(props: LineCommentEditorV2Props) {
               textareaRef = el
             }}
             data-slot="line-comment-v2-textarea"
+            dir="auto"
             rows={local.rows ?? 3}
             placeholder={local.placeholder ?? i18n.t("ui.lineComment.contextPlaceholder")}
             value={local.value}
+            style={{ "unicode-bidi": "plaintext", "text-align": "start" }}
             onInput={(e) => {
               local.onInput(e.currentTarget.value)
               syncMention()