[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled

This commit is contained in:
2026-09-13 18:24:01 +08:00
commit 3c72efcb7f
3255 changed files with 907009 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import React, { useEffect, useRef, useState } from 'react';
import { cn } from '../../lib/utils';
interface DebouncedTextareaProps
extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'value' | 'onChange'> {
value: string;
onCommit: (value: string) => void;
/** Fires on every keystroke before the debounced commit (e.g. live CSS preview). */
onDraftChange?: (value: string) => void;
debounceMs?: number;
}
/**
* Keeps typing responsive by holding draft text locally and committing upstream
* after a short pause — avoids re-rendering the full settings tree per keystroke.
*/
export const DebouncedTextarea: React.FC<DebouncedTextareaProps> = ({
value,
onCommit,
onDraftChange,
debounceMs = 300,
className,
...props
}) => {
const [draft, setDraft] = useState(value);
const draftRef = useRef(value);
const committedRef = useRef(value);
const commitTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const onCommitRef = useRef(onCommit);
const onDraftChangeRef = useRef(onDraftChange);
onCommitRef.current = onCommit;
onDraftChangeRef.current = onDraftChange;
draftRef.current = draft;
committedRef.current = value;
useEffect(() => {
setDraft(value);
}, [value]);
useEffect(() => {
return () => {
if (commitTimerRef.current) {
clearTimeout(commitTimerRef.current);
commitTimerRef.current = null;
}
if (draftRef.current !== committedRef.current) {
onCommitRef.current(draftRef.current);
}
};
}, []);
const scheduleCommit = (next: string) => {
if (commitTimerRef.current) clearTimeout(commitTimerRef.current);
commitTimerRef.current = setTimeout(() => {
commitTimerRef.current = null;
onCommitRef.current(next);
}, debounceMs);
};
return (
<textarea
{...props}
value={draft}
onChange={(e) => {
const next = e.target.value;
setDraft(next);
onDraftChangeRef.current?.(next);
scheduleCommit(next);
}}
onBlur={() => {
if (commitTimerRef.current) {
clearTimeout(commitTimerRef.current);
commitTimerRef.current = null;
}
if (draft !== value) {
onCommitRef.current(draft);
}
}}
className={cn(className)}
/>
);
};