Merge pull request #78 from RuoJi6/codex/fix-repeater-selection-copy

修复报文高亮选区与复制行号问题
This commit is contained in:
RuoJi6 authored and GitHub committed 2026-10-29 08:11:33 -07:00
commit cb1a00105a
2 files changed
+57 -7

No files matched your search

+1 -1
View File
@@ -185,7 +185,7 @@ export function HttpPacketSyntax({
className={cn("grid min-w-0", lineClassName, lineNumbers && "grid-cols-[2.25rem_minmax(0,1fr)]")}
>
{lineNumbers ? (
<span className="sticky left-0 self-stretch border-r bg-muted/20 px-1 text-right text-[11px] text-muted-foreground/50">
<span className="sticky left-0 self-stretch select-none border-r bg-muted/20 px-1 text-right text-[11px] text-muted-foreground/50">
{index + 1}
</span>
) : null}
@@ -10,6 +10,52 @@ import { HttpPacketSyntax } from "@/components/http-code-block";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";
function EditablePacket({
id,
value,
onChange,
onScroll,
}: {
id: string;
value: string;
onChange: (value: string) => void;
onScroll: React.UIEventHandler<HTMLDivElement>;
}) {
const editor = React.useRef<HTMLDivElement>(null);
const lastValue = React.useRef(value);
React.useEffect(() => {
if (!editor.current || lastValue.current === value) return;
if (editor.current.innerText !== value) {
editor.current.innerText = value;
}
lastValue.current = value;
}, [value]);
return (
<div
id={id}
ref={editor}
role="textbox"
aria-label="请求"
aria-multiline="true"
tabIndex={0}
contentEditable
suppressContentEditableWarning
spellCheck={false}
onInput={(event) => {
const next = event.currentTarget.innerText.replace(/\r\n?/g, "\n");
lastValue.current = next;
onChange(next);
}}
onScroll={onScroll}
className="h-full min-h-0 w-0 flex-1 overflow-auto whitespace-pre-wrap break-words rounded-none border-0 px-3 py-2 font-mono text-xs leading-5 outline-none md:text-xs"
>
<HttpPacketSyntax raw={value} lineNumbers={false} wrapLines />
</div>
);
}
export function RepeaterTextPane({
id,
label,
@@ -64,7 +110,7 @@ export function RepeaterTextPane({
{toolbar}
<CopyButton text={value} label={`复制${label}`} className={showClock ? "ml-0" : "ml-auto"} />
</div>
<div className="relative flex min-h-0 flex-1 overflow-hidden rounded border border-input focus-within:border-ring">
<div className="group relative flex min-h-0 flex-1 overflow-hidden rounded border border-input focus-within:border-ring">
<div
aria-hidden="true"
className="w-12 shrink-0 overflow-hidden border-r bg-muted/30 text-right text-muted-foreground"
@@ -73,7 +119,11 @@ export function RepeaterTextPane({
{numbers}
</pre>
</div>
<Textarea
{syntaxHighlight && onChange ? (
<EditablePacket id={id} value={value} onChange={onChange} onScroll={(event) => {
if (gutter.current) gutter.current.style.transform = `translateY(-${event.currentTarget.scrollTop}px)`;
}} />
) : <Textarea
id={id}
value={value}
onChange={(event) => onChange?.(event.target.value)}
@@ -94,15 +144,15 @@ export function RepeaterTextPane({
className={
"field-sizing-fixed relative z-10 h-full max-h-none min-h-0 w-0 flex-1 resize-none rounded-none border-0 px-3 py-2 font-mono text-xs leading-5 focus-visible:ring-0 md:text-xs" +
(syntaxHighlight
? " bg-transparent text-transparent caret-foreground selection:bg-primary/20 selection:text-transparent placeholder:text-muted-foreground"
? " bg-transparent text-transparent caret-foreground selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground group-focus-within:text-foreground"
: "")
}
/>
{syntaxHighlight ? (
/>}
{syntaxHighlight && !onChange ? (
<div
ref={syntax}
aria-hidden="true"
className="pointer-events-none absolute inset-y-0 right-0 left-12 overflow-hidden px-3 py-2 font-mono text-xs leading-5"
className="pointer-events-none absolute inset-y-0 right-0 left-12 overflow-hidden px-3 py-2 font-mono text-xs leading-5 group-focus-within:invisible"
>
<HttpPacketSyntax
raw={value}