thaizip 0.2.1 → 0.3.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/README.md +67 -25
- package/dist/data.cjs +127 -11
- package/dist/data.d.cts +2 -2
- package/dist/data.d.ts +2 -2
- package/dist/data.js +127 -11
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
- ค้นหาได้ทั้งภาษาไทย ภาษาอังกฤษ และรหัสไปรษณีย์
|
|
6
6
|
- Fuzzy search — ไม่ต้องใส่วรรณยุกต์ก็ค้นหาได้ เช่น "ลาดพราว" เจอ "ลาดพร้าว"
|
|
7
7
|
- ไม่มี dependency นอกจาก React (optional)
|
|
8
|
-
-
|
|
8
|
+
- โหลดข้อมูลแบบ async — ไม่บล็อก initial bundle (~132 KB gzip)
|
|
9
9
|
- รองรับ ESM และ CJS
|
|
10
10
|
|
|
11
11
|
---
|
|
@@ -22,20 +22,23 @@ npm install thaizip
|
|
|
22
22
|
|
|
23
23
|
## การใช้งานพื้นฐาน (Vanilla JS / TypeScript)
|
|
24
24
|
|
|
25
|
-
###
|
|
25
|
+
### โหลด index และค้นหาที่อยู่
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
|
-
import {
|
|
28
|
+
import { loadDefaultIndex } from 'thaizip/data'
|
|
29
29
|
import { searchThaiAddress } from 'thaizip'
|
|
30
30
|
|
|
31
|
+
// โหลด index ครั้งแรก ~200ms (cached หลังจากนั้น)
|
|
32
|
+
const index = await loadDefaultIndex()
|
|
33
|
+
|
|
31
34
|
// ค้นหาด้วยชื่อตำบล/อำเภอ/จังหวัด
|
|
32
|
-
const results = searchThaiAddress(
|
|
35
|
+
const results = searchThaiAddress(index, 'ลาดพร้าว')
|
|
33
36
|
|
|
34
37
|
// ค้นหาด้วยรหัสไปรษณีย์
|
|
35
|
-
const
|
|
38
|
+
const results2 = searchThaiAddress(index, '10900')
|
|
36
39
|
|
|
37
40
|
// ค้นหาด้วยภาษาอังกฤษ
|
|
38
|
-
const
|
|
41
|
+
const results3 = searchThaiAddress(index, 'chiang mai')
|
|
39
42
|
|
|
40
43
|
console.log(results)
|
|
41
44
|
// [{ tambonId, tambonNameTh, tambonNameEn, amphureId, amphureNameTh, ... zipCode }, ...]
|
|
@@ -44,7 +47,7 @@ console.log(results)
|
|
|
44
47
|
### ตัวเลือก (options)
|
|
45
48
|
|
|
46
49
|
```ts
|
|
47
|
-
const results = searchThaiAddress(
|
|
50
|
+
const results = searchThaiAddress(index, 'ลาดพร้าว', {
|
|
48
51
|
limit: 5, // จำนวนผลลัพธ์สูงสุด (default: 10)
|
|
49
52
|
threshold: 0.4, // ความแม่นยำขั้นต่ำ 0–1 (default: 0.4)
|
|
50
53
|
})
|
|
@@ -61,9 +64,9 @@ const suggestion = formatThaiAddressSuggestion(results[0])
|
|
|
61
64
|
// {
|
|
62
65
|
// id: '100101',
|
|
63
66
|
// label: 'ลาดพร้าว > ลาดพร้าว > กรุงเทพมหานคร 10230',
|
|
64
|
-
// tambon: 'ลาดพร้าว',
|
|
65
|
-
// amphure: 'ลาดพร้าว',
|
|
66
|
-
// province: 'กรุงเทพมหานคร',
|
|
67
|
+
// tambon: 'ลาดพร้าว', tambonEn: 'Lat Phrao',
|
|
68
|
+
// amphure: 'ลาดพร้าว', amphureEn: 'Lat Phrao',
|
|
69
|
+
// province: 'กรุงเทพมหานคร', provinceEn: 'Bangkok',
|
|
67
70
|
// zipCode: '10230',
|
|
68
71
|
// }
|
|
69
72
|
```
|
|
@@ -75,10 +78,13 @@ import { resolveThaiAddress } from 'thaizip'
|
|
|
75
78
|
|
|
76
79
|
const resolved = resolveThaiAddress(results[0])
|
|
77
80
|
// {
|
|
78
|
-
// tambon: 'ลาดพร้าว',
|
|
79
|
-
// amphure: 'ลาดพร้าว',
|
|
80
|
-
// province: 'กรุงเทพมหานคร',
|
|
81
|
-
// zipCode: '10230',
|
|
81
|
+
// tambon: 'ลาดพร้าว', tambonEn: 'Lat Phrao',
|
|
82
|
+
// amphure: 'ลาดพร้าว', amphureEn: 'Lat Phrao',
|
|
83
|
+
// province: 'กรุงเทพมหานคร', provinceEn: 'Bangkok',
|
|
84
|
+
// zipCode: '10230',
|
|
85
|
+
// subdistrict: 'ลาดพร้าว', subdistrictEn: 'Lat Phrao',
|
|
86
|
+
// district: 'ลาดพร้าว', districtEn: 'Lat Phrao',
|
|
87
|
+
// postalCode: '10230',
|
|
82
88
|
// }
|
|
83
89
|
```
|
|
84
90
|
|
|
@@ -91,13 +97,21 @@ const resolved = resolveThaiAddress(results[0])
|
|
|
91
97
|
Hook นี้จัดการ state ของ query, suggestions, debounce ให้ทั้งหมด
|
|
92
98
|
|
|
93
99
|
```tsx
|
|
94
|
-
import {
|
|
100
|
+
import { useState, useEffect } from 'react'
|
|
101
|
+
import { loadDefaultIndex } from 'thaizip/data'
|
|
95
102
|
import { useThaiAddressAutocomplete } from 'thaizip'
|
|
103
|
+
import type { TrigramIndex } from 'thaizip'
|
|
96
104
|
|
|
97
105
|
function AddressForm() {
|
|
106
|
+
const [index, setIndex] = useState<TrigramIndex | null>(null)
|
|
107
|
+
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
loadDefaultIndex().then(setIndex)
|
|
110
|
+
}, [])
|
|
111
|
+
|
|
98
112
|
const { query, setQuery, suggestions, isOpen, selectSuggestion, clear } =
|
|
99
113
|
useThaiAddressAutocomplete({
|
|
100
|
-
index:
|
|
114
|
+
index: index!,
|
|
101
115
|
limit: 10, // default: 10
|
|
102
116
|
debounce: 200, // default: 200ms
|
|
103
117
|
threshold: 0.4, // default: 0.4
|
|
@@ -105,6 +119,8 @@ function AddressForm() {
|
|
|
105
119
|
|
|
106
120
|
const [address, setAddress] = useState(null)
|
|
107
121
|
|
|
122
|
+
if (!index) return <p>กำลังโหลด...</p>
|
|
123
|
+
|
|
108
124
|
return (
|
|
109
125
|
<div>
|
|
110
126
|
<input
|
|
@@ -128,9 +144,9 @@ function AddressForm() {
|
|
|
128
144
|
|
|
129
145
|
{address && (
|
|
130
146
|
<div>
|
|
131
|
-
<p>ตำบล: {address.tambon}</p>
|
|
132
|
-
<p>อำเภอ: {address.amphure}</p>
|
|
133
|
-
<p>จังหวัด: {address.province}</p>
|
|
147
|
+
<p>ตำบล: {address.tambon} ({address.tambonEn})</p>
|
|
148
|
+
<p>อำเภอ: {address.amphure} ({address.amphureEn})</p>
|
|
149
|
+
<p>จังหวัด: {address.province} ({address.provinceEn})</p>
|
|
134
150
|
<p>รหัสไปรษณีย์: {address.zipCode}</p>
|
|
135
151
|
</div>
|
|
136
152
|
)}
|
|
@@ -156,16 +172,19 @@ function AddressForm() {
|
|
|
156
172
|
|
|
157
173
|
```ts
|
|
158
174
|
import express from 'express'
|
|
159
|
-
import {
|
|
175
|
+
import { loadDefaultIndex } from 'thaizip/data'
|
|
160
176
|
import { searchThaiAddress, formatThaiAddressSuggestion } from 'thaizip'
|
|
161
177
|
|
|
162
178
|
const app = express()
|
|
163
179
|
|
|
180
|
+
// โหลด index ครั้งเดียวตอน startup
|
|
181
|
+
const index = await loadDefaultIndex()
|
|
182
|
+
|
|
164
183
|
app.get('/address/search', (req, res) => {
|
|
165
184
|
const query = String(req.query.q ?? '')
|
|
166
185
|
if (!query) return res.json([])
|
|
167
186
|
|
|
168
|
-
const results = searchThaiAddress(
|
|
187
|
+
const results = searchThaiAddress(index, query, { limit: 10 })
|
|
169
188
|
res.json(results.map(formatThaiAddressSuggestion))
|
|
170
189
|
})
|
|
171
190
|
|
|
@@ -204,26 +223,49 @@ const index = buildThaiAddressIndex({
|
|
|
204
223
|
```ts
|
|
205
224
|
type ThaiAddressSuggestion = {
|
|
206
225
|
id: string
|
|
207
|
-
label: string
|
|
226
|
+
label: string // "ตำบล > อำเภอ > จังหวัด XXXXX"
|
|
208
227
|
tambon: string
|
|
228
|
+
tambonEn: string
|
|
209
229
|
amphure: string
|
|
230
|
+
amphureEn: string
|
|
210
231
|
province: string
|
|
232
|
+
provinceEn: string
|
|
211
233
|
zipCode: string
|
|
212
234
|
}
|
|
213
235
|
|
|
214
236
|
type ResolvedThaiAddress = {
|
|
215
|
-
tambon: string
|
|
216
|
-
|
|
237
|
+
tambon: string // alias: subdistrict
|
|
238
|
+
tambonEn: string // alias: subdistrictEn
|
|
239
|
+
amphure: string // alias: district
|
|
240
|
+
amphureEn: string // alias: districtEn
|
|
217
241
|
province: string
|
|
218
|
-
|
|
242
|
+
provinceEn: string
|
|
243
|
+
zipCode: string // alias: postalCode
|
|
219
244
|
subdistrict: string
|
|
245
|
+
subdistrictEn: string
|
|
220
246
|
district: string
|
|
247
|
+
districtEn: string
|
|
221
248
|
postalCode: string
|
|
222
249
|
}
|
|
223
250
|
```
|
|
224
251
|
|
|
225
252
|
---
|
|
226
253
|
|
|
254
|
+
## Migration จาก v0.x
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
// v0.x (sync)
|
|
258
|
+
import { defaultIndex } from 'thaizip/data'
|
|
259
|
+
const results = searchThaiAddress(defaultIndex, query)
|
|
260
|
+
|
|
261
|
+
// v1.0 (async)
|
|
262
|
+
import { loadDefaultIndex } from 'thaizip/data'
|
|
263
|
+
const index = await loadDefaultIndex() // cache อัตโนมัติ
|
|
264
|
+
const results = searchThaiAddress(index, query)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
227
269
|
## License
|
|
228
270
|
|
|
229
271
|
MIT
|