@ehfuse/mui-form-controls
v3.1.40
Published
Material-UI form controls and text fields for complex forms
Readme
@ehfuse/mui-form-controls
MUI 기반 폼 컨트롤과 텍스트 필드 컴포넌트 모음
컴포넌트
| 컴포넌트 | 설명 | 문서 |
| ----------------------------- | ---------------------------------------------------------------- | ------------------------------------------------- |
| AddressTextField | 다음 우편번호 API 연동 주소 검색 필드 | API |
| Autocomplete | 자동완성 기능이 있는 입력 필드 | API |
| BizNumTextField | 사업자등록번호 입력 필드 (검증, 복사 기능) | API |
| CardNumTextField | 카드번호 4-4-4-4 입력 (2·3칸 마스킹, 브랜드 로고, 키보드 UX) | API |
| ClearTextField | 클리어 버튼이 있는 기본 텍스트 필드 | API |
| DateRange | 날짜 범위 입력 필드 (시작일, 종료일) | API |
| DateTextField | 달력 팝업, 다양한 날짜 포맷, 공휴일 표시 지원 날짜 필드 | API |
| DateTimeTextField | 날짜 + 시간 입력 필드 | API |
| EmailTextField | 도메인 자동완성, 유효성 검사 기능이 있는 이메일 필드 | API |
| JuminTextField | 주민등록번호 입력 필드 (마스킹, 정보 추출) | API |
| NumberField | 숫자 입력 (MUI OutlinedInput + 위·아래 스피너) | API |
| NumberStepper | 가로 스테퍼 ([-] 숫자 [+], 길게 누르기 가속) | API |
| NumberSpinner | 숫자 스피너 (좌우 버튼 + 라벨 드래그) | API |
| NumberTextField | 천 단위 구분자, 소수점, 음수 지원하는 숫자 필드 | API |
| PasswordTextField | 비밀번호 보기/숨기기 토글, 유효성 검사 기능이 있는 비밀번호 필드 | API |
| PhoneTextField | 자동 포맷팅, prefix 고정 기능이 있는 전화번호 필드 | API |
| SearchTextField | 클리어 버튼, 로딩 상태, 디바운스 기능이 있는 검색 필드 | API |
| TextArea | 여러 줄 텍스트 입력 필드 | API |
| TagsTextField | 태그(칩) 목록 입력 · 드래그 정렬 · 선택적 삭제/클릭 콜백 | API |
| TextField | MUI TextField 래퍼 (폼 통합) | API |
| TimeTextField | 시간 입력 필드 (자동 포맷팅, 시간 범위 제한) | API |
| VerificationCodeTextField | 인증번호 입력 필드 (숫자/영문/혼합) | API |
폼 컨트롤 (Form Controls)
키보드 입력이 필요한 컴포넌트는 위 "컴포넌트"에, 마우스 조작만으로 선택/토글하는 컴포넌트는 여기서 분리해 정리했습니다.
| 컴포넌트 | 설명 | 문서 |
| --------------------- | ------------------------------------------------------------ | ----------------------------------------- |
| ButtonGroup | 버튼 그룹 컴포넌트 | API |
| Checkbox | MUI Checkbox 래퍼 (폼 통합) | API |
| LabelSelect | MUI Select 기반 선택 필드 (권장: 라벨 포함, form 바인딩) | API |
| RadioGroup | MUI RadioGroup 래퍼 (폼 통합) | API |
| Rating | 평점 입력 컴포넌트 | API |
| Slider | MUI Slider 래퍼 (폼 통합) | API |
| Stepper | 스텝 진행 표시 컴포넌트 | API |
| Switch | MUI Switch 래퍼 (폼 통합) | API |
| ToggleButton | 토글 버튼 컴포넌트 | API |
| ToggleButtonGroup | 옵션 기반 토글 그룹 필드 (ToggleButtonGroup + form 바인딩) | API |
훅 (Hooks)
| 훅 | 설명 | 문서 | | -------------------------- | --------------------------------------------------- | ---------------------------------------------- | | useKoreanHolidays | 단일 연도의 한국 공휴일을 조회하는 커스텀 훅 | API | | useKoreanHolidaysRange | 여러 연도의 한국 공휴일을 한번에 조회하는 커스텀 훅 | API |
설치
npm install @ehfuse/mui-form-controlsAddressTextField를 사용할 때만 다음 우편번호 의존성을 추가로 설치합니다.
npm install react-daum-postcode필수 의존성
{
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0",
"@mui/icons-material": "^5.0.0 || ^6.0.0 || ^7.0.0",
"@emotion/react": "^11.0.0",
"@emotion/styled": "^11.0.0",
"@ehfuse/overlay-scrollbar": "^1.0.0"
}빠른 시작
import {
SearchTextField,
ClearTextField,
PasswordTextField,
PhoneTextField,
EmailTextField,
NumberTextField,
JuminTextField,
BizNumTextField,
CardNumTextField,
VerificationCodeTextField,
DateTextField,
TimeTextField,
DateTimeTextField,
TextField,
Rating,
ToggleButton,
ToggleButtonGroup,
ButtonGroup,
Stepper,
NumberField,
NumberStepper,
NumberSpinner,
LabelSelect,
Autocomplete,
Checkbox,
RadioGroup,
Switch,
ToggleButtonGroup,
Slider,
DateRange,
TextArea,
TagsTextField,
useKoreanHolidays,
useKoreanHolidaysRange,
} from '@ehfuse/mui-form-controls';
import { AddressTextField } from '@ehfuse/mui-form-controls/address';
// 검색 필드
<SearchTextField
value={search}
onChange={(e) => setSearch(e.target.value)}
searchIcon
loading={isSearching}
/>
// 비밀번호 필드
<PasswordTextField
value={password}
onChange={(e) => setPassword(e.target.value)}
showToggle
/>
// 전화번호 필드
<PhoneTextField
value={phone}
onChange={(e) => setPhone(e.target.value)}
prefix="010"
/>
// 이메일 필드 (forma 호환)
<EmailTextField
name="email"
value={email}
onChange={handleFormChange}
extraDomains={["mycompany.com"]}
/>
// 숫자 필드
<NumberTextField
value={amount}
onChange={(e) => setAmount(e.target.value)}
prefix="₩"
suffix="원"
/>
// 날짜 필드
<DateTextField
value={date}
onChange={(e) => setDate(e.target.value)}
format="YYYY.MM.DD"
selectedColor="secondary.main"
/>
// 주소 필드
<AddressTextField
value={address}
onChange={setAddress}
/>
// 주민등록번호 필드
<JuminTextField
value={jumin}
onChange={setJumin}
mask
/>
// 사업자등록번호 필드
<BizNumTextField
value={bizNum}
onChange={setBizNum}
validate
copyIcon
/>
// 카드번호 필드
<CardNumTextField
value={cardNum}
onChange={(e) => setCardNum(e.target.value)}
onCardBrandChange={(brand) => console.log('카드 브랜드:', brand)}
/>
// 인증번호 필드
<VerificationCodeTextField
value={code}
onChange={setCode}
length={6}
type="numeric"
onComplete={(code) => console.log('완료:', code)}
/>
// 시간 필드
<TimeTextField
value={time}
onChange={(e) => setTime(e.target.value)}
format="HH:mm"
minTime="09:00"
maxTime="18:00"
/>
// 선택 필드 (권장: LabelSelect)
<LabelSelect
name="category"
label="카테고리"
form={form}
options={[
{ value: 'a', label: 'A' },
{ value: 'b', label: 'B' },
]}
/>
// 자동완성 필드
<Autocomplete
name="department"
label="부서"
form={form}
options={[
{ value: 'dev', label: '개발' },
{ value: 'design', label: '디자인' },
]}
/>
// 날짜 범위
<DateRange
form={form}
startName="startDate"
endName="endDate"
startLabel="시작일"
endLabel="종료일"
/>
// 텍스트 에어리어
<TextArea
name="memo"
label="메모"
form={form}
minRows={4}
/>
// 태그(칩) 입력 — `onDelete`·`onTagClick`은 모두 선택. 지정하지 않으면 X는 즉시 삭제, 칩 클릭 핸들러 없음
<TagsTextField
name="tags"
label="태그"
form={form}
placeholder="입력 후 콤마 또는 스페이스"
onDeleteBefore={(e, tag, index) => {
/* 선택: false 반환 시 X 삭제 전체 취소(onDelete·내부 삭제 모두 안 함) */
}}
onDelete={(e, tag, index) => {
/* onDelete 지정 시 내부 삭제 없음 → 모달 확인 뒤 form.setFormValue("tags", ...) 등으로 배열 갱신 */
}}
onTagClick={(e, tag, index) => {
/* 예: 상세 모달·라우팅 — 삭제 아이콘(X) 클릭과는 별도 */
}}
/>선택 입력은 예제/문서 기준으로
LabelSelect를 사용합니다.
TagsTextField (태그 입력)
문자열 배열을 태그 칩으로 표시하고, 콤마·스페이스 등으로 태그를 확정합니다. draggable(기본 true)일 때 드래그로 순서를 바꿀 수 있습니다.
여백·스타일: 입력 칸 기준 좌우 패딩은 기본값에서 theme.spacing과 동일한 단위로 좌우 대칭(px: 1.5)입니다. 칩 줄만 손볼 때는 chipsSx, 아웃라인 안 레이아웃·패딩은 sx(이 컴포넌트에서는 .MuiInputBase-root 아래로 감싸져 적용됨). slotProps / InputProps는 MUI와 동일합니다. 자세한 셀렉터 예시는 API — TagsTextField 스타일을 참고하세요.
칩 X(삭제 아이콘) 클릭 시 순서
- **
onDeleteBefore**가 있으면 먼저 호출됩니다.false를 반환하면 여기서 끝이며,onDelete도 호출되지 않고 내부에서도 태그를 제거하지 않습니다. - 그다음
onDelete가 있으면 그것만 호출하고 내부 자동 삭제는 하지 않습니다. 모달에서 “삭제”를 누른 뒤 등, 반드시form.setFormValue/onChange로string[]에서 해당 태그를 빼 주어야 화면이 맞습니다. onDelete가 없으면 컴포넌트가 곧바로 그 태그를 배열에서 제거합니다(기본 즉시 삭제).
onDelete만 두고 onDeleteBefore는 생략할 수 있고, 그 반대로 onDeleteBefore만 두고 onDelete는 생략하면: 가드에서 막지 않았을 때만 기본 즉시 삭제가 실행됩니다.
| 콜백 / 동작 | 옵션 여부 | 설명 |
| ------------------ | --------- | ---- |
| onDeleteBefore | 선택 | X 클릭 가장 먼저. false면 이후 단계 전부 취소. |
| onDelete | 선택 | 가드 통과 후 호출 시 전적으로 소비자가 배열 갱신. 없으면 내부 즉시 삭제. |
| onTagClick | 선택 | 칩 본문 클릭 시. 상세 모달·상세 페이지 등. chipProps.onClick이 먼저 호출되고, event.defaultPrevented이면 onTagClick은 호출되지 않음. |
draggable이 true이면 짧은 클릭과 드래그 시작이 겹칠 수 있습니다(기본 포인터 센서는 약 5px 이동 후 드래그). 자세한 props는 한국어 API를 참고하세요.
NumberField · NumberStepper · NumberSpinner
세 컴포넌트는 공용 훅 useNumberBasic을 기반으로 동일한 동작 규칙을 공유합니다.
- 입력 중
min/max초과 시 즉시 경계값으로 고정 (clamp) - 천 단위 구분은 기본 적용(Intl·로케일),
thousandSeparator={false}로 끔 form/name지정 시 폼 연동clearWhenZero로 0을 빈칸 표시 (기본false— 0을 0으로 표시)
표시 형태만 다릅니다.
| 컴포넌트 | 형태 |
| -------- | ---- |
| NumberField | MUI OutlinedInput + 오른쪽 위·아래 스피너 |
| NumberStepper | [-] 숫자 [+] 가로 스테퍼 (길게 누르기 가속) |
| NumberSpinner | 좌우 [-]/[+] 버튼 + 라벨 드래그(scrub) 증감 |
// NumberField — 기본 입력 + 위·아래 스피너
<NumberField label="수량" defaultValue={2} min={0} max={99} />
// 천 단위 구분은 기본 적용. 끄려면 thousandSeparator={false}
<NumberField label="금액" defaultValue={1234567} min={0} max={99999999} />
// NumberStepper — 가로 스테퍼 + 길게 누르기 가속 (CPS = 초당 증감 횟수)
<NumberStepper
defaultValue={1}
min={0}
max={99}
aria-label="수량"
stepperAccelerateHoldDelay={300}
stepperAccelerateRampDuration={2000}
stepperAccelerateCps={5}
stepperAccelerateMaxCps={25}
/>
// NumberSpinner — 좌우 버튼 + 라벨 드래그
<NumberSpinner label="수량" defaultValue={2} min={0} max={99} />| prop | 설명 |
| ---- | ---- |
| thousandSeparator | boolean \| string — 기본 true. false 끔 · string 구분 문자 고정 · true일 때 Intl |
| clearWhenZero | 0을 빈칸으로 표시. 기본 false |
| stepperAccelerateHoldDelay | (NumberStepper) 누른 직후 1회 변경 후, 자동 반복까지 대기(ms) |
| stepperAccelerateRampDuration | (NumberStepper) 시작 CPS→최대 CPS까지 걸리는 시간(ms) |
| stepperAccelerateCps | (NumberStepper) 자동 반복 시작 속도 (초당 횟수) |
stepperEditable, stepperButtonDivider(NumberStepper), spinnerDivider(NumberField) 등 전체 props는 API를 참고하세요.
Boolean 필드 표준 패턴
Switch를 boolean 입력의 기본 form-binding 컴포넌트로 사용합니다.
import { Switch } from "@ehfuse/mui-form-controls";
// 1) 단일 스위치 (라벨 없음)
<Switch form={form} name="deceased_disability_certificate" />
// 2) 라벨 포함 스위치 (권장)
<Switch
form={form}
name="deceased_disability_certificate"
label="장애인 증명서 제출"
/>
// 3) readOnly / disabled
<Switch
form={form}
name="deceased_disability_certificate"
label="수정 불가 항목"
readonly
/>
<Switch
form={form}
name="deceased_disability_certificate"
label="비활성 항목"
disabled
/>Toggle 그룹 표준 패턴
import { ToggleButtonGroup } from "@ehfuse/mui-form-controls";
<ToggleButtonGroup
form={form}
name="contractor_gender"
exclusive
options={[
{ label: "남성", value: "M" },
{ label: "여성", value: "F" },
]}
onDeselect="clear"
fullWidth
size="small"
/>;문서 / Documentation
라이선스 / License
MIT © 김영진 (Kim Young Jin)
