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 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,23 @@ 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')
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(defaultIndex, 'ลาดพร้าว', {
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: 'ลาดพร้าว', subdistrict: 'ลาดพร้าว',
79
- // amphure: 'ลาดพร้าว', district: 'ลาดพร้าว',
80
- // province: 'กรุงเทพมหานคร',
81
- // zipCode: '10230', postalCode: '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 { defaultIndex } from 'thaizip/data'
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: defaultIndex,
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 { defaultIndex } from 'thaizip/data'
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(defaultIndex, query, { limit: 10 })
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 // "ตำบล > อำเภอ > จังหวัด XXXXX"
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 // alias: subdistrict
216
- amphure: string // alias: district
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
- zipCode: string // alias: postalCode
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