UNPKG

@assistant-ui/react

Version:

Typescript/React library for AI Chat

115 lines (114 loc) 3.92 kB
"use client"; // src/primitives/composer/ComposerInput.tsx import { composeEventHandlers } from "@radix-ui/primitive"; import { useComposedRefs } from "@radix-ui/react-compose-refs"; import { Slot } from "@radix-ui/react-slot"; import { forwardRef, useCallback, useEffect, useRef } from "react"; import TextareaAutosize from "react-textarea-autosize"; import { useComposer, useComposerRuntime } from "../../context/react/ComposerContext.mjs"; import { useThread, useThreadRuntime } from "../../context/react/ThreadContext.mjs"; import { useEscapeKeydown } from "@radix-ui/react-use-escape-keydown"; import { useOnScrollToBottom } from "../../utils/hooks/useOnScrollToBottom.mjs"; import { useThreadListItemRuntime } from "../../context/react/ThreadListItemContext.mjs"; import { jsx } from "react/jsx-runtime"; var ComposerPrimitiveInput = forwardRef( ({ autoFocus = false, asChild, disabled: disabledProp, onChange, onKeyDown, submitOnEnter = true, cancelOnEscape = true, unstable_focusOnRunStart = true, unstable_focusOnScrollToBottom = true, unstable_focusOnThreadSwitched = true, ...rest }, forwardedRef) => { const threadListItemRuntime = useThreadListItemRuntime(); const threadRuntime = useThreadRuntime(); const composerRuntime = useComposerRuntime(); const value = useComposer((c) => { if (!c.isEditing) return ""; return c.text; }); const Component = asChild ? Slot : TextareaAutosize; const isDisabled = useThread((t) => t.isDisabled) ?? disabledProp ?? false; const textareaRef = useRef(null); const ref = useComposedRefs(forwardedRef, textareaRef); useEscapeKeydown((e) => { if (!cancelOnEscape) return; if (composerRuntime.getState().canCancel) { composerRuntime.cancel(); e.preventDefault(); } }); const handleKeyPress = (e) => { if (isDisabled || !submitOnEnter) return; if (e.nativeEvent.isComposing) return; if (e.key === "Enter" && e.shiftKey === false) { const { isRunning } = threadRuntime.getState(); if (!isRunning) { e.preventDefault(); textareaRef.current?.closest("form")?.requestSubmit(); } } }; const autoFocusEnabled = autoFocus && !isDisabled; const focus = useCallback(() => { const textarea = textareaRef.current; if (!textarea || !autoFocusEnabled) return; textarea.focus({ preventScroll: true }); textarea.setSelectionRange(textarea.value.length, textarea.value.length); }, [autoFocusEnabled]); useEffect(() => focus(), [focus]); useOnScrollToBottom(() => { if (composerRuntime.type === "thread" && unstable_focusOnScrollToBottom) { focus(); } }); useEffect(() => { if (composerRuntime.type !== "thread" || !unstable_focusOnRunStart) return void 0; return threadRuntime.unstable_on("run-start", focus); }, [unstable_focusOnRunStart, focus, composerRuntime, threadRuntime]); useEffect(() => { if (composerRuntime.type !== "thread" || !unstable_focusOnThreadSwitched) return void 0; return threadListItemRuntime.unstable_on("switched-to", focus); }, [ unstable_focusOnThreadSwitched, focus, composerRuntime, threadListItemRuntime ]); return /* @__PURE__ */ jsx( Component, { name: "input", value, ...rest, ref, disabled: isDisabled, onChange: composeEventHandlers(onChange, (e) => { if (!composerRuntime.getState().isEditing) return; return composerRuntime.setText(e.target.value); }), onKeyDown: composeEventHandlers(onKeyDown, handleKeyPress) } ); } ); ComposerPrimitiveInput.displayName = "ComposerPrimitive.Input"; export { ComposerPrimitiveInput }; //# sourceMappingURL=ComposerInput.mjs.map