fix(prompt-input): 提供可选上下文入口并避免历史路由切换期异常
This commit is contained in:
1 parent
519e4c0c01
commit
9455160101
2 files changed
+21
-11
No files matched your search
@@ -60,7 +60,6 @@ import {
|
|||||||
createContext,
|
createContext,
|
||||||
type FormEvent,
|
type FormEvent,
|
||||||
type FormEventHandler,
|
type FormEventHandler,
|
||||||
Fragment,
|
|
||||||
type HTMLAttributes,
|
type HTMLAttributes,
|
||||||
type KeyboardEventHandler,
|
type KeyboardEventHandler,
|
||||||
type PropsWithChildren,
|
type PropsWithChildren,
|
||||||
@@ -124,8 +123,10 @@ export const usePromptInputController = () => {
|
|||||||
return ctx;
|
return ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Optional variants (do NOT throw). Useful for dual-mode components.
|
// Optional variants (do NOT throw). Useful for dual-mode components and for
|
||||||
const useOptionalPromptInputController = () =>
|
// Fast Refresh transitions where a page can briefly retain the previous
|
||||||
|
// provider context instance.
|
||||||
|
export const useOptionalPromptInputController = () =>
|
||||||
useContext(PromptInputController);
|
useContext(PromptInputController);
|
||||||
|
|
||||||
export const useProviderAttachments = () => {
|
export const useProviderAttachments = () => {
|
||||||
@@ -406,9 +407,9 @@ export function PromptInputAttachments({
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{attachments.files.map((file) => (
|
{attachments.files.map((file) => (
|
||||||
<Fragment key={file.id}>
|
<div key={file.id} className="max-w-60">
|
||||||
<div className="max-w-60">{children(file)}</div>
|
{children(file)}
|
||||||
</Fragment>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useParams, useSearchParams } from "next/navigation";
|
import { useParams, useSearchParams } from "next/navigation";
|
||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
|
|
||||||
import { usePromptInputController } from "@/components/ai-elements/prompt-input";
|
import { useOptionalPromptInputController } from "@/components/ai-elements/prompt-input";
|
||||||
import { useI18n } from "@/core/i18n/hooks";
|
import { useI18n } from "@/core/i18n/hooks";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,7 +11,11 @@ export function useSpecificChatMode() {
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { thread_id: threadIdFromPath } = useParams<{ thread_id: string }>();
|
const { thread_id: threadIdFromPath } = useParams<{ thread_id: string }>();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const promptInputController = usePromptInputController();
|
// A regular history item can navigate here while Vite Fast Refresh is
|
||||||
|
// reconciling the previous page tree. In that short window the page may see
|
||||||
|
// a stale provider context. This hook only pre-fills the skill-mode draft,
|
||||||
|
// so it must not make an ordinary chat page fail to render.
|
||||||
|
const promptInputController = useOptionalPromptInputController();
|
||||||
const inputInitialValue = useMemo(() => {
|
const inputInitialValue = useMemo(() => {
|
||||||
if (threadIdFromPath !== "new" || searchParams.get("mode") !== "skill") {
|
if (threadIdFromPath !== "new" || searchParams.get("mode") !== "skill") {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -19,8 +23,10 @@ export function useSpecificChatMode() {
|
|||||||
return t.inputBox.createSkillPrompt;
|
return t.inputBox.createSkillPrompt;
|
||||||
}, [threadIdFromPath, searchParams, t.inputBox.createSkillPrompt]);
|
}, [threadIdFromPath, searchParams, t.inputBox.createSkillPrompt]);
|
||||||
const lastInitialValueRef = useRef<string | undefined>(undefined);
|
const lastInitialValueRef = useRef<string | undefined>(undefined);
|
||||||
const setInputRef = useRef(promptInputController.textInput.setInput);
|
const setInputRef = useRef<((value: string) => void) | undefined>(
|
||||||
setInputRef.current = promptInputController.textInput.setInput;
|
promptInputController?.textInput.setInput,
|
||||||
|
);
|
||||||
|
setInputRef.current = promptInputController?.textInput.setInput;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
inputInitialValue &&
|
inputInitialValue &&
|
||||||
@@ -28,7 +34,10 @@ export function useSpecificChatMode() {
|
|||||||
) {
|
) {
|
||||||
lastInitialValueRef.current = inputInitialValue;
|
lastInitialValueRef.current = inputInitialValue;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setInputRef.current(inputInitialValue);
|
const setInput = setInputRef.current;
|
||||||
|
if (!setInput) return;
|
||||||
|
|
||||||
|
setInput(inputInitialValue);
|
||||||
const textarea = document.querySelector("textarea");
|
const textarea = document.querySelector("textarea");
|
||||||
if (textarea) {
|
if (textarea) {
|
||||||
textarea.focus();
|
textarea.focus();
|
||||||
|
|||||||
Reference in new issue
Block a user