'use client'; import { useActionState, useId, useState } from 'react'; import { FoxButton } from '@fox/core/components/fox-button'; import { FoxInput } from '@fox/core/components/fox-input'; import { FoxEyeIcon, FoxEyeSlashIcon } from '@fox/core/icons'; import { login, type LoginFormState } from '../_actions'; import styles from '../login.module.scss'; const initialState: LoginFormState = {}; /** 시안의 안내 문구. 오류가 없을 때 이 자리에 보인다. */ const HELPER_TEXT = '비밀번호 5회 불일치 시 계정 로그인이 차단됩니다.'; /** * 로그인 폼 — 시안 login-area(5432:16137)의 제목 아래 부분이다. 입력·라벨·버튼은 시안이 * 디자인시스템 컴포넌트를 그대로 쓰고 있어 FoxInput/FoxButton으로 덮인다(치수·서체가 시안과 * 같다). `label`을 주면 FoxInput이 FoxFormLabel까지 함께 그린다. * * 비밀번호 보기 토글은 로그인 화면 전용이다 — FoxInput에 그 기능이 없고, `icon` 슬롯은 * `aria-hidden="true"`라 버튼을 넣으면 보조기술에서 사라진다(사용자 확정). 그래서 슬롯 대신 * 같은 자리에 버튼을 겹쳐 둔다. * * 오류 문구는 FoxInput의 `message`가 아니라 시안의 안내문 자리에 함께 둔다 — 어느 칸이 * 틀렸는지 알려주지 않는 것이 보안상 맞고(계정 존재 여부가 새지 않는다), 입력칸 아래에 * 메시지가 끼면 보기 토글의 세로 위치도 어긋난다. */ export function LoginForm() { const [state, formAction, isPending] = useActionState(login, initialState); const [isPasswordVisible, setIsPasswordVisible] = useState(false); const passwordId = useId(); return (
); }