- Archive dormant apps (daemon, desktop, native, tui) and superseded packages/server into repos/ for reference - Archive 21 dead web components (chat page shell, work-os cluster, strays) into repos/web/; keep reused message-rendering primitives in components/chat - Merge @code/work-os into @code/primitives; work.ts absorbed via ./work subpath and barrel export; update all four importers - Add docs/futures.md tracking audio/video (blocked at Flue + provider), web layout cleanup, and message rendering quality - Repoint dev:zopu script to @code/agents (the live Flue server) - Note repos/ reference-code convention in AGENTS.md
59 lines
1.4 KiB
TypeScript
59 lines
1.4 KiB
TypeScript
import type { ChangeEvent, FormEvent, KeyboardEvent } from "react";
|
|
import { useRef, useState } from "react";
|
|
|
|
interface UseChatComposerOptions {
|
|
busy: boolean;
|
|
onSend: (message: string) => Promise<void>;
|
|
}
|
|
|
|
export const useChatComposer = ({ busy, onSend }: UseChatComposerOptions) => {
|
|
const [draft, setDraft] = useState("");
|
|
const [isFocused, setIsFocused] = useState(false);
|
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
const canSend = draft.trim().length > 0 && !busy;
|
|
|
|
const handleSubmit = async (event?: FormEvent) => {
|
|
event?.preventDefault();
|
|
const message = draft.trim();
|
|
if (!message || busy) {
|
|
return;
|
|
}
|
|
|
|
setDraft("");
|
|
try {
|
|
await onSend(message);
|
|
} finally {
|
|
textareaRef.current?.focus();
|
|
}
|
|
};
|
|
|
|
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
if (
|
|
event.key === "Enter" &&
|
|
!event.shiftKey &&
|
|
!event.nativeEvent.isComposing
|
|
) {
|
|
event.preventDefault();
|
|
void handleSubmit();
|
|
}
|
|
};
|
|
|
|
const inputProps = {
|
|
onBlur: () => setIsFocused(false),
|
|
onChange: (event: ChangeEvent<HTMLTextAreaElement>) =>
|
|
setDraft(event.target.value),
|
|
onFocus: () => setIsFocused(true),
|
|
onKeyDown: handleKeyDown,
|
|
ref: textareaRef,
|
|
value: draft,
|
|
};
|
|
|
|
return {
|
|
canSend,
|
|
draft,
|
|
handleSubmit,
|
|
inputProps,
|
|
isFocused,
|
|
};
|
|
};
|