workspace-ui-kit/components/primitives/InlineTextareaField.tsx
snc777 f6a781c47e initial commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-09 14:24:17 +09:00

55 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
/**
* InlineTextareaField — Pane 4 編集 UI の「複数行 textarea」プリミティブ。
*
* shadcn `<Textarea>` をラップし、Lab v3 で確定した規律で編集体験を統一する:
* - 常に `<Textarea>` 表示Type-direct、ADR-0014
* - `bg-card` で周囲bg-backgroundより明るく「手前」感を出す
* - `field-sizing: content`Tailwind v4 / shadcn v4 の textarea デフォルト)で内容に応じて自動リサイズ
* - 保存: blur で onSave 発火値が変わっていれば。Cmd+Enter で blur
* - キャンセル: Esc で defaultValue に戻して blur
*
* 雛形では「職務経歴」「志望動機」のような長文項目で再利用。
*/
import { Textarea } from "@/components/ui/textarea";
export type InlineTextareaFieldProps = {
/** 現在の値空文字で「未設定」placeholder 表示) */
value: string;
/** 値が変わって blur した時に呼ばれる */
onSave: (v: string) => void;
/** スクリーンリーダー向けラベル */
ariaLabel: string;
/** 空のときの placeholder。デフォルト "未設定" */
placeholder?: string;
};
export function InlineTextareaField({
value,
onSave,
ariaLabel,
placeholder,
}: InlineTextareaFieldProps) {
return (
<Textarea
defaultValue={value}
placeholder={placeholder ?? "未設定"}
aria-label={ariaLabel}
onBlur={(e) => {
if (e.target.value !== value) onSave(e.target.value);
}}
onKeyDown={(e) => {
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
(e.target as HTMLTextAreaElement).blur();
} else if (e.key === "Escape") {
(e.target as HTMLTextAreaElement).value = value;
(e.target as HTMLTextAreaElement).blur();
}
}}
className="min-h-24 bg-card leading-relaxed whitespace-pre-line"
/>
);
}