thaizip 0.1.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 ADDED
@@ -0,0 +1,229 @@
1
+ # thaizip
2
+
3
+ ไลบรารี autocomplete ที่อยู่ไทยแบบ fuzzy search รวดเร็ว รองรับทั้ง Vanilla JS และ React
4
+
5
+ - ค้นหาได้ทั้งภาษาไทย ภาษาอังกฤษ และรหัสไปรษณีย์
6
+ - Fuzzy search — ไม่ต้องใส่วรรณยุกต์ก็ค้นหาได้ เช่น "ลาดพราว" เจอ "ลาดพร้าว"
7
+ - ไม่มี dependency นอกจาก React (optional)
8
+ - Index สร้างไว้ล่วงหน้า ไม่มีต้นทุนตอน runtime
9
+ - รองรับ ESM และ CJS
10
+
11
+ ---
12
+
13
+ ## ติดตั้ง
14
+
15
+ ```bash
16
+ npm install thaizip
17
+ ```
18
+
19
+ ถ้าใช้กับ React ต้องมี React >= 18 เป็น peer dependency อยู่แล้ว ไม่ต้องติดตั้งเพิ่ม
20
+
21
+ ---
22
+
23
+ ## การใช้งานพื้นฐาน (Vanilla JS / TypeScript)
24
+
25
+ ### ค้นหาที่อยู่
26
+
27
+ ```ts
28
+ import { defaultIndex } from 'thaizip/data'
29
+ import { searchThaiAddress } from 'thaizip'
30
+
31
+ // ค้นหาด้วยชื่อตำบล/อำเภอ/จังหวัด
32
+ const results = searchThaiAddress(defaultIndex, 'ลาดพร้าว')
33
+
34
+ // ค้นหาด้วยรหัสไปรษณีย์
35
+ const results = searchThaiAddress(defaultIndex, '10900')
36
+
37
+ // ค้นหาด้วยภาษาอังกฤษ
38
+ const results = searchThaiAddress(defaultIndex, 'chiang mai')
39
+
40
+ console.log(results)
41
+ // [{ tambonId, tambonNameTh, tambonNameEn, amphureId, amphureNameTh, ... zipCode }, ...]
42
+ ```
43
+
44
+ ### ตัวเลือก (options)
45
+
46
+ ```ts
47
+ const results = searchThaiAddress(defaultIndex, 'ลาดพร้าว', {
48
+ limit: 5, // จำนวนผลลัพธ์สูงสุด (default: 10)
49
+ threshold: 0.4, // ความแม่นยำขั้นต่ำ 0–1 (default: 0.4)
50
+ })
51
+ ```
52
+
53
+ ### แปลงผลลัพธ์เป็นรูปแบบต่าง ๆ
54
+
55
+ **`formatThaiAddressSuggestion`** — ใช้แสดงใน dropdown
56
+
57
+ ```ts
58
+ import { formatThaiAddressSuggestion } from 'thaizip'
59
+
60
+ const suggestion = formatThaiAddressSuggestion(results[0])
61
+ // {
62
+ // id: '100101',
63
+ // label: 'ลาดพร้าว > ลาดพร้าว > กรุงเทพมหานคร 10230',
64
+ // tambon: 'ลาดพร้าว',
65
+ // amphure: 'ลาดพร้าว',
66
+ // province: 'กรุงเทพมหานคร',
67
+ // zipCode: '10230',
68
+ // }
69
+ ```
70
+
71
+ **`resolveThaiAddress`** — ใช้บันทึกข้อมูลหลังผู้ใช้เลือก
72
+
73
+ ```ts
74
+ import { resolveThaiAddress } from 'thaizip'
75
+
76
+ const resolved = resolveThaiAddress(results[0])
77
+ // {
78
+ // tambon: 'ลาดพร้าว', subdistrict: 'ลาดพร้าว',
79
+ // amphure: 'ลาดพร้าว', district: 'ลาดพร้าว',
80
+ // province: 'กรุงเทพมหานคร',
81
+ // zipCode: '10230', postalCode: '10230',
82
+ // }
83
+ ```
84
+
85
+ ---
86
+
87
+ ## การใช้งานกับ React
88
+
89
+ ### `useThaiAddressAutocomplete`
90
+
91
+ Hook นี้จัดการ state ของ query, suggestions, debounce ให้ทั้งหมด
92
+
93
+ ```tsx
94
+ import { defaultIndex } from 'thaizip/data'
95
+ import { useThaiAddressAutocomplete } from 'thaizip'
96
+
97
+ function AddressForm() {
98
+ const { query, setQuery, suggestions, isOpen, selectSuggestion, clear } =
99
+ useThaiAddressAutocomplete({
100
+ index: defaultIndex,
101
+ limit: 10, // default: 10
102
+ debounce: 200, // default: 200ms
103
+ threshold: 0.4, // default: 0.4
104
+ })
105
+
106
+ const [address, setAddress] = useState(null)
107
+
108
+ return (
109
+ <div>
110
+ <input
111
+ value={query}
112
+ onChange={(e) => setQuery(e.target.value)}
113
+ placeholder="พิมพ์ตำบล อำเภอ จังหวัด หรือรหัสไปรษณีย์"
114
+ />
115
+
116
+ {isOpen && (
117
+ <ul>
118
+ {suggestions.map((s) => (
119
+ <li key={s.id} onClick={() => {
120
+ const resolved = selectSuggestion(s)
121
+ setAddress(resolved)
122
+ }}>
123
+ {s.label}
124
+ </li>
125
+ ))}
126
+ </ul>
127
+ )}
128
+
129
+ {address && (
130
+ <div>
131
+ <p>ตำบล: {address.tambon}</p>
132
+ <p>อำเภอ: {address.amphure}</p>
133
+ <p>จังหวัด: {address.province}</p>
134
+ <p>รหัสไปรษณีย์: {address.zipCode}</p>
135
+ </div>
136
+ )}
137
+ </div>
138
+ )
139
+ }
140
+ ```
141
+
142
+ ### Return ของ hook
143
+
144
+ | ค่า | ประเภท | คำอธิบาย |
145
+ |---|---|---|
146
+ | `query` | `string` | ข้อความที่ผู้ใช้พิมพ์อยู่ |
147
+ | `setQuery` | `(value: string) => void` | อัปเดต query |
148
+ | `suggestions` | `ThaiAddressSuggestion[]` | รายการผลลัพธ์ที่แสดงใน dropdown |
149
+ | `isOpen` | `boolean` | `true` เมื่อมี query และมี suggestions |
150
+ | `selectSuggestion` | `(item) => ResolvedThaiAddress` | เลือก suggestion แล้วได้ข้อมูลที่อยู่ครบ |
151
+ | `clear` | `() => void` | ล้าง query และ suggestions ทั้งหมด |
152
+
153
+ ---
154
+
155
+ ## การใช้งานกับ Node.js / Express
156
+
157
+ ```ts
158
+ import express from 'express'
159
+ import { defaultIndex } from 'thaizip/data'
160
+ import { searchThaiAddress, formatThaiAddressSuggestion } from 'thaizip'
161
+
162
+ const app = express()
163
+
164
+ app.get('/address/search', (req, res) => {
165
+ const query = String(req.query.q ?? '')
166
+ if (!query) return res.json([])
167
+
168
+ const results = searchThaiAddress(defaultIndex, query, { limit: 10 })
169
+ res.json(results.map(formatThaiAddressSuggestion))
170
+ })
171
+
172
+ app.listen(3000)
173
+ ```
174
+
175
+ เรียกใช้งาน:
176
+ ```
177
+ GET /address/search?q=ลาดพร้าว
178
+ GET /address/search?q=10900
179
+ ```
180
+
181
+ ---
182
+
183
+ ## ใช้ข้อมูล Index ของตัวเอง
184
+
185
+ หากต้องการสร้าง index จากข้อมูลที่กำหนดเอง
186
+
187
+ ```ts
188
+ import { buildThaiAddressIndex } from 'thaizip'
189
+
190
+ const index = buildThaiAddressIndex({
191
+ geographies: [...],
192
+ provinces: [...],
193
+ amphures: [...],
194
+ tambons: [...],
195
+ })
196
+ ```
197
+
198
+ รูปแบบข้อมูล raw ดูได้จาก type `RawData`, `RawProvince`, `RawAmphure`, `RawTambon` ที่ export มาจาก library
199
+
200
+ ---
201
+
202
+ ## Types หลัก
203
+
204
+ ```ts
205
+ type ThaiAddressSuggestion = {
206
+ id: string
207
+ label: string // "ตำบล > อำเภอ > จังหวัด XXXXX"
208
+ tambon: string
209
+ amphure: string
210
+ province: string
211
+ zipCode: string
212
+ }
213
+
214
+ type ResolvedThaiAddress = {
215
+ tambon: string // alias: subdistrict
216
+ amphure: string // alias: district
217
+ province: string
218
+ zipCode: string // alias: postalCode
219
+ subdistrict: string
220
+ district: string
221
+ postalCode: string
222
+ }
223
+ ```
224
+
225
+ ---
226
+
227
+ ## License
228
+
229
+ MIT