| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 |
- "use client";
- import { useMemo, useState } from "react";
- import { ChevronRight } from "lucide-react";
- import { RichText } from "@/components/ui/RichText";
- import { ValueView } from "@/components/ui/ValueView";
- interface Props {
- value: unknown;
- label?: string;
- threshold?: number;
- previewLength?: number;
- className?: string;
- }
- export function LongValueDisclosure({ value, label = "完整内容", threshold = 800, previewLength = 240, className = "" }: Props) {
- const text = useMemo(() => printable(value), [value]);
- const characters = useMemo(() => Array.from(text), [text]);
- const isLong = characters.length > threshold || (Array.isArray(value) && value.length > 5);
- const [open, setOpen] = useState(false);
- if (!isLong) return <ReadableValue value={value} />;
- return <details className={`comparisonLongValue ${className}`} onToggle={(event) => setOpen(event.currentTarget.open)}>
- <summary aria-label={`${open ? "收起" : "展开"}${label}`}>
- <span className="comparisonDisclosureTitle"><ChevronRight aria-hidden="true" size={15} /><strong>{label}</strong></span>
- <small>{characters.length.toLocaleString()} 字符</small>
- {!open ? <span className="comparisonDisclosurePreview">{preview(value, text, previewLength)}</span> : null}
- </summary>
- {open ? <div className="comparisonDisclosureBody"><ReadableValue value={value} /></div> : null}
- </details>;
- }
- export function ReadableValue({ value }: { value: unknown }) {
- if (typeof value === "string") return <RichText value={value || "(空)"} className="comparisonReadableText" />;
- if (value === null || value === undefined || value === "") return <p className="comparisonEmptyValue">(空)</p>;
- return <ValueView value={value} />;
- }
- function printable(value: unknown) {
- if (typeof value === "string") return value;
- if (value === undefined) return "";
- try { return JSON.stringify(value, null, 2) || ""; } catch { return String(value); }
- }
- function preview(value: unknown, text: string, previewLength: number) {
- if (Array.isArray(value) && value.length > 5) {
- const first = printable(value.slice(0, 3));
- return `${first}\n…还有 ${value.length - 3} 项`;
- }
- const characters = Array.from(text);
- return `${characters.slice(0, previewLength).join("")}${characters.length > previewLength ? "…" : ""}`;
- }
|