인터랙션 상태
컨트롤이 호버, 누름, 포커스, 선택, 대기 상태를 보여 주는 방식을 정합니다.
원칙
- 상태마다 신호를 따로 두세요. 호버, 누름, 포커스, 선택, 대기는 뜻이 다르므로 한 가지 색으로 합치지 마세요.
- 작업을 호버나 드래그 뒤에 숨기지 마세요. 터치와 키보드 사용자에게는 둘 다 없으므로 모든 작업에 보이는 컨트롤을 두세요.
- 포커스는 사용자가 둔 곳에 두세요. 공유 포커스 링으로 보여 주고, 작업이 끝났다고 옮기지 마세요.
- 대기 중을 완료로 다루지 마세요. 두 번째 시작을 막고, 가능하면 취소를 두고, 실제 결과만 알리세요.
- 쓸 수 없는 작업에는 이유를 알리세요. 비활성 컨트롤 옆에 이유를 쓰고, 값을 읽어야 하면 읽기 전용을 쓰세요.
상태 모델
상태는 지금 할 수 있는 일과 방금 일어난 일을 알려 줍니다. 공유 컨트롤은 상태마다 토큰을 따로 씁니다.
호버와 누름은 컨트롤에 이미 있는 채움 위에 한 겹으로 그립니다. 그래서 일반 버튼, 눌린 토글, 선택된 행에서 똑같이 보입니다. 선택 채움은 그 겹 아래의 색만 정합니다.
강제 색상 모드에서는 시스템 팔레트가 모든 토큰을 대신합니다. 호버와 누름 겹은 사라지고 포커스는 링을 유지합니다. 선택되었거나 현재 위치이거나 눌린 컨트롤은 Highlight로 채우고 레이블을 HighlightText로 씁니다. 팝업 목록에서 강조된 항목과 자기 링크를 담은 선택 행은 대신 CanvasText 윤곽선을 그리고, 팝업은 고른 항목을 체크 표시로 보여 줍니다.
포커스 링
버튼과 선택 컨트롤은 --surf-interaction-focus 색으로 --surf-focus-ring-width 링을 --surf-focus-ring-offset만큼 띄워 그립니다. 둘 다 2px이고, 키보드 포커스(:focus-visible)에서만 보입니다.
텍스트 필드는 포커스를 받으면 테두리를 --surf-control-focus로 바꾸고 3px --surf-control-focus-ring 헤일로를 더합니다. 컨테이너가 잘라 내는 곳에서는 링이 --surf-focus-ring-inset만큼 안쪽으로 들어갑니다.
선택과 실행
마우스, 터치, Enter, Space는 같은 작업을 실행합니다. 아래에서 토글은 선택을 유지하고, 비활성 버튼은 실행되지 않고, 읽기 전용 필드는 복사할 수 있습니다.
증거를 제외했습니다.
이 값에 포커스하고 복사하세요. 편집할 수는 없습니다.
비활성 컨트롤은 aria-describedby로 이유와 연결하세요. 컴포넌트의 기본 키 동작을 유지하고, 작업을 두 번 실행하는 keydown 핸들러를 더하지 마세요.
대기 중인 작업
대기 중에는 실행 버튼이 포커스를 유지하고 두 번째 시작을 막습니다. 취소하면 포커스가 실행 버튼으로 돌아오고, 완료되어도 포커스는 그대로입니다. 900ms 로컬 작업으로 실패, 취소, 재시도를 시험해 보세요.
시작한 횟수: 0
실행한 미리보기가 없습니다.
누름에는 100ms 안에 반응하세요. 1초를 넘길 수 있는 작업에는 스피너를, 10초를 넘는 작업에는 진행률을 보여 주세요.
비활성 상태만으로는 요청이 막히지 않으므로 핸들러에서도 막으세요. 실제 쓰기 작업의 멱등성과 권한은 서버가 맡습니다.