thaizip 0.6.0 → 0.7.3
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.md +92 -263
- package/dist/data.cjs +98 -9
- package/dist/data.d.cts +25 -0
- package/dist/data.d.ts +25 -0
- package/dist/data.js +98 -9
- package/dist/index.cjs +380 -29
- package/dist/index.d.cts +187 -2
- package/dist/index.d.ts +187 -2
- package/dist/index.js +375 -30
- package/dist/react.cjs +267 -50
- package/dist/react.d.cts +49 -1
- package/dist/react.d.ts +49 -1
- package/dist/react.js +268 -51
- package/package.json +8 -5
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Narathip Thakham
|
|
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.md
CHANGED
|
@@ -1,337 +1,166 @@
|
|
|
1
1
|
# thaizip
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Fast fuzzy autocomplete for Thai addresses — subdistrict, district, province, postal code. Thai and English input, zero runtime dependencies, React optional.
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
- Fuzzy search — ไม่ต้องใส่วรรณยุกต์ก็ค้นหาได้ เช่น "ลาดพราว" เจอ "ลาดพร้าว"
|
|
7
|
-
- ไม่มี dependency นอกจาก React (optional)
|
|
8
|
-
- โหลดข้อมูลแบบ async — ไม่บล็อก initial bundle (~132 KB gzip)
|
|
9
|
-
- รองรับ ESM และ CJS
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## ติดตั้ง
|
|
5
|
+
**Docs:** https://naay99999.github.io/thai-zip/ (ไทย / [English](https://naay99999.github.io/thai-zip/en/))
|
|
14
6
|
|
|
15
7
|
```bash
|
|
16
8
|
npm install thaizip
|
|
17
9
|
```
|
|
18
10
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Package exports
|
|
24
|
-
|
|
25
|
-
| import path | เนื้อหา |
|
|
11
|
+
| import path | contents |
|
|
26
12
|
|---|---|
|
|
27
|
-
| `thaizip` | core functions + types
|
|
28
|
-
| `thaizip/react` | `useThaiAddressAutocomplete`
|
|
29
|
-
| `thaizip/data` | `loadDefaultIndex`, `clearDefaultIndex` |
|
|
30
|
-
|
|
31
|
-
---
|
|
13
|
+
| `thaizip` | core functions + types (no React code, 4.4 KB gzip) |
|
|
14
|
+
| `thaizip/react` | `useThaiAddressAutocomplete` (ships `"use client"`) |
|
|
15
|
+
| `thaizip/data` | `loadDefaultIndex`, `clearDefaultIndex` (132 KB gzip) |
|
|
32
16
|
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
### โหลด index และค้นหาที่อยู่
|
|
17
|
+
## Quick start
|
|
36
18
|
|
|
37
19
|
```ts
|
|
38
20
|
import { loadDefaultIndex } from 'thaizip/data'
|
|
39
|
-
import { searchThaiAddress } from 'thaizip'
|
|
40
|
-
|
|
41
|
-
// โหลด index ครั้งแรก ~200ms (cached หลังจากนั้น)
|
|
42
|
-
const index = await loadDefaultIndex()
|
|
21
|
+
import { searchThaiAddress, formatThaiAddressSuggestion, resolveThaiAddress } from 'thaizip'
|
|
43
22
|
|
|
44
|
-
//
|
|
45
|
-
const results = searchThaiAddress(index, 'ลาดพร้าว')
|
|
23
|
+
const index = await loadDefaultIndex() // ~40ms of synchronous work, cached after
|
|
46
24
|
|
|
47
|
-
|
|
48
|
-
|
|
25
|
+
searchThaiAddress(index, 'ลาดพร้าว')
|
|
26
|
+
searchThaiAddress(index, 'bang rak')
|
|
27
|
+
searchThaiAddress(index, '10500')
|
|
49
28
|
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// ⚠️ ไม่รองรับ: ค้นหาแบบรวม text + รหัสไปรษณีย์ในครั้งเดียว (เช่น "ลาดพร้าว 10900")
|
|
54
|
-
// ให้ค้นหาด้วยชื่อสถานที่ หรือรหัสไปรษณีย์ แยกกัน
|
|
55
|
-
|
|
56
|
-
console.log(results)
|
|
57
|
-
// [{ tambonId, tambonNameTh, tambonNameEn, amphureId, amphureNameTh, ... zipCode }, ...]
|
|
29
|
+
formatThaiAddressSuggestion(record) // for the dropdown
|
|
30
|
+
formatThaiAddressSuggestion(record, { locale: 'en' })
|
|
31
|
+
resolveThaiAddress(record) // for saving
|
|
58
32
|
```
|
|
59
33
|
|
|
60
|
-
|
|
34
|
+
Call `loadDefaultIndex()` at mount or route load — deferring it to the user's first keystroke costs ~2 dropped frames.
|
|
35
|
+
|
|
36
|
+
## Search
|
|
61
37
|
|
|
62
38
|
```ts
|
|
63
|
-
|
|
64
|
-
limit:
|
|
65
|
-
threshold: 0.4,
|
|
39
|
+
searchThaiAddress(index, query, {
|
|
40
|
+
limit: 10, // text queries only
|
|
41
|
+
threshold: 0.4, // match quality 0–1
|
|
42
|
+
zipLimit: Infinity, // all-digit queries — unlimited by default
|
|
43
|
+
romanizationAliases: true, // expand non-RTGS spellings
|
|
66
44
|
})
|
|
67
45
|
```
|
|
68
46
|
|
|
69
|
-
|
|
47
|
+
Results rank by trigram score, then by how well the query matches the subdistrict's **own** name (exact → prefix → substring), then alphabetically. That second key is what keeps ตำบลลาดพร้าว above the other subdistricts that merely sit inside เขตลาดพร้าว.
|
|
70
48
|
|
|
71
|
-
|
|
49
|
+
> Combined text + zip in one query (`"ลาดพร้าว 10900"`) is not supported — search by name or zip separately.
|
|
72
50
|
|
|
73
|
-
|
|
74
|
-
import { formatThaiAddressSuggestion } from 'thaizip'
|
|
75
|
-
|
|
76
|
-
const suggestion = formatThaiAddressSuggestion(results[0])
|
|
77
|
-
// {
|
|
78
|
-
// id: '100101',
|
|
79
|
-
// label: 'ลาดพร้าว > ลาดพร้าว > กรุงเทพมหานคร 10230',
|
|
80
|
-
// tambon: 'ลาดพร้าว', tambonEn: 'Lat Phrao',
|
|
81
|
-
// amphure: 'ลาดพร้าว', amphureEn: 'Lat Phrao',
|
|
82
|
-
// province: 'กรุงเทพมหานคร', provinceEn: 'Bangkok',
|
|
83
|
-
// zipCode: '10230',
|
|
84
|
-
// }
|
|
85
|
-
```
|
|
51
|
+
### Postal codes
|
|
86
52
|
|
|
87
|
-
|
|
53
|
+
One Thai postal code can cover many subdistricts — `45000` covers 33, and 230 of the 953 codes cover more than 10 — so `zipLimit` defaults to unlimited rather than silently truncating at `limit`.
|
|
88
54
|
|
|
89
55
|
```ts
|
|
90
|
-
import {
|
|
91
|
-
|
|
92
|
-
const resolved = resolveThaiAddress(results[0])
|
|
93
|
-
// {
|
|
94
|
-
// tambon: 'ลาดพร้าว', tambonEn: 'Lat Phrao',
|
|
95
|
-
// amphure: 'ลาดพร้าว', amphureEn: 'Lat Phrao',
|
|
96
|
-
// province: 'กรุงเทพมหานคร', provinceEn: 'Bangkok',
|
|
97
|
-
// zipCode: '10230',
|
|
98
|
-
// subdistrict: 'ลาดพร้าว', subdistrictEn: 'Lat Phrao',
|
|
99
|
-
// district: 'ลาดพร้าว', districtEn: 'Lat Phrao',
|
|
100
|
-
// postalCode: '10230',
|
|
101
|
-
// }
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## การใช้งานกับ React
|
|
56
|
+
import { lookupByZipCode } from 'thaizip'
|
|
107
57
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
58
|
+
lookupByZipCode(index, '45000') // exact
|
|
59
|
+
lookupByZipCode(index, '450') // prefix
|
|
60
|
+
```
|
|
111
61
|
|
|
112
|
-
|
|
113
|
-
import { useState, useEffect } from 'react'
|
|
114
|
-
import { loadDefaultIndex } from 'thaizip/data'
|
|
115
|
-
import { useThaiAddressAutocomplete } from 'thaizip/react'
|
|
116
|
-
import type { TrigramIndex, ResolvedThaiAddress } from 'thaizip/react'
|
|
62
|
+
### English input
|
|
117
63
|
|
|
118
|
-
|
|
119
|
-
function AddressPage() {
|
|
120
|
-
const [index, setIndex] = useState<TrigramIndex | null>(null)
|
|
64
|
+
The dataset indexes official RTGS spellings, so `bang rak` and `chatuchak` work directly. 87 common non-RTGS spellings are mapped on first: `lardprao` → `lat phrao`, `ladkrabang` → `lat krabang`, `krungthep` → `bangkok`. It is a curated dictionary, not a transliterator — unlisted spellings still miss. Opt out with `romanizationAliases: false`.
|
|
121
65
|
|
|
122
|
-
|
|
123
|
-
loadDefaultIndex().then(setIndex)
|
|
124
|
-
}, [])
|
|
66
|
+
### Cascade dropdowns
|
|
125
67
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
68
|
+
```ts
|
|
69
|
+
import { listProvinces, listAmphures, listTambons } from 'thaizip'
|
|
129
70
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
index,
|
|
134
|
-
limit: 10, // default: 10
|
|
135
|
-
debounce: 200, // default: 200ms
|
|
136
|
-
threshold: 0.4, // default: 0.4
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
const [address, setAddress] = useState<ResolvedThaiAddress | null>(null)
|
|
140
|
-
|
|
141
|
-
return (
|
|
142
|
-
<div>
|
|
143
|
-
<input
|
|
144
|
-
value={query}
|
|
145
|
-
onChange={(e) => setQuery(e.target.value)}
|
|
146
|
-
placeholder="พิมพ์ตำบล อำเภอ จังหวัด หรือรหัสไปรษณีย์"
|
|
147
|
-
/>
|
|
148
|
-
|
|
149
|
-
{isOpen && (
|
|
150
|
-
<ul>
|
|
151
|
-
{suggestions.map((s) => (
|
|
152
|
-
<li key={s.id} onClick={() => {
|
|
153
|
-
const resolved = selectSuggestion(s)
|
|
154
|
-
setAddress(resolved)
|
|
155
|
-
}}>
|
|
156
|
-
{s.label}
|
|
157
|
-
</li>
|
|
158
|
-
))}
|
|
159
|
-
</ul>
|
|
160
|
-
)}
|
|
161
|
-
|
|
162
|
-
{address && (
|
|
163
|
-
<div>
|
|
164
|
-
<p>ตำบล: {address.tambon} ({address.tambonEn})</p>
|
|
165
|
-
<p>อำเภอ: {address.amphure} ({address.amphureEn})</p>
|
|
166
|
-
<p>จังหวัด: {address.province} ({address.provinceEn})</p>
|
|
167
|
-
<p>รหัสไปรษณีย์: {address.zipCode}</p>
|
|
168
|
-
</div>
|
|
169
|
-
)}
|
|
170
|
-
</div>
|
|
171
|
-
)
|
|
172
|
-
}
|
|
71
|
+
listProvinces(index) // 77, sorted by Thai name
|
|
72
|
+
listAmphures(index, provinceId)
|
|
73
|
+
listTambons(index, amphureId) // each with its zipCode
|
|
173
74
|
```
|
|
174
75
|
|
|
175
|
-
|
|
76
|
+
Backed by pre-built groupings, not scans over all 7,385 records. Unknown ids return `[]`.
|
|
176
77
|
|
|
177
|
-
|
|
178
|
-
|---|---|---|
|
|
179
|
-
| `query` | `string` | ข้อความที่ผู้ใช้พิมพ์อยู่ |
|
|
180
|
-
| `setQuery` | `(value: string) => void` | อัปเดต query |
|
|
181
|
-
| `suggestions` | `ThaiAddressSuggestion[]` | รายการผลลัพธ์ที่แสดงใน dropdown |
|
|
182
|
-
| `isOpen` | `boolean` | `true` เมื่อมี query และมี suggestions |
|
|
183
|
-
| `selectSuggestion` | `(item) => ResolvedThaiAddress` | เลือก suggestion แล้วได้ข้อมูลที่อยู่ครบ |
|
|
184
|
-
| `clear` | `() => void` | ล้าง query และ suggestions ทั้งหมด |
|
|
78
|
+
## React
|
|
185
79
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
## การใช้งานกับ Node.js / Express
|
|
189
|
-
|
|
190
|
-
```ts
|
|
191
|
-
import express from 'express'
|
|
192
|
-
import { loadDefaultIndex } from 'thaizip/data'
|
|
193
|
-
import { searchThaiAddress, formatThaiAddressSuggestion } from 'thaizip'
|
|
80
|
+
```tsx
|
|
81
|
+
import { useThaiAddressAutocomplete } from 'thaizip/react'
|
|
194
82
|
|
|
195
|
-
const
|
|
83
|
+
const { query, setQuery, setQuerySilent, suggestions, isOpen, selectSuggestion, clear } =
|
|
84
|
+
useThaiAddressAutocomplete({ index })
|
|
85
|
+
```
|
|
196
86
|
|
|
197
|
-
|
|
198
|
-
const index = await loadDefaultIndex()
|
|
87
|
+
Options: `index`, `limit`, `debounce` (200ms), `threshold`, `zipLimit`, `locale`, `initialQuery`, `onSelect`.
|
|
199
88
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
89
|
+
| value | description |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `query` / `setQuery` | input value; `setQuery` searches |
|
|
92
|
+
| `setQuerySilent` | set the value **without** searching or reopening the dropdown |
|
|
93
|
+
| `suggestions` | `ThaiAddressSuggestion[]` |
|
|
94
|
+
| `isOpen` | `query` is non-empty and suggestions exist |
|
|
95
|
+
| `selectSuggestion` | `(item) => ResolvedThaiAddress \| null` — clears suggestions, leaves `query` alone; `null` if the item is stale |
|
|
96
|
+
| `clear` | reset query and suggestions |
|
|
203
97
|
|
|
204
|
-
|
|
205
|
-
res.json(results.map(formatThaiAddressSuggestion))
|
|
206
|
-
})
|
|
98
|
+
### Controlled forms
|
|
207
99
|
|
|
208
|
-
|
|
209
|
-
```
|
|
100
|
+
`selectSuggestion` leaves `query` untouched by design. To echo the choice back into the input use `setQuerySilent` — plain `setQuery` would immediately reopen the dropdown:
|
|
210
101
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
102
|
+
```tsx
|
|
103
|
+
const handlePick = (s: ThaiAddressSuggestion) => {
|
|
104
|
+
const address = selectSuggestion(s)
|
|
105
|
+
if (!address) return
|
|
106
|
+
setQuerySilent(s.label)
|
|
107
|
+
form.setValue('address', address)
|
|
108
|
+
}
|
|
215
109
|
```
|
|
216
110
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
## ใช้ข้อมูล Index ของตัวเอง
|
|
111
|
+
Editing a saved address? Pass `initialQuery` rather than calling `setQuery` in an effect.
|
|
220
112
|
|
|
221
|
-
|
|
113
|
+
### Accessibility
|
|
222
114
|
|
|
223
|
-
|
|
224
|
-
import { buildThaiAddressIndex } from 'thaizip'
|
|
225
|
-
|
|
226
|
-
const index = buildThaiAddressIndex({
|
|
227
|
-
provinces: [...],
|
|
228
|
-
amphures: [...],
|
|
229
|
-
tambons: [...],
|
|
230
|
-
// geographies ไม่จำเป็นต้องระบุ (ไม่ได้ใช้งานโดย indexer)
|
|
231
|
-
}, {
|
|
232
|
-
// รับ callback เมื่อ tambon ถูกข้ามเนื่องจากไม่พบ amphure/province
|
|
233
|
-
onSkip: (tambon) => console.warn('skipped tambon:', tambon.id),
|
|
234
|
-
})
|
|
235
|
-
```
|
|
115
|
+
The hook owns query and suggestion state only. Keyboard navigation and ARIA combobox semantics are yours — `npx react-thaizip add autocomplete` scaffolds a component that already has them.
|
|
236
116
|
|
|
237
|
-
|
|
117
|
+
## Custom data
|
|
238
118
|
|
|
239
119
|
```ts
|
|
240
|
-
import {
|
|
120
|
+
import { buildThaiAddressIndex, validateRawData } from 'thaizip'
|
|
241
121
|
|
|
242
|
-
|
|
122
|
+
const index = buildThaiAddressIndex({ provinces, amphures, tambons }, {
|
|
123
|
+
onSkip: (tambon) => console.warn('skipped:', tambon.id),
|
|
124
|
+
validate: true, // default
|
|
125
|
+
})
|
|
243
126
|
```
|
|
244
127
|
|
|
245
|
-
|
|
128
|
+
Input is validated by default, so a stray non-string field fails with `[thaizip] tambon 100404: expected string for name_th, got number` instead of crashing inside the normalizer. It costs nothing measurable on a full-size dataset. `validateRawData(data)` runs the same checks standalone.
|
|
246
129
|
|
|
247
|
-
|
|
130
|
+
`RawData` is meant to be trusted, application-controlled input — your own dataset, not arbitrary end-user uploads. `buildThaiAddressIndex` has no built-in cap on row count or field length; build cost scales linearly with total input size, but an unbounded or maliciously oversized payload (e.g. an admin importer fed directly to this function) can still cost real time and memory with nothing to stop it. If you ever build an index from untrusted input, enforce your own size limits (row count, field length) before calling `buildThaiAddressIndex`.
|
|
248
131
|
|
|
249
|
-
|
|
132
|
+
Types: `RawData`, `RawProvince`, `RawAmphure`, `RawTambon`.
|
|
250
133
|
|
|
251
|
-
Types
|
|
134
|
+
## Types
|
|
252
135
|
|
|
253
136
|
```ts
|
|
254
|
-
// จาก thaizip หรือ thaizip/react
|
|
255
137
|
type ThaiAddressSuggestion = {
|
|
256
138
|
id: string
|
|
257
|
-
label: string
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
amphureEn: string
|
|
262
|
-
province: string
|
|
263
|
-
provinceEn: string
|
|
139
|
+
label: string // follows `locale`, Thai by default
|
|
140
|
+
labelTh: string
|
|
141
|
+
labelEn: string
|
|
142
|
+
tambon: string; tambonEn: string
|
|
143
|
+
amphure: string; amphureEn: string
|
|
144
|
+
province: string; provinceEn: string
|
|
264
145
|
zipCode: string
|
|
265
146
|
}
|
|
266
147
|
|
|
267
|
-
// จาก thaizip หรือ thaizip/react
|
|
268
148
|
type ResolvedThaiAddress = {
|
|
269
|
-
tambon: string
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
zipCode: string // alias: postalCode
|
|
276
|
-
subdistrict: string
|
|
277
|
-
subdistrictEn: string
|
|
278
|
-
district: string
|
|
279
|
-
districtEn: string
|
|
149
|
+
tambon: string; tambonEn: string // alias: subdistrict / subdistrictEn
|
|
150
|
+
amphure: string; amphureEn: string // alias: district / districtEn
|
|
151
|
+
province: string; provinceEn: string
|
|
152
|
+
zipCode: string // alias: postalCode
|
|
153
|
+
subdistrict: string; subdistrictEn: string
|
|
154
|
+
district: string; districtEn: string
|
|
280
155
|
postalCode: string
|
|
281
156
|
}
|
|
282
157
|
```
|
|
283
158
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
## Migration จาก v0.5.x → v1.0.0
|
|
287
|
-
|
|
288
|
-
### hook ย้ายไปอยู่ที่ `thaizip/react`
|
|
289
|
-
|
|
290
|
-
```ts
|
|
291
|
-
// v0.5.x
|
|
292
|
-
import { useThaiAddressAutocomplete } from 'thaizip'
|
|
293
|
-
import type { TrigramIndex } from 'thaizip'
|
|
294
|
-
|
|
295
|
-
// v1.0.0
|
|
296
|
-
import { useThaiAddressAutocomplete } from 'thaizip/react'
|
|
297
|
-
import type { TrigramIndex, ResolvedThaiAddress, ThaiAddressSuggestion } from 'thaizip/react'
|
|
298
|
-
// หรือยังคง import types จาก 'thaizip' ได้เช่นเดิม
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### `clearDefaultIndex` ย้ายไปอยู่ที่ `thaizip/data`
|
|
302
|
-
|
|
303
|
-
```ts
|
|
304
|
-
// v0.5.x
|
|
305
|
-
import { clearDefaultIndex } from 'thaizip'
|
|
306
|
-
|
|
307
|
-
// v1.0.0
|
|
308
|
-
import { clearDefaultIndex } from 'thaizip/data'
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
---
|
|
312
|
-
|
|
313
|
-
## Migration จาก v0.2.x → v0.3.0+
|
|
314
|
-
|
|
315
|
-
```ts
|
|
316
|
-
// v0.2.x (sync, bundle ~630KB)
|
|
317
|
-
import { defaultIndex } from 'thaizip/data'
|
|
318
|
-
const results = searchThaiAddress(defaultIndex, query)
|
|
319
|
-
|
|
320
|
-
// v0.3.0+ (async, bundle ~132KB gzip)
|
|
321
|
-
import { loadDefaultIndex } from 'thaizip/data'
|
|
322
|
-
const index = await loadDefaultIndex() // cache อัตโนมัติ หลังจากโหลดครั้งแรก
|
|
323
|
-
const results = searchThaiAddress(index, query)
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
---
|
|
327
|
-
|
|
328
|
-
## ข้อมูลที่อยู่
|
|
329
|
-
|
|
330
|
-
ข้อมูลอ้างอิงจากการแบ่งเขตการปกครองของไทย (77 จังหวัด, 920 อำเภอ, ~7,385 ตำบล)
|
|
159
|
+
## Data
|
|
331
160
|
|
|
332
|
-
|
|
161
|
+
77 provinces, 918 districts, 7,385 subdistricts. Records whose parent district or province is soft-deleted are excluded automatically.
|
|
333
162
|
|
|
334
|
-
|
|
163
|
+
`searchThaiAddress` is pure and framework-free — it works unchanged in Node, Vue, Svelte, or vanilla JS.
|
|
335
164
|
|
|
336
165
|
## License
|
|
337
166
|
|