import { useLayoutEffect, useRef } from 'react'; import type { ProblemFramingPlan, ProblemFramingStep } from '../../../shared/types/api'; import { useI18n } from '../../../shared/i18n'; const DESIGN_FIELDS = ['audience', 'backgroundRules', 'selectedRoute', 'alternativeRoutes', 'outOfScope', 'specialCases', 'visualMotif', 'designerHint'] as const; // 稿纸语言:字段不带自己的框,静息时只是一行字;悬停与聚焦由底色承接。 // 独立块自带底色反馈,行内字段把反馈让给整行。 const blockField = 'w-full overflow-hidden rounded-lg bg-transparent px-2 py-1.5 text-sm leading-6 text-text-primary transition-colors duration-200 hover:bg-bg-tertiary/15 focus:bg-bg-tertiary/20 focus:outline-none disabled:opacity-60'; const rowField = 'w-full overflow-hidden bg-transparent text-text-primary focus:outline-none disabled:opacity-60'; /** 稿纸里没有固定行高的框:文本有几行,这一行就多高。 */ function GrowingTextarea({ label, value, disabled, className, onChange }: { label: string; value: string; disabled: boolean; className: string; onChange: (value: string) => void; }) { const ref = useRef(null); useLayoutEffect(() => { const el = ref.current; if (!el) return; const fit = () => { el.style.height = 'auto'; el.style.height = `${el.scrollHeight}px`; }; fit(); // 手写字体加载完成后行高会变,重算一次。 void document.fonts?.ready.then(fit); }, [value, disabled]); return