nihonput 0.1.0
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/LICENSE +21 -0
- package/README.ja.md +318 -0
- package/README.md +318 -0
- package/dist/index.d.mts +216 -0
- package/dist/index.d.ts +216 -0
- package/dist/index.js +948 -0
- package/dist/index.mjs +892 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hanab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://img.shields.io/npm/v/nihonput?style=flat-square" alt="npm version" />
|
|
3
|
+
<img src="https://img.shields.io/npm/l/nihonput?style=flat-square" alt="license" />
|
|
4
|
+
<img src="https://img.shields.io/badge/React-18%2B-61dafb?style=flat-square&logo=react" alt="React 18+" />
|
|
5
|
+
<img src="https://img.shields.io/badge/TypeScript-5.0%2B-3178c6?style=flat-square&logo=typescript" alt="TypeScript" />
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<h1 align="center">nihonput</h1>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<strong>React用 日本語入力フォーム制御ライブラリ</strong>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
日本語フォーム入力を扱うためのHeadless React Hooksライブラリ。<br />
|
|
16
|
+
カタカナ、郵便番号、電話番号などの自動変換・バリデーション・フォーマットを提供します。
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="./README.md">🇺🇸 English</a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 特徴
|
|
26
|
+
|
|
27
|
+
- **カタカナ / ひらがな** — 自動変換とバリデーション
|
|
28
|
+
- **郵便番号** — `1234567` → `123-4567` へのフォーマットとバリデーション
|
|
29
|
+
- **都道府県** — バリデーションと自動補完(例: `東京` → `東京都`)
|
|
30
|
+
- **住所** — 全角/半角の文字幅制御
|
|
31
|
+
- **電話番号** — ハイフン自動挿入とバリデーション
|
|
32
|
+
- **IME対応** — 日本語IME変換中の適切なハンドリング
|
|
33
|
+
- **Headless** — UIなし、ロジックのみ。どんなデザインシステムとも組み合わせ可能
|
|
34
|
+
- **Tree-shaking対応** — 必要なものだけインポート可能
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## インストール
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install nihonput
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add nihonput
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
yarn add nihonput
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## クイックスタート
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { useNameField } from 'nihonput';
|
|
58
|
+
|
|
59
|
+
function NameInput() {
|
|
60
|
+
const field = useNameField({
|
|
61
|
+
kanaMode: 'auto-convert',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<input
|
|
66
|
+
value={field.value}
|
|
67
|
+
onChange={field.onChange}
|
|
68
|
+
onBlur={field.onBlur}
|
|
69
|
+
onCompositionStart={field.onCompositionStart}
|
|
70
|
+
onCompositionEnd={field.onCompositionEnd}
|
|
71
|
+
placeholder="フリガナ"
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`やまだ たろう` と入力 → blur時に自動で `ヤマダ タロウ` に変換されます。
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Hooks
|
|
82
|
+
|
|
83
|
+
### useNameField
|
|
84
|
+
|
|
85
|
+
フリガナなど、カタカナ入力用のフィールド。
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
const field = useNameField({
|
|
89
|
+
kanaMode: 'auto-convert', // または 'error-on-hiragana'
|
|
90
|
+
normalizeOn: 'blur', // 'blur' | 'change' | 'compositionEnd'
|
|
91
|
+
validateOn: 'blur', // 'blur' | 'change' | 'submit'
|
|
92
|
+
errorMessages: {
|
|
93
|
+
katakanaOnly: 'カタカナで入力してください',
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| オプション | 値 | 説明 |
|
|
99
|
+
|-----------|-----|------|
|
|
100
|
+
| `kanaMode` | `'auto-convert'` | ひらがな → カタカナ自動変換 |
|
|
101
|
+
| | `'error-on-hiragana'` | ひらがな入力時にエラー表示 |
|
|
102
|
+
| `normalizeOn` | `'blur'` `'change'` `'compositionEnd'` | 正規化のタイミング |
|
|
103
|
+
| `validateOn` | `'blur'` `'change'` `'submit'` | バリデーションのタイミング |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### usePostalCodeField
|
|
108
|
+
|
|
109
|
+
郵便番号フィールド用。
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
const field = usePostalCodeField({
|
|
113
|
+
widthMode: 'half-width-only', // または 'full-width-only'
|
|
114
|
+
onInvalid: 'auto-convert', // または 'error'
|
|
115
|
+
autoHyphen: true,
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| オプション | 値 | 説明 |
|
|
120
|
+
|-----------|-----|------|
|
|
121
|
+
| `widthMode` | `'half-width-only'` | 半角のみ許可(`123-4567`) |
|
|
122
|
+
| | `'full-width-only'` | 全角のみ許可(`123−4567`) |
|
|
123
|
+
| `onInvalid` | `'auto-convert'` | 自動変換 |
|
|
124
|
+
| | `'error'` | エラー表示 |
|
|
125
|
+
| `autoHyphen` | `true` / `false` | ハイフン自動挿入 |
|
|
126
|
+
|
|
127
|
+
**変換例:** `1234567` → `123-4567`
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### usePrefectureField
|
|
132
|
+
|
|
133
|
+
都道府県フィールド用。
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
const field = usePrefectureField({
|
|
137
|
+
autoComplete: true,
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
| オプション | 値 | 説明 |
|
|
142
|
+
|-----------|-----|------|
|
|
143
|
+
| `autoComplete` | `true` / `false` | 短縮名を自動補完 |
|
|
144
|
+
|
|
145
|
+
**変換例:** `東京` → `東京都`、`大阪` → `大阪府`
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### useAddressField
|
|
150
|
+
|
|
151
|
+
住所フィールド用。文字幅の制御が可能。
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
const field = useAddressField({
|
|
155
|
+
alphanumericMode: 'full-width-only', // または 'allow-half-width'
|
|
156
|
+
onInvalid: 'auto-convert',
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| オプション | 値 | 説明 |
|
|
161
|
+
|-----------|-----|------|
|
|
162
|
+
| `alphanumericMode` | `'full-width-only'` | 半角英数字を全角に変換 |
|
|
163
|
+
| | `'allow-half-width'` | 半角も許可 |
|
|
164
|
+
| `onInvalid` | `'auto-convert'` / `'error'` | 違反時の動作 |
|
|
165
|
+
|
|
166
|
+
**変換例:** `渋谷区1-2-3` → `渋谷区1−2−3`
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### usePhoneNumberField
|
|
171
|
+
|
|
172
|
+
電話番号フィールド用。
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
const field = usePhoneNumberField({
|
|
176
|
+
onInvalid: 'auto-convert',
|
|
177
|
+
autoHyphen: true,
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
| オプション | 値 | 説明 |
|
|
182
|
+
|-----------|-----|------|
|
|
183
|
+
| `onInvalid` | `'auto-convert'` / `'error'` | 違反時の動作 |
|
|
184
|
+
| `autoHyphen` | `true` / `false` | ハイフン自動挿入 |
|
|
185
|
+
|
|
186
|
+
**変換例:** `09012345678` → `090-1234-5678`
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 戻り値
|
|
191
|
+
|
|
192
|
+
すべてのフックは同じインターフェースを返します:
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
interface FieldReturn {
|
|
196
|
+
value: string; // 現在の値
|
|
197
|
+
onChange: (e) => void; // changeイベントハンドラ
|
|
198
|
+
onBlur: (e) => void; // blurイベントハンドラ
|
|
199
|
+
onCompositionStart: (e) => void; // IME変換開始
|
|
200
|
+
onCompositionEnd: (e) => void; // IME変換確定
|
|
201
|
+
error: string | null; // エラーメッセージ
|
|
202
|
+
isValidating: boolean; // バリデーション中かどうか
|
|
203
|
+
isComposing: boolean; // IME変換中かどうか
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 単体関数
|
|
210
|
+
|
|
211
|
+
フックを使わずに、バリデーション関数や正規化関数を単体で使用できます。
|
|
212
|
+
|
|
213
|
+
### バリデーション関数
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import {
|
|
217
|
+
validateKatakana,
|
|
218
|
+
validateHiragana,
|
|
219
|
+
validatePostalCode,
|
|
220
|
+
validatePrefecture,
|
|
221
|
+
validatePhoneNumber,
|
|
222
|
+
} from 'nihonput';
|
|
223
|
+
|
|
224
|
+
validateKatakana('カタカナ'); // true
|
|
225
|
+
validateKatakana('ひらがな'); // false
|
|
226
|
+
|
|
227
|
+
validatePostalCode('123-4567'); // true
|
|
228
|
+
validatePostalCode('1234567'); // true
|
|
229
|
+
|
|
230
|
+
validatePrefecture('東京都'); // true
|
|
231
|
+
validatePrefecture('東京'); // true(短縮形もOK)
|
|
232
|
+
|
|
233
|
+
validatePhoneNumber('090-1234-5678'); // true
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 正規化関数
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
import {
|
|
240
|
+
toKatakana,
|
|
241
|
+
toHiragana,
|
|
242
|
+
toFullWidth,
|
|
243
|
+
toHalfWidth,
|
|
244
|
+
addPostalCodeHyphen,
|
|
245
|
+
addPhoneNumberHyphen,
|
|
246
|
+
} from 'nihonput';
|
|
247
|
+
|
|
248
|
+
toKatakana('ひらがな'); // 'ヒラガナ'
|
|
249
|
+
toHiragana('カタカナ'); // 'かたかな'
|
|
250
|
+
|
|
251
|
+
toFullWidth('abc123'); // 'abc123'
|
|
252
|
+
toHalfWidth('123'); // '123'
|
|
253
|
+
|
|
254
|
+
addPostalCodeHyphen('1234567'); // '123-4567'
|
|
255
|
+
addPhoneNumberHyphen('09012345678'); // '090-1234-5678'
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## React Hook Form との連携
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { useForm } from 'react-hook-form';
|
|
264
|
+
import { toKatakana, validateKatakana } from 'nihonput';
|
|
265
|
+
|
|
266
|
+
function Form() {
|
|
267
|
+
const { register, handleSubmit, setValue, formState: { errors } } = useForm();
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<form onSubmit={handleSubmit(console.log)}>
|
|
271
|
+
<input
|
|
272
|
+
{...register('furigana', {
|
|
273
|
+
validate: (v) => validateKatakana(v) || 'カタカナで入力してください',
|
|
274
|
+
})}
|
|
275
|
+
onBlur={(e) => setValue('furigana', toKatakana(e.target.value))}
|
|
276
|
+
/>
|
|
277
|
+
{errors.furigana && <span>{errors.furigana.message}</span>}
|
|
278
|
+
|
|
279
|
+
<button type="submit">送信</button>
|
|
280
|
+
</form>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## エクスポート一覧
|
|
288
|
+
|
|
289
|
+
### Hooks
|
|
290
|
+
- `useNameField`
|
|
291
|
+
- `usePostalCodeField`
|
|
292
|
+
- `usePrefectureField`
|
|
293
|
+
- `useAddressField`
|
|
294
|
+
- `usePhoneNumberField`
|
|
295
|
+
|
|
296
|
+
### バリデーション関数
|
|
297
|
+
- `validateKatakana` / `containsHiragana`
|
|
298
|
+
- `validateHiragana` / `containsKatakana`
|
|
299
|
+
- `validatePostalCode` / `isHalfWidthPostalCode` / `isFullWidthPostalCode`
|
|
300
|
+
- `validatePrefecture` / `normalizePrefecture`
|
|
301
|
+
- `validatePhoneNumber` / `isHalfWidthPhoneNumber`
|
|
302
|
+
|
|
303
|
+
### 正規化関数
|
|
304
|
+
- `toKatakana` / `toHiragana`
|
|
305
|
+
- `toFullWidth` / `toHalfWidth`
|
|
306
|
+
- `toFullWidthNumbers` / `toHalfWidthNumbers`
|
|
307
|
+
- `addPostalCodeHyphen` / `addPhoneNumberHyphen`
|
|
308
|
+
|
|
309
|
+
### 定数
|
|
310
|
+
- `PREFECTURES` — 47都道府県の配列
|
|
311
|
+
- `PREFECTURE_SHORT_NAMES` — 短縮名から正式名へのマップ
|
|
312
|
+
- `defaultErrorMessages` — デフォルトエラーメッセージ
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## ライセンス
|
|
317
|
+
|
|
318
|
+
MIT © [Hanab Labs](https://github.com/HanabLabs)
|
package/README.md
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://img.shields.io/npm/v/nihonput?style=flat-square" alt="npm version" />
|
|
3
|
+
<img src="https://img.shields.io/npm/l/nihonput?style=flat-square" alt="license" />
|
|
4
|
+
<img src="https://img.shields.io/badge/React-18%2B-61dafb?style=flat-square&logo=react" alt="React 18+" />
|
|
5
|
+
<img src="https://img.shields.io/badge/TypeScript-5.0%2B-3178c6?style=flat-square&logo=typescript" alt="TypeScript" />
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<h1 align="center">nihonput</h1>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<strong>Japanese Input Form Control Library for React</strong>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
A headless React hooks library for handling Japanese form inputs.<br />
|
|
16
|
+
Automatic conversion, validation, and formatting for Katakana, postal codes, phone numbers, and more.
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="./README.ja.md">🇯🇵 日本語</a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Katakana / Hiragana** — Auto-convert and validate Japanese kana
|
|
28
|
+
- **Postal Code** — Format `1234567` → `123-4567` with validation
|
|
29
|
+
- **Prefecture** — Validate and auto-complete (e.g., `東京` → `東京都`)
|
|
30
|
+
- **Address** — Full-width / half-width character control
|
|
31
|
+
- **Phone Number** — Format with hyphens and validate
|
|
32
|
+
- **IME Aware** — Proper handling of Japanese IME composition
|
|
33
|
+
- **Headless** — No UI, just logic. Use with any design system
|
|
34
|
+
- **Tree-shakeable** — Import only what you need
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install nihonput
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add nihonput
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
yarn add nihonput
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { useNameField } from 'nihonput';
|
|
58
|
+
|
|
59
|
+
function NameInput() {
|
|
60
|
+
const field = useNameField({
|
|
61
|
+
kanaMode: 'auto-convert',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<input
|
|
66
|
+
value={field.value}
|
|
67
|
+
onChange={field.onChange}
|
|
68
|
+
onBlur={field.onBlur}
|
|
69
|
+
onCompositionStart={field.onCompositionStart}
|
|
70
|
+
onCompositionEnd={field.onCompositionEnd}
|
|
71
|
+
placeholder="フリガナ"
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Type `やまだ たろう` → automatically converts to `ヤマダ タロウ` on blur.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Hooks
|
|
82
|
+
|
|
83
|
+
### useNameField
|
|
84
|
+
|
|
85
|
+
For name fields with Katakana input.
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
const field = useNameField({
|
|
89
|
+
kanaMode: 'auto-convert', // or 'error-on-hiragana'
|
|
90
|
+
normalizeOn: 'blur', // 'blur' | 'change' | 'compositionEnd'
|
|
91
|
+
validateOn: 'blur', // 'blur' | 'change' | 'submit'
|
|
92
|
+
errorMessages: {
|
|
93
|
+
katakanaOnly: 'カタカナで入力してください',
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| Option | Values | Description |
|
|
99
|
+
|--------|--------|-------------|
|
|
100
|
+
| `kanaMode` | `'auto-convert'` | Hiragana → Katakana auto-conversion |
|
|
101
|
+
| | `'error-on-hiragana'` | Show error if Hiragana is entered |
|
|
102
|
+
| `normalizeOn` | `'blur'` `'change'` `'compositionEnd'` | When to normalize |
|
|
103
|
+
| `validateOn` | `'blur'` `'change'` `'submit'` | When to validate |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### usePostalCodeField
|
|
108
|
+
|
|
109
|
+
For Japanese postal codes (郵便番号).
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
const field = usePostalCodeField({
|
|
113
|
+
widthMode: 'half-width-only', // or 'full-width-only'
|
|
114
|
+
onInvalid: 'auto-convert', // or 'error'
|
|
115
|
+
autoHyphen: true,
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Option | Values | Description |
|
|
120
|
+
|--------|--------|-------------|
|
|
121
|
+
| `widthMode` | `'half-width-only'` | Only allow `123-4567` |
|
|
122
|
+
| | `'full-width-only'` | Only allow `123−4567` |
|
|
123
|
+
| `onInvalid` | `'auto-convert'` | Auto-convert to correct width |
|
|
124
|
+
| | `'error'` | Show validation error |
|
|
125
|
+
| `autoHyphen` | `true` / `false` | Auto-insert hyphen |
|
|
126
|
+
|
|
127
|
+
**Example:** `1234567` → `123-4567`
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### usePrefectureField
|
|
132
|
+
|
|
133
|
+
For Japanese prefecture (都道府県) input.
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
const field = usePrefectureField({
|
|
137
|
+
autoComplete: true,
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
| Option | Values | Description |
|
|
142
|
+
|--------|--------|-------------|
|
|
143
|
+
| `autoComplete` | `true` / `false` | Auto-complete short names |
|
|
144
|
+
|
|
145
|
+
**Example:** `東京` → `東京都`, `大阪` → `大阪府`
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### useAddressField
|
|
150
|
+
|
|
151
|
+
For address fields with character width control.
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
const field = useAddressField({
|
|
155
|
+
alphanumericMode: 'full-width-only', // or 'allow-half-width'
|
|
156
|
+
onInvalid: 'auto-convert',
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| Option | Values | Description |
|
|
161
|
+
|--------|--------|-------------|
|
|
162
|
+
| `alphanumericMode` | `'full-width-only'` | Convert half-width to full-width |
|
|
163
|
+
| | `'allow-half-width'` | Allow both |
|
|
164
|
+
| `onInvalid` | `'auto-convert'` / `'error'` | Behavior on invalid input |
|
|
165
|
+
|
|
166
|
+
**Example:** `渋谷区1-2-3` → `渋谷区1−2−3`
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### usePhoneNumberField
|
|
171
|
+
|
|
172
|
+
For Japanese phone numbers.
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
const field = usePhoneNumberField({
|
|
176
|
+
onInvalid: 'auto-convert',
|
|
177
|
+
autoHyphen: true,
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
| Option | Values | Description |
|
|
182
|
+
|--------|--------|-------------|
|
|
183
|
+
| `onInvalid` | `'auto-convert'` / `'error'` | Behavior on invalid input |
|
|
184
|
+
| `autoHyphen` | `true` / `false` | Auto-insert hyphens |
|
|
185
|
+
|
|
186
|
+
**Example:** `09012345678` → `090-1234-5678`
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Return Value
|
|
191
|
+
|
|
192
|
+
All hooks return the same interface:
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
interface FieldReturn {
|
|
196
|
+
value: string; // Current value
|
|
197
|
+
onChange: (e) => void; // Change handler
|
|
198
|
+
onBlur: (e) => void; // Blur handler
|
|
199
|
+
onCompositionStart: (e) => void; // IME composition start
|
|
200
|
+
onCompositionEnd: (e) => void; // IME composition end
|
|
201
|
+
error: string | null; // Validation error message
|
|
202
|
+
isValidating: boolean; // Validation in progress
|
|
203
|
+
isComposing: boolean; // IME composing state
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Standalone Functions
|
|
210
|
+
|
|
211
|
+
Use validators and normalizers without hooks:
|
|
212
|
+
|
|
213
|
+
### Validators
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import {
|
|
217
|
+
validateKatakana,
|
|
218
|
+
validateHiragana,
|
|
219
|
+
validatePostalCode,
|
|
220
|
+
validatePrefecture,
|
|
221
|
+
validatePhoneNumber,
|
|
222
|
+
} from 'nihonput';
|
|
223
|
+
|
|
224
|
+
validateKatakana('カタカナ'); // true
|
|
225
|
+
validateKatakana('ひらがな'); // false
|
|
226
|
+
|
|
227
|
+
validatePostalCode('123-4567'); // true
|
|
228
|
+
validatePostalCode('1234567'); // true
|
|
229
|
+
|
|
230
|
+
validatePrefecture('東京都'); // true
|
|
231
|
+
validatePrefecture('東京'); // true (short form)
|
|
232
|
+
|
|
233
|
+
validatePhoneNumber('090-1234-5678'); // true
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Normalizers
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
import {
|
|
240
|
+
toKatakana,
|
|
241
|
+
toHiragana,
|
|
242
|
+
toFullWidth,
|
|
243
|
+
toHalfWidth,
|
|
244
|
+
addPostalCodeHyphen,
|
|
245
|
+
addPhoneNumberHyphen,
|
|
246
|
+
} from 'nihonput';
|
|
247
|
+
|
|
248
|
+
toKatakana('ひらがな'); // 'ヒラガナ'
|
|
249
|
+
toHiragana('カタカナ'); // 'かたかな'
|
|
250
|
+
|
|
251
|
+
toFullWidth('abc123'); // 'abc123'
|
|
252
|
+
toHalfWidth('123'); // '123'
|
|
253
|
+
|
|
254
|
+
addPostalCodeHyphen('1234567'); // '123-4567'
|
|
255
|
+
addPhoneNumberHyphen('09012345678'); // '090-1234-5678'
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## React Hook Form Integration
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { useForm } from 'react-hook-form';
|
|
264
|
+
import { toKatakana, validateKatakana } from 'nihonput';
|
|
265
|
+
|
|
266
|
+
function Form() {
|
|
267
|
+
const { register, handleSubmit, setValue, formState: { errors } } = useForm();
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<form onSubmit={handleSubmit(console.log)}>
|
|
271
|
+
<input
|
|
272
|
+
{...register('furigana', {
|
|
273
|
+
validate: (v) => validateKatakana(v) || 'カタカナで入力してください',
|
|
274
|
+
})}
|
|
275
|
+
onBlur={(e) => setValue('furigana', toKatakana(e.target.value))}
|
|
276
|
+
/>
|
|
277
|
+
{errors.furigana && <span>{errors.furigana.message}</span>}
|
|
278
|
+
|
|
279
|
+
<button type="submit">Submit</button>
|
|
280
|
+
</form>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## All Exports
|
|
288
|
+
|
|
289
|
+
### Hooks
|
|
290
|
+
- `useNameField`
|
|
291
|
+
- `usePostalCodeField`
|
|
292
|
+
- `usePrefectureField`
|
|
293
|
+
- `useAddressField`
|
|
294
|
+
- `usePhoneNumberField`
|
|
295
|
+
|
|
296
|
+
### Validators
|
|
297
|
+
- `validateKatakana` / `containsHiragana`
|
|
298
|
+
- `validateHiragana` / `containsKatakana`
|
|
299
|
+
- `validatePostalCode` / `isHalfWidthPostalCode` / `isFullWidthPostalCode`
|
|
300
|
+
- `validatePrefecture` / `normalizePrefecture`
|
|
301
|
+
- `validatePhoneNumber` / `isHalfWidthPhoneNumber`
|
|
302
|
+
|
|
303
|
+
### Normalizers
|
|
304
|
+
- `toKatakana` / `toHiragana`
|
|
305
|
+
- `toFullWidth` / `toHalfWidth`
|
|
306
|
+
- `toFullWidthNumbers` / `toHalfWidthNumbers`
|
|
307
|
+
- `addPostalCodeHyphen` / `addPhoneNumberHyphen`
|
|
308
|
+
|
|
309
|
+
### Constants
|
|
310
|
+
- `PREFECTURES` — Array of all 47 prefectures
|
|
311
|
+
- `PREFECTURE_SHORT_NAMES` — Map of short names to full names
|
|
312
|
+
- `defaultErrorMessages` — Default error messages (Japanese)
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## License
|
|
317
|
+
|
|
318
|
+
MIT © [Hanab Labs](https://github.com/HanabLabs)
|