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 CHANGED
@@ -5,7 +5,7 @@
5
5
  - ค้นหาได้ทั้งภาษาไทย ภาษาอังกฤษ และรหัสไปรษณีย์
6
6
  - Fuzzy search — ไม่ต้องใส่วรรณยุกต์ก็ค้นหาได้ เช่น "ลาดพราว" เจอ "ลาดพร้าว"
7
7
  - ไม่มี dependency นอกจาก React (optional)
8
- - Index สร้างไว้ล่วงหน้า ไม่มีต้นทุนตอน runtime
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 { defaultIndex } from 'thaizip/data'
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(defaultIndex, 'ลาดพร้าว')
35
+ const results = searchThaiAddress(index, 'ลาดพร้าว')
33
36
 
34
37
  // ค้นหาด้วยรหัสไปรษณีย์
35
- const results = searchThaiAddress(defaultIndex, '10900')
38
+ const results2 = searchThaiAddress(index, '10900')
36
39
 
37
40
  // ค้นหาด้วยภาษาอังกฤษ
38
- const results = searchThaiAddress(defaultIndex, 'chiang mai')
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(defaultIndex, 'ลาดพร้าว', {
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: 'ลาดพร้าว', subdistrict: 'ลาดพร้าว',
79
- // amphure: 'ลาดพร้าว', district: 'ลาดพร้าว',
80
- // province: 'กรุงเทพมหานคร',
81
- // zipCode: '10230', postalCode: '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 { defaultIndex } from 'thaizip/data'
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
- function AddressForm() {
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: defaultIndex,
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 { defaultIndex } from 'thaizip/data'
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(defaultIndex, query, { limit: 10 })
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 // "ตำบล > อำเภอ > จังหวัด XXXXX"
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 // alias: subdistrict
216
- amphure: string // alias: district
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
- zipCode: string // alias: postalCode
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