/* ============================================================================ * 서명전에 — TDS Button 컴포넌트 * · TDS Mobile 2026-03 Button 스펙. 기존 `.btn` (HIG 잔재) 을 대체하는 신규 * 공식 버튼. 레거시 `.btn` 은 deprecated 로 유지 (§4.7 마이그레이션 참고). * * · props: * as "button" (기본) | "a" * color "primary" (기본) | "danger" | "light" | "dark" * variant "fill" (기본) | "weak" * display "inline" (기본) | "block" | "full" * size "small" | "medium" | "large" | "xlarge" (기본) * loading boolean — 3-dot 인디케이터 + 딤 레이어. 너비는 유지. * disabled boolean * type "button" | "submit" | "reset" (as="button" 에서만) * href string (as="a" 에서만) * htmlStyle React.CSSProperties — HTML 의 `style` 속성에 매핑. * `style` prop 은 CSS 변수 오버라이드용으로 쓰는 것이 권장이지만 * 래퍼/HoC 가 `style` 을 가로채는 환경을 위해 별도 경로로 제공. * className, aria-* 등 HTMLElement 속성 전부 패스스루. * * · 색상 커스터마이즈는 style 로 CSS 변수 덮어쓰기: * * 지원 변수는 §4.7 참조. * * · 로딩 상태는 aria-busy="true", 비활성은 disabled/aria-disabled 로 접근성 지원. * ========================================================================== */ function Button({ as = "button", color = "primary", variant = "fill", display = "inline", size = "xlarge", loading = false, disabled = false, type, href, htmlStyle, style, className = "", children, onClick, ...rest }) { const Tag = as === "a" ? "a" : "button"; const cls = [ "tds-button", `tds-button--${color}`, `tds-button--${variant}`, `tds-button--${display}`, `tds-button--${size}`, loading && "is-loading", disabled && "is-disabled", className, ] .filter(Boolean) .join(" "); // style (CSS 변수 오버라이드 용) + htmlStyle (일반 인라인 스타일) 병합. const mergedStyle = { ...(style || {}), ...(htmlStyle || {}) }; // 로딩/비활성 시 클릭 가로채기. button 태그는 disabled 속성으로도 막히지만 // a 태그는 disabled 가 없어서 가로채고 aria-disabled 만 달아준다. const handleClick = (e) => { if (loading || disabled) { e.preventDefault(); e.stopPropagation(); return; } onClick?.(e); }; const tagProps = { className: cls, style: mergedStyle, onClick: handleClick, "aria-busy": loading ? "true" : undefined, ...rest, }; if (Tag === "button") { tagProps.type = type || "button"; // loading 중에도 실제 클릭은 못하게 disabled 처리 (포커스는 유지). tagProps.disabled = disabled || loading; } else { if (href) tagProps.href = href; if (disabled || loading) { tagProps["aria-disabled"] = "true"; tagProps.tabIndex = -1; } } return ( {children} {loading && ( ); } window.Button = Button; Object.assign(window, { Button });