Files
HMDesign/docs/components/textarea.md
shkim4 4c29894e56 refactor(storybook): simplify component and preview examples
Drop page / section descriptions, state notes and repeated captions from
the representative Stories of 44 components, the Patterns, Center
Graphic and OrgChart pages. Value readouts, spec lists and captions hide
only on the representative page; hidden verification Stories keep them.
Tabs Default API and the Filter Bar draft / applied counts move to the
hidden DefaultApi and DraftApplied Stories; Center Overview is hidden
with its direct URL kept. Story IDs are unchanged.

Align the component, pattern and OrgChart docs with the pages, point the
quality reference check at the DraftApplied Story, and make the P8
styles check expect no section header on the preview-only Expanded page.
2026-10-23 00:28:05 +09:00

10 KiB

Textarea

현재 HM 구현의 기준 문서. 공통 원칙은 docs/guidelines/프로젝트-지침.md(§6, §7), Token 구조 원칙은 테마-토큰-가이드.md를 따른다. 이 문서는 Textarea 고유의 API·Token·상태·결정만 기록한다.

1. 상태

항목 내용
구현 상태 HM 스타일 적용 완료 (hm-textarea class 없음)
기준일 2026-10-02
기반 shadcn/ui Textarea (native <textarea>)
대표 Story Components/Form/Textarea → All (이름 "Textarea")
보류 아래 §11

2. 적용 근거

원본: 외부 ui_viz Reference (ZIP 미포함)의 docs/components/textarea.md (+ brand/hanmac/foundation/{color,border}.md, foundation/token-inventory.md의 입력 계열 Semantic).

  • ui_viz Confirmed: border 1px / radius 4px(§2, §2.2), 면·값·Placeholder 색(§2.2), 기본 테두리 color.stroke.input.default, Focus color.stroke.input.focus, Error color.stroke.input.error, Focus/Error 두께 1.5px(D-005 상속, §2.2), Hover = Default(§3.3 사용자 결정 TEXTAREA-05, Confirmed), Readonly 표현(§3.1), 값 typography 16/24/400(§2).
  • SCOPED_DESIGN_APPROVAL (2026-09-17 owner, Textarea 한정): min-height 112px, padding 8px 12px(§8.1, TEXTAREA-01/02). D-093 디자인 확정값이 아니며 ui_viz Canonical은 TBD다. Textarea 범위에서만 사용하고 size.*/space.*로 승격하지 않는다.
  • Component-local: resize 정책(vertical 기본, none/both 선택, Readonly는 none 고정).
  • shadcn 유지: native textarea 동작, transition-colors, outline-none, Disabled opacity와 커서.
  • HM 사용자 결정(2026-10-06): Error border와 Keyboard Focus ring을 독립 Semantic으로 표시한다.

3. 기본 규격

항목 값 상태
Width 부모 폭 100% (w-full) Canonical
Min-height 112px SCOPED_DESIGN_APPROVAL
Padding 8px (block) / 12px (inline) SCOPED_DESIGN_APPROVAL
Border / Radius 1px --hm-sem-stroke-input-default / --hm-radius-input(4px) Confirmed
Face / 값 색 --hm-sem-bg-surface / --hm-sem-fg-primary Confirmed
Typography 16 / 24 / 400 Existing role
Placeholder --hm-sem-fg-placeholder, opacity: 1 Confirmed
Resize vertical 기본 Component-local

Size 체계 없음. Input의 Small/Medium/Large와 공유하지 않는다(ui_viz Textarea에 size 정의 없음). field.gap 8px 등 Field 관계는 Textarea 밖(소비 조합)이다.

4. 상태 규격

상태 값 근거
Default 위 기본 규격 Confirmed
Hover Default와 동일 (hover rule 없음) Confirmed (사용자 결정 TEXTAREA-05)
Focus (:focus-visible) border 1.5px --hm-sem-stroke-input-focus, shadow/glow 없음, padding으로 0.5px 보정해 글자 위치 유지 Confirmed (D-005 상속)
Error ([aria-invalid="true"]) border 1.5px --hm-sem-action-destructive, ring 없음, 동일 padding 보정 Confirmed (D-005 상속)
Error + Keyboard Focus Destructive border 유지 + HM Focus Semantic 3px / 50% outer ring, outline: none Input과 동일, 2026-10-06 사용자 결정
Disabled surface face 유지, cursor: not-allowed, opacity: 0.6 opacity: 사용자 결정(§10)
Readonly ([readonly]) Default와 같은 면·테두리·typography, opacity: 1, resize: none 고정 Component-local (§3.1)

Chromium은 1.5px 테두리를 getComputedStyle 기준 1px로 계산한다(ui_viz도 같은 관측을 기록). padding 보정(7.5px/11.5px)은 선언 1.5px 기준으로 적용된다.

5. API

Textarea:
  resize?: "vertical" | "none" | "both"     기본 "vertical"
  • 나머지는 native <textarea> props 그대로(rows, placeholder, disabled, readOnly, aria-invalid 등).
  • 출력 속성: data-slot="textarea", data-resize.
  • 상태는 새 prop이 아니라 native 속성으로 준다.
  • Field(Label, Required 별표, Helper/Error 문구)는 Textarea에 포함하지 않는다. 소비 조합이다.
  • auto-grow, 글자 수 카운터는 범위 밖이다. shadcn의 field-sizing-content(auto-grow)는 제거했다.

6. Token

Component Mapping 위치: packages/ui/src/theme/textarea.css (--hm-textarea-*).

  • 재사용한 공통 Semantic: --hm-radius-input, --hm-sem-bg-surface, --hm-sem-fg-primary, --hm-sem-fg-placeholder, --hm-sem-stroke-input-default, --hm-sem-stroke-input-focus, --hm-sem-action-destructive(Semantic 참조).
  • Textarea 전용 값: --hm-textarea-min-height, --hm-textarea-padding-{block,inline}, --hm-textarea-font-{size,weight}, --hm-textarea-line-height, --hm-textarea-border-width, --hm-textarea-state-border-width(1.5px).
  • Primitive 신규 추가 없음.
  • Input의 --hm-input-*와 값이 겹쳐도 alias하지 않는다(ui_viz도 Input·Textarea를 별도 owner로 두고 값을 각각 소비).

7. shadcn / Radix에서 유지한 항목

native <textarea> 동작 전체, data-slot, cn(..., className), transition-colors, outline-none, disabled:cursor-not-allowed. Radix 사용 없음.

8. HM에서 변경한 항목

  • resize prop, data-resize 추가.
  • shadcn의 기본 min-height/padding/border/ring/shadow/dark:/field-sizing-content class 제거 → theme CSS가 담당.
  • 일반 Focus는 border 1.5px로 표시, Error 단독은 ring 없음. Error + :focus-visible만 독립 Focus ring을 표시한다.
  • Readonly 전용 표현(resize 고정) 추가.

9. Storybook

  • 대표 Story All("Textarea"): 구역 default, focus, error, error-message, readonly, disabled, multiline, resize. Focus는 play 함수로 실제 focus를 준다. Hover는 Default와 같아(TEXTAREA-05) 2026-10-22 대표 화면의 중복 hover 예시를 뺐다. 실제 포인터 확인은 Default 예시에서 한다.
  • verification(tags: ["verification"]): Default, Focus, Error, InvalidFocus, ErrorMessage, Required, Readonly, Disabled, LongContent, Playground(HM 전용).
  • Error Message·Required 표시는 Story 안의 조합 예시이며 Textarea 컴포넌트의 일부가 아니다.

10. 사용자 확정 결정

2026-10-02: Textarea Disabled opacity 0.6 확정. ui_viz에서 Temporary지만 현재 HM 구현에서는 이 결정이 우선한다. Textarea 한정이며 전역 Disabled opacity로 확대하지 않는다 (Input·Select와 같은 값). Token이 아니라 ui/textarea.tsx의 disabled:opacity-60으로 적용.

  • ui_viz에 기록된 결정을 따른다: 2026-09-17 Hover = Default(TEXTAREA-05), min-height 112 / padding 8·12 Textarea 한정 승인(TEXTAREA-01/02). 2026-10-01 필수 별표 #D32F2F(TEXTAREA-07, Textarea에 별표 없음 — Story 조합 예시는 shadcn text-destructive).

11. 미확정 / 보류

  • min-height 112 / padding 8·12: Textarea 한정 owner 승인이지만 ui_viz Canonical은 TBD, D-093 미확정(TEXTAREA-01/02/06, NO_SOURCE_EVIDENCE). 변경 가능성이 있다.
  • Label 14/20/500 · Value 16/24 · Error 11/18 vs D-093 원본 실행본 13/700 등: KNOWN_DEVIATION / FOLLOW_UP(TEXTAREA-08). 확정 근거 없어 ui_viz 문서값을 사용.
  • Error + Focus: HM 사용자 결정(2026-10-06)으로 Input과 같은 3px / 50% Focus Semantic ring을 적용한다.
  • auto-grow, 글자 수 카운터(TEXTAREA-03): 범위 밖. max length 관련 표현 없음.
  • 전역 focus ring 수치: TBD.

12. 관련 파일

packages/ui/src/components/ui/textarea.tsx
packages/ui/src/theme/textarea.css
packages/ui/src/theme.css            (import)
packages/ui/src/index.ts             (export Textarea, TextareaResize)
src/components/textarea.stories.tsx
src/components/story-board.tsx

13. 검증 상태

  • npm run typecheck(root + ui + center-graphic), npm run build: 통과(2026-10-02).
  • Storybook computed style(components-form-textarea--all): Default min-height 112px / padding 8px 12px / border 1px rgb(222,219,210) / radius 4px / bg white / 16·24·400 / resize vertical / Placeholder rgb(153,153,153), Error border rgb(211,47,47) + padding 7.5px 11.5px, Readonly resize none · opacity 1, resize="none" 적용, Disabled opacity 0.6.
  • 실제 클릭 focus: :focus-visible 매칭, border rgb(18,51,40), padding 7.5px 11.5px 확인.
  • Story ID: All + verification 8개 존재 확인(index.json). @hm-design/ui에서 import { Textarea }로 Story가 빌드됨.
  • 2026-10-06 ui_viz Storybook 화면 비교(1280/768/390, Chromium): 컨트롤 computed style 일치(ui_viz Story의 114px은 rows=4 때문), Error+Focus outline 유지, 긴 내용은 내부 세로 scroll·가로 넘침 없음, Readonly 편집 불가·선택 가능, Disabled focus 불가. ui_viz는 Disabled에서 Field 전체(라벨 포함)를 흐리지만 HM은 컨트롤만 흐리고 라벨은 Label의 disabled 연동(소비 조합)이 맡는다 — 의도적 차이. 대표 Story는 ui_viz 5구역을 모두 포함한 상위 집합(Hover = Default, Error Message, Resize none 추가)이라 변경하지 않음.
  • 미확인: 브라우저별 렌더(Chromium 외).

Invalid + Focus 검증 (2026-10-07)

  • Focus ring: --ring → --hm-sem-stroke-input-focus → --hm-color-border-focus. Invalid border: 기존 --hm-sem-action-destructive. 새 Runtime Role / Production Error prop / 메시지 컴포넌트 없음.
  • Chromium computed style: Invalid border rgb(211, 47, 47), Invalid + Keyboard Focus box-shadow color(srgb 0.14902 0.4 0.317647 / 0.5) 0px 0px 0px 3px, outline-style: none. Invalid 단독은 box-shadow: none.
  • Theme Designer UI에서 Focus #c75b00, Destructive #d41466, Active #007f73, Accent #ffd36d로 분리. Invalid border rgb(212, 20, 102) + Focus shadow color(srgb 0.780392 0.356863 0 / 0.5) 0px 0px 0px 3px 확인.
  • npm run typecheck, npm run build, npm run build-storybook 통과. 기존 문서 예시 CSS warning 및 Storybook chunk 크기 / plugin timing warning 유지.
  • 검증 범위: Chromium 환경. 다른 브라우저의 렌더링은 별도 확인이 필요하다.
  • 대표 All과 숨김 InvalidFocus 확인. 일반 Focus / Invalid의 padding 7.5px 11.5px, 기본 min-height 112px / 16px 글자 / Readonly resize none / Disabled opacity 0.6 유지. Border CSS 계약 1.5px, 이 브라우저 환경의 computed border-width는 1px으로 정규화. Input과 같은 Invalid + Focus ring.