@ehfuse/mui-form-controls 3.1.21 → 3.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -20
- package/dist/NumberField.d.ts +4 -1
- package/dist/components/NumberField.d.ts +16 -96
- package/dist/components/NumberSpinner.d.ts +14 -16
- package/dist/components/NumberStepper.d.ts +72 -0
- package/dist/components/index.d.ts +4 -1
- package/dist/components/numberBasic.d.ts +72 -0
- package/dist/hooks/useNumberBasic.d.ts +52 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +59 -1
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +59 -1
- package/dist/index.mjs.map +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,8 +16,9 @@ MUI 기반 폼 컨트롤과 텍스트 필드 컴포넌트 모음
|
|
|
16
16
|
| **DateTimeTextField** | 날짜 + 시간 입력 필드 | [API](./docs/ko/api.md#datetimetextfield) |
|
|
17
17
|
| **EmailTextField** | 도메인 자동완성, 유효성 검사 기능이 있는 이메일 필드 | [API](./docs/ko/api.md#emailtextfield) |
|
|
18
18
|
| **JuminTextField** | 주민등록번호 입력 필드 (마스킹, 정보 추출) | [API](./docs/ko/api.md#jumintextfield) |
|
|
19
|
-
| **NumberField** | 숫자 입력 (
|
|
20
|
-
| **
|
|
19
|
+
| **NumberField** | 숫자 입력 (MUI OutlinedInput + 위·아래 스피너) | [API](./docs/ko/api.md#numberfield) |
|
|
20
|
+
| **NumberStepper** | 가로 스테퍼 (`[-]` 숫자 `[+]`, 길게 누르기 가속) | [API](./docs/ko/api.md#numberstepper) |
|
|
21
|
+
| **NumberSpinner** | 숫자 스피너 (좌우 버튼 + 라벨 드래그) | [API](./docs/ko/api.md#numberspinner) |
|
|
21
22
|
| **NumberTextField** | 천 단위 구분자, 소수점, 음수 지원하는 숫자 필드 | [API](./docs/ko/api.md#numbertextfield) |
|
|
22
23
|
| **PasswordTextField** | 비밀번호 보기/숨기기 토글, 유효성 검사 기능이 있는 비밀번호 필드 | [API](./docs/ko/api.md#passwordtextfield) |
|
|
23
24
|
| **PhoneTextField** | 자동 포맷팅, prefix 고정 기능이 있는 전화번호 필드 | [API](./docs/ko/api.md#phonetextfield) |
|
|
@@ -102,6 +103,7 @@ import {
|
|
|
102
103
|
ButtonGroup,
|
|
103
104
|
Stepper,
|
|
104
105
|
NumberField,
|
|
106
|
+
NumberStepper,
|
|
105
107
|
NumberSpinner,
|
|
106
108
|
LabelSelect,
|
|
107
109
|
Autocomplete,
|
|
@@ -292,25 +294,32 @@ import { AddressTextField } from '@ehfuse/mui-form-controls/address';
|
|
|
292
294
|
|
|
293
295
|
`draggable`이 `true`이면 짧은 클릭과 드래그 시작이 겹칠 수 있습니다(기본 포인터 센서는 약 5px 이동 후 드래그). 자세한 props는 [한국어 API](./docs/ko/api.md#tagstextfield)를 참고하세요.
|
|
294
296
|
|
|
295
|
-
## NumberField
|
|
297
|
+
## NumberField · NumberStepper · NumberSpinner
|
|
296
298
|
|
|
297
|
-
|
|
299
|
+
세 컴포넌트는 공용 훅 `useNumberBasic`을 기반으로 동일한 동작 규칙을 공유합니다.
|
|
300
|
+
|
|
301
|
+
- 입력 중 `min`/`max` 초과 시 **즉시 경계값으로 고정** (clamp)
|
|
302
|
+
- 천 단위 구분은 기본 적용(Intl·로케일), `thousandSeparator={false}`로 끔
|
|
303
|
+
- `form`/`name` 지정 시 폼 연동
|
|
304
|
+
- `clearWhenZero`로 0을 빈칸 표시 (**기본 `false` — 0을 0으로 표시**)
|
|
305
|
+
|
|
306
|
+
표시 형태만 다릅니다.
|
|
307
|
+
|
|
308
|
+
| 컴포넌트 | 형태 |
|
|
309
|
+
| -------- | ---- |
|
|
310
|
+
| **NumberField** | MUI OutlinedInput + 오른쪽 위·아래 스피너 |
|
|
311
|
+
| **NumberStepper** | `[-]` 숫자 `[+]` 가로 스테퍼 (길게 누르기 가속) |
|
|
312
|
+
| **NumberSpinner** | 좌우 `[-]`/`[+]` 버튼 + 라벨 드래그(scrub) 증감 |
|
|
298
313
|
|
|
299
314
|
```tsx
|
|
300
|
-
// 기본 스피너
|
|
315
|
+
// NumberField — 기본 입력 + 위·아래 스피너
|
|
301
316
|
<NumberField label="수량" defaultValue={2} min={0} max={99} />
|
|
302
317
|
|
|
303
|
-
// 천 단위 구분은 기본
|
|
304
|
-
<NumberField
|
|
305
|
-
label="금액"
|
|
306
|
-
defaultValue={1234567}
|
|
307
|
-
min={0}
|
|
308
|
-
max={99999999}
|
|
309
|
-
/>
|
|
318
|
+
// 천 단위 구분은 기본 적용. 끄려면 thousandSeparator={false}
|
|
319
|
+
<NumberField label="금액" defaultValue={1234567} min={0} max={99999999} />
|
|
310
320
|
|
|
311
|
-
// 가로 스테퍼 + 길게 누르기 가속 (CPS = 초당
|
|
312
|
-
<
|
|
313
|
-
variant="stepper"
|
|
321
|
+
// NumberStepper — 가로 스테퍼 + 길게 누르기 가속 (CPS = 초당 증감 횟수)
|
|
322
|
+
<NumberStepper
|
|
314
323
|
defaultValue={1}
|
|
315
324
|
min={0}
|
|
316
325
|
max={99}
|
|
@@ -320,16 +329,20 @@ import { AddressTextField } from '@ehfuse/mui-form-controls/address';
|
|
|
320
329
|
stepperAccelerateCps={5}
|
|
321
330
|
stepperAccelerateMaxCps={25}
|
|
322
331
|
/>
|
|
332
|
+
|
|
333
|
+
// NumberSpinner — 좌우 버튼 + 라벨 드래그
|
|
334
|
+
<NumberSpinner label="수량" defaultValue={2} min={0} max={99} />
|
|
323
335
|
```
|
|
324
336
|
|
|
325
337
|
| prop | 설명 |
|
|
326
338
|
| ---- | ---- |
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
339
|
+
| `thousandSeparator` | `boolean \| string` — 기본 `true`. `false` 끔 · `string` 구분 문자 고정 · `true`일 때 Intl |
|
|
340
|
+
| `clearWhenZero` | 0을 빈칸으로 표시. 기본 `false` |
|
|
341
|
+
| `stepperAccelerateHoldDelay` | (NumberStepper) 누른 직후 1회 변경 후, 자동 반복까지 대기(ms) |
|
|
342
|
+
| `stepperAccelerateRampDuration` | (NumberStepper) 시작 CPS→최대 CPS까지 걸리는 시간(ms) |
|
|
343
|
+
| `stepperAccelerateCps` | (NumberStepper) 자동 반복 **시작** 속도 (초당 횟수) |
|
|
331
344
|
|
|
332
|
-
`stepperEditable`, `stepperButtonDivider
|
|
345
|
+
`stepperEditable`, `stepperButtonDivider`(NumberStepper), `spinnerDivider`(NumberField) 등 전체 props는 [API](./docs/ko/api.md#numberfield)를 참고하세요.
|
|
333
346
|
|
|
334
347
|
## Boolean 필드 표준 패턴
|
|
335
348
|
|
package/dist/NumberField.d.ts
CHANGED
|
@@ -6,5 +6,8 @@
|
|
|
6
6
|
* @author 김영진 (ehfuse@gmail.com)
|
|
7
7
|
*/
|
|
8
8
|
export { default as NumberField } from "./components/NumberField";
|
|
9
|
-
export type { NumberFieldAlign, NumberFieldProps,
|
|
9
|
+
export type { NumberFieldAlign, NumberFieldProps, } from "./components/NumberField";
|
|
10
|
+
export { default as NumberStepper } from "./components/NumberStepper";
|
|
11
|
+
export type { NumberStepperProps } from "./components/NumberStepper";
|
|
10
12
|
export { default as NumberSpinner } from "./components/NumberSpinner";
|
|
13
|
+
export type { NumberSpinnerProps } from "./components/NumberSpinner";
|
|
@@ -1,101 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 천 단위 구분.
|
|
19
|
-
* - `false`: 구분 없음
|
|
20
|
-
* - `true` / `undefined`(기본): `Intl` 로케일 규칙 (`locale`·`format`과 함께)
|
|
21
|
-
* - `string`: 구분 문자 직접 지정 (예: `","`, `"."`, `" "`)
|
|
22
|
-
* @default true
|
|
23
|
-
*/
|
|
24
|
-
thousandSeparator?: ThousandSeparatorProp;
|
|
25
|
-
/** @default "default" — `stepper`는 [-] 값 [+] 가로 스테퍼 UI */
|
|
26
|
-
variant?: NumberFieldVariant;
|
|
27
|
-
/**
|
|
28
|
-
* 값이 정확히 0일 때 입력칸을 빈칸으로 표시한다 (placeholder만 노출).
|
|
29
|
-
*
|
|
30
|
-
* 내부 값은 항상 숫자(0 포함)로 유지되므로 base-ui의 스피너 증감이 정상 동작한다
|
|
31
|
-
* (빈칸=0에서 ▲ → 1, 1에서 ▼ → 0=빈칸). 표시(렌더링)만 비우며,
|
|
32
|
-
* `onValueChange`로는 숫자 0이 그대로 전달된다. 포커스/입력 중에는 사용자가
|
|
33
|
-
* 타이핑한 값을 그대로 보여주고, 비포커스 상태에서만 0을 빈칸으로 표시한다.
|
|
34
|
-
*
|
|
35
|
-
* `default`·`stepper` 두 variant 모두에 적용된다.
|
|
36
|
-
* 0을 빈칸으로 표시하려면 `clearWhenZero={true}`로 켠다.
|
|
37
|
-
* @default false
|
|
38
|
-
*/
|
|
39
|
-
clearWhenZero?: boolean;
|
|
40
|
-
/**
|
|
41
|
-
* `variant="stepper"`일 때 가운데를 키패드·키보드로 직접 입력할지 여부.
|
|
42
|
-
* @default false — Typography로 숫자만 표시 (장바구니 수량 UI 등)
|
|
43
|
-
*/
|
|
44
|
-
stepperEditable?: boolean;
|
|
45
|
-
/** `variant="stepper"` 루트(Box)에 적용할 `sx` */
|
|
46
|
-
stepperSx?: SxProps<Theme>;
|
|
47
|
-
/** `variant="stepper"`일 때 − / + 버튼과 숫자 영역 사이 세로 구분선 */
|
|
48
|
-
stepperButtonDivider?: boolean;
|
|
49
|
-
/** `variant="stepper"` 감소(−) 버튼 `sx` */
|
|
50
|
-
stepperDecrementButtonSx?: SxProps<Theme>;
|
|
51
|
-
/** `variant="stepper"` 증가(+) 버튼 `sx` */
|
|
52
|
-
stepperIncrementButtonSx?: SxProps<Theme>;
|
|
53
|
-
/** `variant="stepper"` 가운데 숫자 영역 `sx` */
|
|
54
|
-
stepperCenterSx?: SxProps<Theme>;
|
|
55
|
-
/**
|
|
56
|
-
* `variant="stepper"`일 때 화면에 라벨을 표시할지 여부.
|
|
57
|
-
* @default false — 장바구니 수량처럼 컴팩트 UI에는 라벨 없음. `label`은 접근성용 aria-label로만 쓸 수 있음.
|
|
58
|
-
*/
|
|
59
|
-
stepperShowLabel?: boolean;
|
|
60
|
-
/** `variant="stepper"` 감소 버튼 아이콘. 미지정 시 Remove(−) 아이콘 */
|
|
61
|
-
stepperDecrementIcon?: React.ReactNode;
|
|
62
|
-
/** `variant="stepper"` 증가 버튼 아이콘. 미지정 시 Add(+) 아이콘 */
|
|
63
|
-
stepperIncrementIcon?: React.ReactNode;
|
|
64
|
-
/** `variant="stepper"` 감소 버튼 클릭 이벤트. `event.preventDefault()` 호출 시 기본 감소 동작을 막는다. */
|
|
65
|
-
onStepperDecrementClick?: (event: React.MouseEvent<HTMLButtonElement>, value: number | null) => void;
|
|
66
|
-
/** `variant="stepper"` 증가 버튼 클릭 이벤트. `event.preventDefault()` 호출 시 기본 증가 동작을 막는다. */
|
|
67
|
-
onStepperIncrementClick?: (event: React.MouseEvent<HTMLButtonElement>, value: number | null) => void;
|
|
68
|
-
/**
|
|
69
|
-
* `variant="default"`일 때 위·아래 스피너 영역 왼쪽 구분선 표시 여부.
|
|
1
|
+
/**
|
|
2
|
+
* NumberField.tsx
|
|
3
|
+
*
|
|
4
|
+
* MUI OutlinedInput + Base UI NumberField 기반 숫자 입력 필드.
|
|
5
|
+
* 가로 스테퍼(−값+)는 `NumberStepper`, 드래그 스피너는 `NumberSpinner`로 분리됐다.
|
|
6
|
+
* 값 상태·clamp·grouping 공용 로직은 `useNumberBasic` 훅이 담당한다.
|
|
7
|
+
*
|
|
8
|
+
* @license MIT
|
|
9
|
+
* @copyright 2025 김영진 (Kim Young Jin)
|
|
10
|
+
* @author 김영진 (ehfuse@gmail.com)
|
|
11
|
+
*/
|
|
12
|
+
import { type NumberBaseProps } from "./numberBasic";
|
|
13
|
+
export type { NumberFieldAlign } from "./numberBasic";
|
|
14
|
+
export type NumberFieldProps = NumberBaseProps & {
|
|
15
|
+
/**
|
|
16
|
+
* 위·아래 스피너 영역 왼쪽 구분선 표시 여부.
|
|
70
17
|
* @default true
|
|
71
18
|
*/
|
|
72
19
|
spinnerDivider?: boolean;
|
|
73
|
-
/**
|
|
74
|
-
* `variant="stepper"`에서 길게 누를 때 반복 간격이 점점 짧아지는 가속 효과.
|
|
75
|
-
* @default true
|
|
76
|
-
*/
|
|
77
|
-
stepperAccelerate?: boolean;
|
|
78
|
-
/**
|
|
79
|
-
* 길게 누른 뒤, 숫자가 **한 번** 바뀐 다음 자동 반복이 시작되기까지의 대기 시간(ms).
|
|
80
|
-
* @default 300
|
|
81
|
-
*/
|
|
82
|
-
stepperAccelerateHoldDelay?: number;
|
|
83
|
-
/**
|
|
84
|
-
* 자동 반복이 시작된 뒤, 시작 속도에서 최고 속도까지 빨라지는 데 걸리는 시간(ms).
|
|
85
|
-
* @default 1800
|
|
86
|
-
*/
|
|
87
|
-
stepperAccelerateRampDuration?: number;
|
|
88
|
-
/**
|
|
89
|
-
* 길게 눌렀을 때 **처음** 자동으로 숫자가 바뀌는 속도
|
|
90
|
-
* 예) `5` → 1초에 5번(약 0.2초마다 1씩 증가)
|
|
91
|
-
* @default 5
|
|
92
|
-
*/
|
|
93
|
-
stepperAccelerateCps?: number;
|
|
94
|
-
/**
|
|
95
|
-
* 가속이 끝난 뒤 유지되는 **최고** 속도.
|
|
96
|
-
* 예) `100` → 1초에 100번 반복 (약 0.01초마다 1씩 증가)
|
|
97
|
-
* @default 100
|
|
98
|
-
*/
|
|
99
|
-
stepperAccelerateMaxCps?: number;
|
|
100
20
|
};
|
|
101
21
|
export default function NumberField(props: NumberFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export default function NumberSpinner({ id: idProp, label, error, size, suffix, thousandSeparator, locale, format, ...other }: NumberSpinnerProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
-
export {};
|
|
1
|
+
/**
|
|
2
|
+
* NumberSpinner.tsx
|
|
3
|
+
*
|
|
4
|
+
* 좌우 [−][+] 버튼 + 라벨 드래그(ScrubArea) 증감형 숫자 입력.
|
|
5
|
+
* 값 상태·min/max 즉시 clamp·grouping·폼 연동 공용 로직은 `useNumberBasic` 훅이
|
|
6
|
+
* 담당한다(min/max·form이 주어졌을 때만 동작하므로 기존 사용과 호환).
|
|
7
|
+
*
|
|
8
|
+
* @license MIT
|
|
9
|
+
* @copyright 2025 김영진 (Kim Young Jin)
|
|
10
|
+
* @author 김영진 (ehfuse@gmail.com)
|
|
11
|
+
*/
|
|
12
|
+
import { type NumberBaseProps } from "./numberBasic";
|
|
13
|
+
export type NumberSpinnerProps = NumberBaseProps;
|
|
14
|
+
export default function NumberSpinner(props: NumberSpinnerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NumberStepper.tsx
|
|
3
|
+
*
|
|
4
|
+
* 가로 스테퍼([−] 값 [+]) 형태의 숫자 입력. 장바구니 수량 등 컴팩트 UI용.
|
|
5
|
+
* 값 상태·clamp·grouping 공용 로직은 `useNumberBasic` 훅이 담당한다.
|
|
6
|
+
*
|
|
7
|
+
* @license MIT
|
|
8
|
+
* @copyright 2025 김영진 (Kim Young Jin)
|
|
9
|
+
* @author 김영진 (ehfuse@gmail.com)
|
|
10
|
+
*/
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import type { SxProps, Theme } from "@mui/material/styles";
|
|
13
|
+
import { type NumberBaseProps } from "./numberBasic";
|
|
14
|
+
export type { NumberFieldAlign } from "./numberBasic";
|
|
15
|
+
export type NumberStepperProps = NumberBaseProps & {
|
|
16
|
+
/**
|
|
17
|
+
* 가운데를 키패드·키보드로 직접 입력할지 여부.
|
|
18
|
+
* @default false — Typography로 숫자만 표시 (장바구니 수량 UI 등)
|
|
19
|
+
*/
|
|
20
|
+
stepperEditable?: boolean;
|
|
21
|
+
/** 루트(Box)에 적용할 `sx` */
|
|
22
|
+
stepperSx?: SxProps<Theme>;
|
|
23
|
+
/** − / + 버튼과 숫자 영역 사이 세로 구분선 */
|
|
24
|
+
stepperButtonDivider?: boolean;
|
|
25
|
+
/** 감소(−) 버튼 `sx` */
|
|
26
|
+
stepperDecrementButtonSx?: SxProps<Theme>;
|
|
27
|
+
/** 증가(+) 버튼 `sx` */
|
|
28
|
+
stepperIncrementButtonSx?: SxProps<Theme>;
|
|
29
|
+
/** 가운데 숫자 영역 `sx` */
|
|
30
|
+
stepperCenterSx?: SxProps<Theme>;
|
|
31
|
+
/**
|
|
32
|
+
* 화면에 라벨을 표시할지 여부.
|
|
33
|
+
* @default false — 컴팩트 UI에는 라벨 없음. `label`은 aria-label로만 쓸 수 있음.
|
|
34
|
+
*/
|
|
35
|
+
stepperShowLabel?: boolean;
|
|
36
|
+
/** 감소 버튼 아이콘. 미지정 시 Remove(−) 아이콘 */
|
|
37
|
+
stepperDecrementIcon?: React.ReactNode;
|
|
38
|
+
/** 증가 버튼 아이콘. 미지정 시 Add(+) 아이콘 */
|
|
39
|
+
stepperIncrementIcon?: React.ReactNode;
|
|
40
|
+
/** 감소 버튼 클릭 이벤트. `event.preventDefault()` 호출 시 기본 감소 동작을 막는다. */
|
|
41
|
+
onStepperDecrementClick?: (event: React.MouseEvent<HTMLButtonElement>, value: number | null) => void;
|
|
42
|
+
/** 증가 버튼 클릭 이벤트. `event.preventDefault()` 호출 시 기본 증가 동작을 막는다. */
|
|
43
|
+
onStepperIncrementClick?: (event: React.MouseEvent<HTMLButtonElement>, value: number | null) => void;
|
|
44
|
+
/**
|
|
45
|
+
* 길게 누를 때 반복 간격이 점점 짧아지는 가속 효과.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
stepperAccelerate?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* 길게 누른 뒤, 숫자가 **한 번** 바뀐 다음 자동 반복이 시작되기까지의 대기 시간(ms).
|
|
51
|
+
* @default 300
|
|
52
|
+
*/
|
|
53
|
+
stepperAccelerateHoldDelay?: number;
|
|
54
|
+
/**
|
|
55
|
+
* 자동 반복이 시작된 뒤, 시작 속도에서 최고 속도까지 빨라지는 데 걸리는 시간(ms).
|
|
56
|
+
* @default 1800
|
|
57
|
+
*/
|
|
58
|
+
stepperAccelerateRampDuration?: number;
|
|
59
|
+
/**
|
|
60
|
+
* 길게 눌렀을 때 **처음** 자동으로 숫자가 바뀌는 속도
|
|
61
|
+
* 예) `5` → 1초에 5번(약 0.2초마다 1씩 증가)
|
|
62
|
+
* @default 5
|
|
63
|
+
*/
|
|
64
|
+
stepperAccelerateCps?: number;
|
|
65
|
+
/**
|
|
66
|
+
* 가속이 끝난 뒤 유지되는 **최고** 속도.
|
|
67
|
+
* 예) `100` → 1초에 100번 반복 (약 0.01초마다 1씩 증가)
|
|
68
|
+
* @default 100
|
|
69
|
+
*/
|
|
70
|
+
stepperAccelerateMaxCps?: number;
|
|
71
|
+
};
|
|
72
|
+
export default function NumberStepper(props: NumberStepperProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,5 +3,8 @@ export type { GroupedInputWrapperProps } from "./GroupedInputWrapper";
|
|
|
3
3
|
export { ColonBox } from "./ColonBox";
|
|
4
4
|
export type { ColonBoxProps } from "./ColonBox";
|
|
5
5
|
export { default as NumberField } from "./NumberField";
|
|
6
|
-
export type { NumberFieldProps } from "./NumberField";
|
|
6
|
+
export type { NumberFieldProps, NumberFieldAlign } from "./NumberField";
|
|
7
|
+
export { default as NumberStepper } from "./NumberStepper";
|
|
8
|
+
export type { NumberStepperProps } from "./NumberStepper";
|
|
7
9
|
export { default as NumberSpinner } from "./NumberSpinner";
|
|
10
|
+
export type { NumberSpinnerProps } from "./NumberSpinner";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* numberBasic.tsx
|
|
3
|
+
*
|
|
4
|
+
* NumberField · NumberStepper · NumberSpinner 공용 타입/헬퍼/폼 바인딩.
|
|
5
|
+
* 값 상태·clamp·grouping 등 동작 로직은 `useNumberBasic` 훅이 담당하고,
|
|
6
|
+
* 이 파일은 세 컴포넌트가 공유하는 순수 헬퍼와 타입만 모은다.
|
|
7
|
+
*
|
|
8
|
+
* @license MIT
|
|
9
|
+
* @copyright 2025 김영진 (Kim Young Jin)
|
|
10
|
+
* @author 김영진 (ehfuse@gmail.com)
|
|
11
|
+
*/
|
|
12
|
+
import * as React from "react";
|
|
13
|
+
import { NumberField as BaseNumberField } from "@base-ui/react/number-field";
|
|
14
|
+
import type { NumberFieldRoot } from "@base-ui/react/number-field";
|
|
15
|
+
import type { FormLike } from "../types";
|
|
16
|
+
import type { ThousandSeparatorProp } from "../utils/number";
|
|
17
|
+
export type NumberFieldAlign = "left" | "center" | "right";
|
|
18
|
+
/**
|
|
19
|
+
* 세 숫자 컴포넌트(NumberField·NumberStepper·NumberSpinner) 공통 props.
|
|
20
|
+
* 각 컴포넌트는 여기에 자기만의 표시 옵션을 더한다.
|
|
21
|
+
*/
|
|
22
|
+
export type NumberBaseProps = BaseNumberField.Root.Props & {
|
|
23
|
+
label?: React.ReactNode;
|
|
24
|
+
size?: "small" | "medium";
|
|
25
|
+
error?: boolean;
|
|
26
|
+
fullWidth?: boolean;
|
|
27
|
+
form?: FormLike | null;
|
|
28
|
+
suffix?: React.ReactNode;
|
|
29
|
+
/** 입력 숫자 텍스트 정렬 방향. */
|
|
30
|
+
align?: NumberFieldAlign;
|
|
31
|
+
/**
|
|
32
|
+
* 천 단위 구분.
|
|
33
|
+
* - `false`: 구분 없음
|
|
34
|
+
* - `true` / `undefined`(기본): `Intl` 로케일 규칙 (`locale`·`format`과 함께)
|
|
35
|
+
* - `string`: 구분 문자 직접 지정 (예: `","`, `"."`, `" "`)
|
|
36
|
+
* @default true
|
|
37
|
+
*/
|
|
38
|
+
thousandSeparator?: ThousandSeparatorProp;
|
|
39
|
+
/**
|
|
40
|
+
* 값이 정확히 0일 때 입력칸을 빈칸으로 표시한다 (placeholder만 노출).
|
|
41
|
+
*
|
|
42
|
+
* 내부 값은 항상 숫자(0 포함)로 유지되므로 base-ui의 스피너 증감이 정상 동작한다.
|
|
43
|
+
* 표시(렌더링)만 비우며, `onValueChange`로는 숫자 0이 그대로 전달된다.
|
|
44
|
+
* 0을 빈칸으로 표시하려면 `clearWhenZero={true}`로 켠다.
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
clearWhenZero?: boolean;
|
|
48
|
+
};
|
|
49
|
+
/** 다양한 입력(문자열·null 포함)을 NumberField 내부 숫자 값으로 정규화 */
|
|
50
|
+
export declare function normalizeNumberFieldValue(value: unknown): number | null;
|
|
51
|
+
/** default OutlinedInput과 동일한 입력 영역 높이 */
|
|
52
|
+
export declare function getNumberFieldControlHeight(size: "small" | "medium"): 40 | 56;
|
|
53
|
+
/**
|
|
54
|
+
* FormControl이 SSR에서 shrink label 상태를 올바르게 잡도록 하는 placeholder.
|
|
55
|
+
*/
|
|
56
|
+
export declare function SSRInitialFilled(_: BaseNumberField.Root.Props): null;
|
|
57
|
+
export declare namespace SSRInitialFilled {
|
|
58
|
+
var muiName: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `form`/`name`이 주어졌을 때 폼 값과 양방향으로 연결한다.
|
|
62
|
+
* form이 있는 경우에만 렌더되는 하위 컴포넌트에서 무조건 호출되어야 한다
|
|
63
|
+
* (조건부 호출 금지). NumberField·NumberStepper·NumberSpinner 공통.
|
|
64
|
+
*/
|
|
65
|
+
export declare function useNumberFormBinding({ form, name, onValueChange, }: {
|
|
66
|
+
form: FormLike;
|
|
67
|
+
name: string;
|
|
68
|
+
onValueChange?: (value: number | null, eventDetails: NumberFieldRoot.ChangeEventDetails) => void;
|
|
69
|
+
}): {
|
|
70
|
+
value: number | null;
|
|
71
|
+
onValueChange: (next: number | null, eventDetails: NumberFieldRoot.ChangeEventDetails) => void;
|
|
72
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useNumberBasic.ts
|
|
3
|
+
*
|
|
4
|
+
* NumberField · NumberStepper · NumberSpinner 공용 동작 훅.
|
|
5
|
+
* 값 상태(controlled/uncontrolled) · min/max 즉시 clamp · 천 단위 live grouping ·
|
|
6
|
+
* format 정규화 · Base UI Root 배선에 필요한 값들을 한곳에서 만들어 돌려준다.
|
|
7
|
+
* 각 컴포넌트는 이 훅을 호출하고 "가운데 표시/입력 UI"만 다르게 렌더한다.
|
|
8
|
+
*
|
|
9
|
+
* clamp는 min/max가 주어졌을 때만, 폼 연동은 form이 주어졌을 때만 동작하므로
|
|
10
|
+
* 세 컴포넌트에 동일하게 적용해도 순수한 상위호환이다.
|
|
11
|
+
*
|
|
12
|
+
* @license MIT
|
|
13
|
+
* @copyright 2025 김영진 (Kim Young Jin)
|
|
14
|
+
* @author 김영진 (ehfuse@gmail.com)
|
|
15
|
+
*/
|
|
16
|
+
import * as React from "react";
|
|
17
|
+
import type { NumberFieldRoot } from "@base-ui/react/number-field";
|
|
18
|
+
import { type ThousandSeparatorProp } from "../utils/number";
|
|
19
|
+
export interface UseNumberBasicParams {
|
|
20
|
+
value?: number | null;
|
|
21
|
+
defaultValue?: number | string | null;
|
|
22
|
+
onValueChange?: (value: number | null, eventDetails: NumberFieldRoot.ChangeEventDetails) => void;
|
|
23
|
+
min?: number;
|
|
24
|
+
max?: number;
|
|
25
|
+
locale?: Intl.LocalesArgument;
|
|
26
|
+
format?: Intl.NumberFormatOptions;
|
|
27
|
+
thousandSeparator?: ThousandSeparatorProp;
|
|
28
|
+
clearWhenZero?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 초기값(defaultValue)이 없을 때 min(또는 0)으로 채울지 여부.
|
|
31
|
+
* 스테퍼처럼 항상 숫자 값이 있어야 증감이 자연스러운 경우 true.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
initialFallbackToMin?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function useNumberBasic({ value, defaultValue, onValueChange, min, max, locale, format, thousandSeparator, clearWhenZero, initialFallbackToMin, }: UseNumberBasicParams): {
|
|
37
|
+
isControlled: boolean;
|
|
38
|
+
resolvedValue: number | null;
|
|
39
|
+
setInternalValue: React.Dispatch<React.SetStateAction<number | null>>;
|
|
40
|
+
inputRef: React.RefObject<HTMLInputElement | null>;
|
|
41
|
+
liveGrouping: {
|
|
42
|
+
getDisplayValue: (baseInputValue: string) => string;
|
|
43
|
+
syncBaseInputValue: (baseInputValue: string) => void;
|
|
44
|
+
setLiveDisplay: (text: string | null) => void;
|
|
45
|
+
wrapOnChange: (handler: React.ChangeEventHandler<HTMLInputElement> | undefined) => (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
46
|
+
wrapOnBlur: (handler: React.FocusEventHandler<HTMLInputElement> | undefined) => (event: React.FocusEvent<HTMLInputElement, Element>) => void;
|
|
47
|
+
wrapOnFocus: (handler: React.FocusEventHandler<HTMLInputElement> | undefined) => (event: React.FocusEvent<HTMLInputElement, Element>) => void;
|
|
48
|
+
};
|
|
49
|
+
groupingEnabled: boolean;
|
|
50
|
+
handleValueChange: (next: number | null, details: NumberFieldRoot.ChangeEventDetails) => void;
|
|
51
|
+
formatForRoot: Intl.NumberFormatOptions | undefined;
|
|
52
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -21,8 +21,8 @@ export { ButtonGroup } from "./ButtonGroup";
|
|
|
21
21
|
export { DateRange } from "./DateRange";
|
|
22
22
|
export { Slider } from "./Slider";
|
|
23
23
|
export { Stepper } from "./Stepper";
|
|
24
|
-
export { NumberField, NumberSpinner } from "./NumberField";
|
|
25
|
-
export type { NumberFieldProps,
|
|
24
|
+
export { NumberField, NumberStepper, NumberSpinner } from "./NumberField";
|
|
25
|
+
export type { NumberFieldProps, NumberFieldAlign, NumberStepperProps, NumberSpinnerProps, } from "./NumberField";
|
|
26
26
|
export { Autocomplete } from "./Autocomplete";
|
|
27
27
|
export { Select } from "./Select";
|
|
28
28
|
export { LabelSelect } from "./LabelSelect";
|