Files
HMDesign/docs/components/input.md
T

10 KiB

Input

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

1. 상태

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

2. 적용 근거

  • ui_viz Confirmed: size·padding-x(input.md §24, §16), border/radius/색(§10, §11, D-005), Focus/Error 표현.
  • ui_viz owner decision: size별 value·placeholder 글자(§9, §21 INPUT_VALUE_ROLE_FOLLOWS_SIZE).
  • HM 사용자 결정: Disabled opacity 0.6(2026-10-02, §10).
  • shadcn 유지: native input 동작, file: 스타일 class, disabled 포인터/커서 처리.
  • ui_viz 미정의: 아래 §11 참조.

3. 기본 규격

Size Height(min) Padding-x Font / Line-height
small 28 10 12 / 18
medium 34 12 14 / 20
large (기본) 42 12 16 / 24
  • 높이는 min-height, 한 줄 텍스트는 가운데.
  • Border 1px(--hm-sem-stroke-input-default), radius --hm-radius-input, face --hm-sem-bg-surface, 글자색 --hm-sem-fg-primary, weight 400.
  • Placeholder: --hm-sem-fg-placeholder, opacity: 1.

4. 상태 규격

상태 값 근거
Default 위 기본 규격 ui_viz Confirmed
Focus (:focus-visible) border 1.5px --hm-sem-stroke-input-focus, shadow/glow 없음, padding으로 0.5px 보정해 값이 움직이지 않음 ui_viz Confirmed
Error ([aria-invalid="true"]) border 1.5px --hm-sem-action-destructive, ring 없음 ui_viz Confirmed
Error + Keyboard Focus Destructive border 유지 + HM Focus Semantic 3px / 50% outer ring, outline: none 2026-10-06 사용자 결정
Disabled White face 유지, opacity: 0.6, cursor: not-allowed, pointer-events: none face: ui_viz Confirmed / opacity: 사용자 결정
Readonly ([readonly]) 박스 없음(border 0, padding-x 0, 투명 face), dim 없음, 항상 Large 치수 ui_viz
Hover / Active 정의 없음(별도 스타일 없음) ui_viz 미정의

Focus ring chain은 --ring → --hm-sem-stroke-input-focus → --hm-color-border-focus다. Error border는 --hm-input-error-border-color → --hm-sem-action-destructive를 따른다. 일반 Focus / Readonly의 기존 표현은 유지하며, editable Invalid + Focus에서 UA outline 의존을 제거했다.

5. API

Input:
  size?: native <input size> (number)
  →
  size?: "small" | "medium" | "large"     기본 "large"
  • native size(글자 수 폭)를 대체한다. native 속성이 CSS 폭과 무관해 쓰임이 없다는 판단(지침 §6.7).
  • 출력 속성: data-slot="input", data-size.
  • 상태는 새 prop이 아니라 native 속성으로 준다: aria-invalid, disabled, readOnly.
  • Field(Label, Required 별표, Helper/Error 문구)는 Input에 포함하지 않는다. 소비 조합이다.

6. Token

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

  • 재사용한 공통 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 참조).
  • Input 전용 값: --hm-input-height-{sm,md,lg}, --hm-input-padding-x-*, --hm-input-font-size-*, --hm-input-line-height-*, --hm-input-state-border-width(1.5px).
  • Primitive 신규 추가 없음.
  • Button의 높이 Token(--hm-button-height-*)·Select 높이와 값이 겹쳐도 alias하지 않는다. 각 ui_viz 규격이 따로 확정한 값이다.
  • Disabled opacity는 Token이 아니라 ui/input.tsx의 disabled:opacity-60으로 적용된다(§11).

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

native <input> 동작 전체(type, file: 스타일 class, placeholder), data-slot, cn(..., className), transition-colors, outline-none, disabled의 pointer-events-none/cursor-not-allowed. Radix 사용 없음.

8. HM에서 변경한 항목

  • size API 교체, 기본 Large, data-size 추가.
  • shadcn의 기본 높이/padding/border/ring/dark class 제거 → theme CSS가 담당.
  • 일반 Focus는 border 1.5px로 표시, Error 단독은 ring 없음. Error + :focus-visible만 독립 Focus ring을 표시한다.
  • Readonly 전용 표현 추가.
  • hm-input class 제거.

9. Storybook

  • 대표 Story All("Input"): 구역 sizes, default, focus, error, error-message, disabled, readonly. Focus는 play 함수로 실제 focus를 준다.
  • verification(tags: ["verification"]): Default, Focus, Error, InvalidFocus, ErrorMessage, Required, Disabled, Readonly, Sizes("Compare Sizes"), Small, Medium, Large, Playground(HM 전용).
  • Error Message·Required 표시는 Story 안의 조합 예시이며 Input 컴포넌트의 일부가 아니다.
  • sidebar는 All 하나만 보이는 1뎁스. 운영 규칙은 지침 §6.3, §7 참조.

10. 사용자 확정 결정

2026-10-11 최종 사용자 결정 — Disabled Input Label

  • Input Story 소비 조합(src/components/input.stories.tsx의 Specimen)의 Disabled Label은 기존 text-muted-foreground → --muted-foreground → --hm-sem-fg-secondary 색(#6E6759)을 유지하고, input.disabled일 때만 opacity-60을 적용한다. HEX·Semantic Token·공개 Input API는 변경하지 않는다.
  • Disabled Input 컨트롤 0.6, 소비 Label 0.6, 부모 Field 1이다. 형제 요소에 각각 적용하여 중첩 opacity를 만들지 않는다. 기본·readOnly·Error Label은 기존 1을 유지한다(Disabled가 아닌 경우).
  • 공통 Label Component의 Disabled 0.5는 유지한다. Helper Text(#6E6759)와 Error Message(#D32F2F)도 기존 구현을 유지하며 이번 변경 대상이 아니다.
  • 이전 검토의 “Label 100% 유지”는 당시 선택이며 현재 최종 결정은 Disabled Input Story Label 60%다. 아래 2026-10-02 승인과 2026-10-06 검증은 당시 기록으로 보존하며, 이번 Label 정책의 현재 검증을 대신하지 않는다.
  • 실제 소비 화면은 자동으로 확대 수정하지 않는다. 신규 화면의 공개 Label 재사용·control 연결 계약은 유지하며, 공통 Label의 Disabled 정책을 이 Story 결정으로 대체하지 않는다.

2026-10-02

  • Input Disabled opacity 0.6 확정.
  • ui_viz에서 Temporary로 기록된 이력이 있으나, 현재 HM 구현에서는 사용자 결정이 우선한다. 이전의 "Temporary → 미적용" 판단은 이 결정으로 superseded.
  • 이 값은 Input에 대한 현재 최종값이다. 전체 디자인 시스템 공통 Disabled opacity로 자동 확대하지 않는다.
  • 근거: Select 작업에서 확정된 Disabled 시각 intent와의 정합. Select Trigger도 0.6(select.md 참조).

11. 미확정 / 보류

  • ui_viz 미정의: Hover, Active 표현, Error 메시지 컴포넌트, Input 내부 아이콘/clear 버튼.
  • Disabled opacity 0.6은 Input 한정 사용자 결정이다. 다른 컴포넌트에 적용하지 않는다.
  • file: 타입 스타일은 shadcn 기본이며 HM 규격 없음.
  • Readonly에서 Disabled 조합 동작은 별도로 확인하지 않았다.

12. 관련 파일

packages/ui/src/components/ui/input.tsx
packages/ui/src/theme/input.css
src/components/input.stories.tsx
src/components/story-board.tsx

13. 검증 상태

  • TypeScript, npm run build: 통과(2026-10-02).
  • Storybook computed style: Components/Form/Input Disabled opacity = 0.6 확인.
  • Story: All의 구역 7개와 verification Story ID 존재 확인.
  • 2026-10-06 ui_viz Storybook 화면 비교(1280/768/390, Chromium): 대표 Story 7구역의 컨트롤·Label·Error 문구 computed style 일치, placeholder 색, Focus·Error 경계, Error+Focus의 outline 유지, 긴 값 가로 스크롤 일치. Readonly는 ui_viz <p> 대신 native input[readonly]로 같은 42px·16/24 표시. Error Message·Required Story에 ui_viz처럼 placeholder를 넣음(Story만 변경).
  • 미확인: 브라우저별 렌더(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는 border만 변경, Small/Medium/Large 28/34/42px 및 12/14/16px 유지. Readonly border 0 / padding 0, Disabled opacity 0.6 유지. Border CSS 계약 1.5px, 이 브라우저 환경의 computed border-width는 1px으로 정규화; padding 보정은 11.5px 유지. 기존 non-invalid Readonly의 UA outline 정책은 이번 범위에서 유지.

Disabled Input Label 검증 (2026-10-11)

  • 실제 Storybook(Chromium/Edge): Disabled Label rgb(110, 103, 89) / opacity 0.6, Input 0.6, 부모와 모든 조상 opacity 1. 공통 Label Disabled 0.5, Input Default/readOnly/Error Label 1 유지.
  • 실제 배경 rgb(245, 240, 229)에서 합성색 약 #A49E91, 대비 약 2.35:1(원본 100% 약 4.93:1). 일반 텍스트 4.5:1보다 낮으며, 실제 disabled 컨트롤에 연결된 비활성 UI 라벨의 WCAG 1.4.3 예외와 구분한다. 사용자 확정 정책은 유지하고 가독성 우려를 기록한다.
  • Default/Disabled/Readonly/Error/Error Message/Playground 및 대표 All 390/768/1280/1440px, htmlFor/control 연결·편집·readOnly·disabled focus·문서 overflow 확인. Typecheck, UI build, Storybook build 통과. Guard FAIL 0, 원본 NOT VERIFIED 보존. 검증 범위와 제한.