thaizip 0.2.1 → 0.4.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 +84 -27
- package/dist/data.cjs +132 -11
- package/dist/data.d.cts +2 -2
- package/dist/data.d.ts +2 -2
- package/dist/data.js +132 -11
- package/dist/index.cjs +22 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +22 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
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,26 @@ 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')
|
|
42
|
+
|
|
43
|
+
// ⚠️ ไม่รองรับ: ค้นหาแบบรวม text + รหัสไปรษณีย์ในครั้งเดียว (เช่น "ลาดพร้าว 10900")
|
|
44
|
+
// ให้ค้นหาด้วยชื่อสถานที่ หรือรหัสไปรษณีย์ แยกกัน
|
|
39
45
|
|
|
40
46
|
console.log(results)
|
|
41
47
|
// [{ tambonId, tambonNameTh, tambonNameEn, amphureId, amphureNameTh, ... zipCode }, ...]
|
|
@@ -44,7 +50,7 @@ console.log(results)
|
|
|
44
50
|
### ตัวเลือก (options)
|
|
45
51
|
|
|
46
52
|
```ts
|
|
47
|
-
const results = searchThaiAddress(
|
|
53
|
+
const results = searchThaiAddress(index, 'ลาดพร้าว', {
|
|
48
54
|
limit: 5, // จำนวนผลลัพธ์สูงสุด (default: 10)
|
|
49
55
|
threshold: 0.4, // ความแม่นยำขั้นต่ำ 0–1 (default: 0.4)
|
|
50
56
|
})
|
|
@@ -61,9 +67,9 @@ const suggestion = formatThaiAddressSuggestion(results[0])
|
|
|
61
67
|
// {
|
|
62
68
|
// id: '100101',
|
|
63
69
|
// label: 'ลาดพร้าว > ลาดพร้าว > กรุงเทพมหานคร 10230',
|
|
64
|
-
// tambon: 'ลาดพร้าว',
|
|
65
|
-
// amphure: 'ลาดพร้าว',
|
|
66
|
-
// province: 'กรุงเทพมหานคร',
|
|
70
|
+
// tambon: 'ลาดพร้าว', tambonEn: 'Lat Phrao',
|
|
71
|
+
// amphure: 'ลาดพร้าว', amphureEn: 'Lat Phrao',
|
|
72
|
+
// province: 'กรุงเทพมหานคร', provinceEn: 'Bangkok',
|
|
67
73
|
// zipCode: '10230',
|
|
68
74
|
// }
|
|
69
75
|
```
|
|
@@ -75,10 +81,13 @@ import { resolveThaiAddress } from 'thaizip'
|
|
|
75
81
|
|
|
76
82
|
const resolved = resolveThaiAddress(results[0])
|
|
77
83
|
// {
|
|
78
|
-
// tambon: 'ลาดพร้าว',
|
|
79
|
-
// amphure: 'ลาดพร้าว',
|
|
80
|
-
// province: 'กรุงเทพมหานคร',
|
|
81
|
-
// zipCode: '10230',
|
|
84
|
+
// tambon: 'ลาดพร้าว', tambonEn: 'Lat Phrao',
|
|
85
|
+
// amphure: 'ลาดพร้าว', amphureEn: 'Lat Phrao',
|
|
86
|
+
// province: 'กรุงเทพมหานคร', provinceEn: 'Bangkok',
|
|
87
|
+
// zipCode: '10230',
|
|
88
|
+
// subdistrict: 'ลาดพร้าว', subdistrictEn: 'Lat Phrao',
|
|
89
|
+
// district: 'ลาดพร้าว', districtEn: 'Lat Phrao',
|
|
90
|
+
// postalCode: '10230',
|
|
82
91
|
// }
|
|
83
92
|
```
|
|
84
93
|
|
|
@@ -91,13 +100,27 @@ const resolved = resolveThaiAddress(results[0])
|
|
|
91
100
|
Hook นี้จัดการ state ของ query, suggestions, debounce ให้ทั้งหมด
|
|
92
101
|
|
|
93
102
|
```tsx
|
|
94
|
-
import {
|
|
103
|
+
import { useState, useEffect } from 'react'
|
|
104
|
+
import { loadDefaultIndex } from 'thaizip/data'
|
|
95
105
|
import { useThaiAddressAutocomplete } from 'thaizip'
|
|
106
|
+
import type { TrigramIndex } from 'thaizip'
|
|
107
|
+
|
|
108
|
+
// แนะนำ: แยก loading และ form ออกจากกัน เพื่อให้ hook เรียกหลัง index พร้อมแล้วเสมอ
|
|
109
|
+
function AddressPage() {
|
|
110
|
+
const [index, setIndex] = useState<TrigramIndex | null>(null)
|
|
96
111
|
|
|
97
|
-
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
loadDefaultIndex().then(setIndex)
|
|
114
|
+
}, [])
|
|
115
|
+
|
|
116
|
+
if (!index) return <p>กำลังโหลด...</p>
|
|
117
|
+
return <AddressForm index={index} />
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function AddressForm({ index }: { index: TrigramIndex }) {
|
|
98
121
|
const { query, setQuery, suggestions, isOpen, selectSuggestion, clear } =
|
|
99
122
|
useThaiAddressAutocomplete({
|
|
100
|
-
index
|
|
123
|
+
index,
|
|
101
124
|
limit: 10, // default: 10
|
|
102
125
|
debounce: 200, // default: 200ms
|
|
103
126
|
threshold: 0.4, // default: 0.4
|
|
@@ -128,9 +151,9 @@ function AddressForm() {
|
|
|
128
151
|
|
|
129
152
|
{address && (
|
|
130
153
|
<div>
|
|
131
|
-
<p>ตำบล: {address.tambon}</p>
|
|
132
|
-
<p>อำเภอ: {address.amphure}</p>
|
|
133
|
-
<p>จังหวัด: {address.province}</p>
|
|
154
|
+
<p>ตำบล: {address.tambon} ({address.tambonEn})</p>
|
|
155
|
+
<p>อำเภอ: {address.amphure} ({address.amphureEn})</p>
|
|
156
|
+
<p>จังหวัด: {address.province} ({address.provinceEn})</p>
|
|
134
157
|
<p>รหัสไปรษณีย์: {address.zipCode}</p>
|
|
135
158
|
</div>
|
|
136
159
|
)}
|
|
@@ -156,16 +179,19 @@ function AddressForm() {
|
|
|
156
179
|
|
|
157
180
|
```ts
|
|
158
181
|
import express from 'express'
|
|
159
|
-
import {
|
|
182
|
+
import { loadDefaultIndex } from 'thaizip/data'
|
|
160
183
|
import { searchThaiAddress, formatThaiAddressSuggestion } from 'thaizip'
|
|
161
184
|
|
|
162
185
|
const app = express()
|
|
163
186
|
|
|
187
|
+
// โหลด index ครั้งเดียวตอน startup
|
|
188
|
+
const index = await loadDefaultIndex()
|
|
189
|
+
|
|
164
190
|
app.get('/address/search', (req, res) => {
|
|
165
191
|
const query = String(req.query.q ?? '')
|
|
166
192
|
if (!query) return res.json([])
|
|
167
193
|
|
|
168
|
-
const results = searchThaiAddress(
|
|
194
|
+
const results = searchThaiAddress(index, query, { limit: 10 })
|
|
169
195
|
res.json(results.map(formatThaiAddressSuggestion))
|
|
170
196
|
})
|
|
171
197
|
|
|
@@ -188,10 +214,10 @@ GET /address/search?q=10900
|
|
|
188
214
|
import { buildThaiAddressIndex } from 'thaizip'
|
|
189
215
|
|
|
190
216
|
const index = buildThaiAddressIndex({
|
|
191
|
-
geographies: [...],
|
|
192
217
|
provinces: [...],
|
|
193
218
|
amphures: [...],
|
|
194
219
|
tambons: [...],
|
|
220
|
+
// geographies ไม่จำเป็นต้องระบุ (ไม่ได้ใช้งานโดย indexer)
|
|
195
221
|
})
|
|
196
222
|
```
|
|
197
223
|
|
|
@@ -204,26 +230,57 @@ const index = buildThaiAddressIndex({
|
|
|
204
230
|
```ts
|
|
205
231
|
type ThaiAddressSuggestion = {
|
|
206
232
|
id: string
|
|
207
|
-
label: string
|
|
233
|
+
label: string // "ตำบล > อำเภอ > จังหวัด XXXXX"
|
|
208
234
|
tambon: string
|
|
235
|
+
tambonEn: string
|
|
209
236
|
amphure: string
|
|
237
|
+
amphureEn: string
|
|
210
238
|
province: string
|
|
239
|
+
provinceEn: string
|
|
211
240
|
zipCode: string
|
|
212
241
|
}
|
|
213
242
|
|
|
214
243
|
type ResolvedThaiAddress = {
|
|
215
|
-
tambon: string
|
|
216
|
-
|
|
244
|
+
tambon: string // alias: subdistrict
|
|
245
|
+
tambonEn: string // alias: subdistrictEn
|
|
246
|
+
amphure: string // alias: district
|
|
247
|
+
amphureEn: string // alias: districtEn
|
|
217
248
|
province: string
|
|
218
|
-
|
|
249
|
+
provinceEn: string
|
|
250
|
+
zipCode: string // alias: postalCode
|
|
219
251
|
subdistrict: string
|
|
252
|
+
subdistrictEn: string
|
|
220
253
|
district: string
|
|
254
|
+
districtEn: string
|
|
221
255
|
postalCode: string
|
|
222
256
|
}
|
|
223
257
|
```
|
|
224
258
|
|
|
225
259
|
---
|
|
226
260
|
|
|
261
|
+
## Migration จาก v0.2.x → v0.3.0+
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
// v0.2.x (sync, bundle ~630KB)
|
|
265
|
+
import { defaultIndex } from 'thaizip/data'
|
|
266
|
+
const results = searchThaiAddress(defaultIndex, query)
|
|
267
|
+
|
|
268
|
+
// v0.3.0+ (async, bundle ~132KB gzip)
|
|
269
|
+
import { loadDefaultIndex } from 'thaizip/data'
|
|
270
|
+
const index = await loadDefaultIndex() // cache อัตโนมัติ หลังจากโหลดครั้งแรก
|
|
271
|
+
const results = searchThaiAddress(index, query)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## ข้อมูลที่อยู่
|
|
277
|
+
|
|
278
|
+
ข้อมูลอ้างอิงจากการแบ่งเขตการปกครองของไทย (77 จังหวัด, 920 อำเภอ, ~7,385 ตำบล)
|
|
279
|
+
|
|
280
|
+
ตำบลที่ยังมีสถานะ active แต่อ้างอิงอำเภอที่ถูก soft-deleted จะถูกข้ามโดย index โดยอัตโนมัติ พร้อมแสดง `console.warn` ให้ทราบ
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
227
284
|
## License
|
|
228
285
|
|
|
229
286
|
MIT
|