thaizip 0.5.1 → 0.7.2

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/dist/index.js CHANGED
@@ -1,8 +1,6 @@
1
- import { useState, useRef, useCallback, useEffect } from 'react';
2
-
3
1
  // src/core/normalizer.ts
4
- var TONE_MARKS = /[\u0E48-\u0E4B\u0E47\u0E4C]/g;
5
- var ADDRESS_PREFIXES = /^(จังหวัด|อำเภอ|ตำบล|แขวง|เขต)/;
2
+ var TONE_MARKS = /[่-๋็์]/g;
3
+ var ADDRESS_PREFIXES = /^(จังหวัด|อำเภอ|ตำบล|แขวง|เขต|จ\.|อ\.|ต\.|ข\.)/;
6
4
  function normalizeThaiAddressText(input) {
7
5
  if (!input) return "";
8
6
  let text = input.trim();
@@ -30,7 +28,56 @@ function extractTrigramsNormalized(text) {
30
28
  }
31
29
 
32
30
  // src/core/indexer.ts
33
- function buildThaiAddressIndex(data) {
31
+ function typeErr(table, id, field, expected, value) {
32
+ return new TypeError(`[thaizip] ${table} ${id}: expected ${expected} for ${field}, got ${typeof value}`);
33
+ }
34
+ function validateRawData(data) {
35
+ const { provinces, amphures, tambons } = data;
36
+ for (let i = 0; i < provinces.length; i++) {
37
+ const p = provinces[i];
38
+ if (typeof p.id !== "number") throw typeErr("province", p.id, "id", "number", p.id);
39
+ if (typeof p.name_th !== "string") throw typeErr("province", p.id, "name_th", "string", p.name_th);
40
+ if (typeof p.name_en !== "string") throw typeErr("province", p.id, "name_en", "string", p.name_en);
41
+ }
42
+ for (let i = 0; i < amphures.length; i++) {
43
+ const a = amphures[i];
44
+ if (typeof a.id !== "number") throw typeErr("amphure", a.id, "id", "number", a.id);
45
+ if (typeof a.name_th !== "string") throw typeErr("amphure", a.id, "name_th", "string", a.name_th);
46
+ if (typeof a.name_en !== "string") throw typeErr("amphure", a.id, "name_en", "string", a.name_en);
47
+ if (typeof a.province_id !== "number") throw typeErr("amphure", a.id, "province_id", "number", a.province_id);
48
+ }
49
+ for (let i = 0; i < tambons.length; i++) {
50
+ const t = tambons[i];
51
+ if (typeof t.id !== "number") throw typeErr("tambon", t.id, "id", "number", t.id);
52
+ if (typeof t.name_th !== "string") throw typeErr("tambon", t.id, "name_th", "string", t.name_th);
53
+ if (typeof t.name_en !== "string") throw typeErr("tambon", t.id, "name_en", "string", t.name_en);
54
+ const zipType = typeof t.zip_code;
55
+ if (zipType !== "string" && zipType !== "number") {
56
+ throw typeErr("tambon", t.id, "zip_code", "string or number", t.zip_code);
57
+ }
58
+ if (typeof t.amphure_id !== "number") throw typeErr("tambon", t.id, "amphure_id", "number", t.amphure_id);
59
+ }
60
+ }
61
+ function addTrigrams(map, trigrams, idx) {
62
+ for (const trigram of trigrams) {
63
+ let set = map.get(trigram);
64
+ if (!set) {
65
+ set = /* @__PURE__ */ new Set();
66
+ map.set(trigram, set);
67
+ }
68
+ set.add(idx);
69
+ }
70
+ }
71
+ function combinedTrigrams(nameTh, nameEn) {
72
+ const s = /* @__PURE__ */ new Set();
73
+ for (const t of extractTrigrams(nameTh)) s.add(t);
74
+ for (const t of extractTrigrams(nameEn)) s.add(t);
75
+ return s;
76
+ }
77
+ function buildThaiAddressIndex(data, options) {
78
+ if (options?.validate !== false) {
79
+ validateRawData(data);
80
+ }
34
81
  const { provinces, amphures, tambons } = data;
35
82
  const provMap = new Map(
36
83
  provinces.filter((p) => !p.deleted_at).map((p) => [p.id, p])
@@ -38,20 +85,33 @@ function buildThaiAddressIndex(data) {
38
85
  const ampMap = new Map(
39
86
  amphures.filter((a) => !a.deleted_at).map((a) => [a.id, a])
40
87
  );
88
+ const provTrigrams = /* @__PURE__ */ new Map();
89
+ for (const [id, prov] of provMap) {
90
+ provTrigrams.set(id, combinedTrigrams(prov.name_th, prov.name_en));
91
+ }
92
+ const ampTrigrams = /* @__PURE__ */ new Map();
93
+ for (const [id, amp] of ampMap) {
94
+ ampTrigrams.set(id, combinedTrigrams(amp.name_th, amp.name_en));
95
+ }
41
96
  const records = [];
42
97
  const map = /* @__PURE__ */ new Map();
43
98
  const zipIndex = /* @__PURE__ */ new Map();
99
+ const normTambon = [];
100
+ const normTambonEn = [];
101
+ const byProvince = /* @__PURE__ */ new Map();
102
+ const byAmphure = /* @__PURE__ */ new Map();
44
103
  for (const tambon of tambons) {
45
104
  if (tambon.deleted_at) continue;
46
105
  const amphure = ampMap.get(tambon.amphure_id);
47
106
  if (!amphure) {
48
- console.warn(
49
- `[thaizip] skipping tambon id=${tambon.id} (${tambon.name_th}): amphure_id=${tambon.amphure_id} not found or deleted`
50
- );
107
+ if (options?.onSkip) options.onSkip(tambon);
51
108
  continue;
52
109
  }
53
110
  const province = provMap.get(amphure.province_id);
54
- if (!province) continue;
111
+ if (!province) {
112
+ if (options?.onSkip) options.onSkip(tambon);
113
+ continue;
114
+ }
55
115
  const record = {
56
116
  provinceId: province.id,
57
117
  provinceNameTh: province.name_th,
@@ -69,56 +129,195 @@ function buildThaiAddressIndex(data) {
69
129
  const existing = zipIndex.get(record.zipCode);
70
130
  if (existing) existing.push(idx);
71
131
  else zipIndex.set(record.zipCode, [idx]);
72
- const fields = [
73
- record.tambonNameTh,
74
- record.tambonNameEn,
75
- record.amphureNameTh,
76
- record.amphureNameEn,
77
- record.provinceNameTh,
78
- record.provinceNameEn,
79
- record.zipCode
80
- ];
81
- for (const field of fields) {
82
- for (const trigram of extractTrigrams(field)) {
83
- let set = map.get(trigram);
84
- if (!set) {
85
- set = /* @__PURE__ */ new Set();
86
- map.set(trigram, set);
87
- }
88
- set.add(idx);
89
- }
90
- }
132
+ const provList = byProvince.get(province.id);
133
+ if (provList) provList.push(idx);
134
+ else byProvince.set(province.id, [idx]);
135
+ const ampList = byAmphure.get(amphure.id);
136
+ if (ampList) ampList.push(idx);
137
+ else byAmphure.set(amphure.id, [idx]);
138
+ const normTh = normalizeThaiAddressText(record.tambonNameTh);
139
+ normTambon.push(normTh);
140
+ addTrigrams(map, extractTrigramsNormalized(normTh), idx);
141
+ const normEn = normalizeThaiAddressText(record.tambonNameEn);
142
+ normTambonEn.push(normEn);
143
+ addTrigrams(map, extractTrigramsNormalized(normEn), idx);
144
+ addTrigrams(map, extractTrigrams(record.zipCode), idx);
145
+ addTrigrams(map, provTrigrams.get(province.id), idx);
146
+ addTrigrams(map, ampTrigrams.get(amphure.id), idx);
91
147
  }
92
- return { map, records, zipIndex };
148
+ return { map, records, zipIndex, normTambon, normTambonEn, byProvince, byAmphure };
149
+ }
150
+
151
+ // src/core/romanize.ts
152
+ var ALIASES = /* @__PURE__ */ new Map([
153
+ // --- Bangkok khet (districts) — concatenated ("no space") forms ---------
154
+ ["phranakhon", "phra nakhon"],
155
+ ["nongchok", "nong chok"],
156
+ ["bangrak", "bang rak"],
157
+ ["bangkhen", "bang khen"],
158
+ ["bangkapi", "bang kapi"],
159
+ ["pathumwan", "pathum wan"],
160
+ ["patumwan", "pathum wan"],
161
+ ["pomprap", "pom prap sattru phai"],
162
+ ["phrakhanong", "phra khanong"],
163
+ ["minburi", "min buri"],
164
+ ["latkrabang", "lat krabang"],
165
+ ["ladkrabang", "lat krabang"],
166
+ ["yannawa", "yan nawa"],
167
+ ["phayathai", "phaya thai"],
168
+ ["thonburi", "thon buri"],
169
+ ["bangkokyai", "bangkok yai"],
170
+ ["huaikhwang", "huai khwang"],
171
+ ["huaykhwang", "huai khwang"],
172
+ ["huaykwang", "huai khwang"],
173
+ ["khlongsan", "khlong san"],
174
+ ["klongsan", "khlong san"],
175
+ ["talingchan", "taling chan"],
176
+ ["bangkoknoi", "bangkok noi"],
177
+ ["bangkhunthian", "bang khun thian"],
178
+ ["phasicharoen", "phasi charoen"],
179
+ ["nongkhaem", "nong khaem"],
180
+ ["ratburana", "rat burana"],
181
+ ["bangphlat", "bang phlat"],
182
+ ["dindaeng", "din daeng"],
183
+ ["buengkum", "bueng kum"],
184
+ ["bangsue", "bang sue"],
185
+ ["bangkholaem", "bang kho laem"],
186
+ ["khlongtoei", "khlong toei"],
187
+ ["klongtoei", "khlong toei"],
188
+ ["klongtoey", "khlong toei"],
189
+ ["khlongtoey", "khlong toei"],
190
+ ["suanluang", "suan luang"],
191
+ ["chomthong", "chom thong"],
192
+ ["donmueang", "don mueang"],
193
+ ["donmuang", "don mueang"],
194
+ ["latphrao", "lat phrao"],
195
+ ["ladprao", "lat phrao"],
196
+ ["lardprao", "lat phrao"],
197
+ ["lat prao", "lat phrao"],
198
+ ["bangkhae", "bang khae"],
199
+ ["laksi", "lak si"],
200
+ ["saimai", "sai mai"],
201
+ ["khannayao", "khan na yao"],
202
+ ["saphansung", "saphan sung"],
203
+ ["wangthonglang", "wang thonglang"],
204
+ ["khlongsamwa", "khlong sam wa"],
205
+ ["klongsamwa", "khlong sam wa"],
206
+ ["bangna", "bang na"],
207
+ ["thawiwatthana", "thawi watthana"],
208
+ ["thungkhru", "thung khru"],
209
+ ["bangbon", "bang bon"],
210
+ // --- Bangkok area / street nicknames with a common misspelling ----------
211
+ ["sathorn", "sathon"],
212
+ ["wattana", "watthana"],
213
+ ["silom", "si lom"],
214
+ // --- Provinces and other high-traffic areas ------------------------------
215
+ ["krungthep", "bangkok"],
216
+ ["korat", "nakhon ratchasima"],
217
+ ["nakornratchasima", "nakhon ratchasima"],
218
+ ["chiangmai", "chiang mai"],
219
+ ["chiangrai", "chiang rai"],
220
+ ["pathumthani", "pathum thani"],
221
+ ["patumthani", "pathum thani"],
222
+ ["samutprakan", "samut prakan"],
223
+ ["samutsakhon", "samut sakhon"],
224
+ ["samutsongkhram", "samut songkhram"],
225
+ ["nakhonpathom", "nakhon pathom"],
226
+ ["nakhonsawan", "nakhon sawan"],
227
+ ["nakhonsithammarat", "nakhon si thammarat"],
228
+ ["prachuapkhirikhan", "prachuap khiri khan"],
229
+ ["huahin", "hua hin"],
230
+ ["hatyai", "hat yai"],
231
+ ["hadyai", "hat yai"],
232
+ ["had yai", "hat yai"],
233
+ ["lopburi", "loburi"],
234
+ ["lop buri", "loburi"],
235
+ ["buengkan", "buogkan"],
236
+ ["bungkan", "buogkan"],
237
+ ["bung kan", "buogkan"],
238
+ ["udonthani", "udon thani"],
239
+ ["khonkaen", "khon kaen"],
240
+ ["suphanburi", "suphan buri"],
241
+ ["nongkhai", "nong khai"],
242
+ ["buriram", "buri ram"]
243
+ ]);
244
+ var NOISE_WORDS_RE = /\b(?:sub[- ]?district|district|province|changwat|amphoe|amphur)\b/g;
245
+ var WHITESPACE_RE = /\s+/g;
246
+ function cleanup(text) {
247
+ const stripped = text.replace(NOISE_WORDS_RE, " ").replace(WHITESPACE_RE, " ").trim();
248
+ return stripped.length > 0 ? stripped : text;
93
249
  }
94
- function clearDefaultIndex() {
250
+ function applyRomanizationAliases(normalized) {
251
+ if (!normalized) return normalized;
252
+ const direct = ALIASES.get(normalized);
253
+ if (direct !== void 0) return direct;
254
+ const cleaned = cleanup(normalized);
255
+ if (cleaned === normalized) return normalized;
256
+ const aliasedCleaned = ALIASES.get(cleaned);
257
+ return aliasedCleaned !== void 0 ? aliasedCleaned : cleaned;
95
258
  }
96
259
 
97
260
  // src/core/search.ts
98
261
  var ZIP_CODE_RE = /^\d+$/;
262
+ var HAS_LATIN_RE = /[a-z]/i;
263
+ var TH_COLLATOR = new Intl.Collator("th");
264
+ function compareZip(a, b) {
265
+ if (a < b) return -1;
266
+ if (a > b) return 1;
267
+ return 0;
268
+ }
269
+ function sortZipMatches(matches, exactZip) {
270
+ matches.sort((a, b) => {
271
+ if (a.zipCode === exactZip && b.zipCode !== exactZip) return -1;
272
+ if (b.zipCode === exactZip && a.zipCode !== exactZip) return 1;
273
+ return compareZip(a.zipCode, b.zipCode);
274
+ });
275
+ return matches;
276
+ }
277
+ function lookupByZipCode(index, zip, options) {
278
+ if (!index || !zip) return [];
279
+ const normalized = zip.trim();
280
+ if (!ZIP_CODE_RE.test(normalized) || normalized.length < 2) return [];
281
+ const zipLimit = options?.zipLimit ?? Infinity;
282
+ const matches = [];
283
+ for (const [z, indices] of index.zipIndex) {
284
+ if (z.startsWith(normalized)) {
285
+ for (const idx of indices) matches.push(index.records[idx]);
286
+ }
287
+ }
288
+ sortZipMatches(matches, normalized);
289
+ return matches.slice(0, zipLimit);
290
+ }
291
+ function rankAgainstName(name, query) {
292
+ if (name === void 0 || name.length === 0) return 0;
293
+ if (name === query) return 3;
294
+ if (name.startsWith(query)) return 2;
295
+ if (name.includes(query)) return 1;
296
+ return 0;
297
+ }
298
+ function computeMatchRank(index, idx, query) {
299
+ const th = rankAgainstName(index.normTambon?.[idx], query);
300
+ if (th === 3) return 3;
301
+ const en = rankAgainstName(index.normTambonEn?.[idx], query);
302
+ return en > th ? en : th;
303
+ }
99
304
  function searchThaiAddress(index, query, options) {
100
305
  const limit = options?.limit ?? 10;
101
306
  const threshold = options?.threshold ?? 0.4;
102
307
  if (!index || !query) return [];
308
+ if (query.length > 1e3) return [];
103
309
  const normalized = normalizeThaiAddressText(query);
104
310
  if (normalized.length === 0) return [];
105
311
  if (normalized.length > 300) return [];
106
312
  if (ZIP_CODE_RE.test(normalized)) {
107
313
  if (normalized.length < 2) return [];
108
- const matches = [];
109
- for (const [zip, indices] of index.zipIndex) {
110
- if (zip.startsWith(normalized)) {
111
- for (const idx of indices) matches.push(index.records[idx]);
112
- }
113
- }
114
- matches.sort((a, b) => {
115
- if (a.zipCode === normalized && b.zipCode !== normalized) return -1;
116
- if (b.zipCode === normalized && a.zipCode !== normalized) return 1;
117
- return a.zipCode.localeCompare(b.zipCode);
314
+ return lookupByZipCode(index, normalized, {
315
+ zipLimit: options?.zipLimit ?? Infinity
118
316
  });
119
- return matches.slice(0, limit);
120
317
  }
121
- const queryTrigrams = extractTrigramsNormalized(normalized);
318
+ if (normalized.length < 3) return [];
319
+ const searchText = options?.romanizationAliases !== false && HAS_LATIN_RE.test(normalized) ? applyRomanizationAliases(normalized) : normalized;
320
+ const queryTrigrams = extractTrigramsNormalized(searchText);
122
321
  const hits = /* @__PURE__ */ new Map();
123
322
  for (const trigram of queryTrigrams) {
124
323
  const candidates = index.map.get(trigram);
@@ -131,23 +330,98 @@ function searchThaiAddress(index, query, options) {
131
330
  for (const [idx, count] of hits) {
132
331
  const score = count / queryTrigrams.size;
133
332
  if (score >= threshold) {
134
- scored.push({ idx, score });
333
+ scored.push({ idx, score, matchRank: computeMatchRank(index, idx, searchText) });
135
334
  }
136
335
  }
137
336
  scored.sort((a, b) => {
138
337
  if (b.score !== a.score) return b.score - a.score;
338
+ return b.matchRank - a.matchRank;
339
+ });
340
+ const windowSize = Math.max(limit * 4, 50);
341
+ const window = scored.slice(0, windowSize);
342
+ window.sort((a, b) => {
343
+ if (b.score !== a.score) return b.score - a.score;
344
+ if (b.matchRank !== a.matchRank) return b.matchRank - a.matchRank;
139
345
  const ra = index.records[a.idx];
140
346
  const rb = index.records[b.idx];
141
- return ra.provinceNameTh.localeCompare(rb.provinceNameTh) || ra.amphureNameTh.localeCompare(rb.amphureNameTh) || ra.tambonNameTh.localeCompare(rb.tambonNameTh);
347
+ return TH_COLLATOR.compare(ra.provinceNameTh, rb.provinceNameTh) || TH_COLLATOR.compare(ra.amphureNameTh, rb.amphureNameTh) || TH_COLLATOR.compare(ra.tambonNameTh, rb.tambonNameTh);
348
+ });
349
+ return window.slice(0, limit).map(({ idx }) => index.records[idx]);
350
+ }
351
+
352
+ // src/core/enumerate.ts
353
+ var thCollator = new Intl.Collator("th");
354
+ function byNameTh(a, b) {
355
+ return thCollator.compare(a.nameTh, b.nameTh);
356
+ }
357
+ function listProvinces(index) {
358
+ const seen = /* @__PURE__ */ new Map();
359
+ if (index.byProvince) {
360
+ for (const [provinceId, recordIndices] of index.byProvince) {
361
+ if (seen.has(provinceId) || recordIndices.length === 0) continue;
362
+ const r = index.records[recordIndices[0]];
363
+ seen.set(provinceId, { id: provinceId, nameTh: r.provinceNameTh, nameEn: r.provinceNameEn });
364
+ }
365
+ } else {
366
+ for (const r of index.records) {
367
+ if (!seen.has(r.provinceId)) {
368
+ seen.set(r.provinceId, { id: r.provinceId, nameTh: r.provinceNameTh, nameEn: r.provinceNameEn });
369
+ }
370
+ }
371
+ }
372
+ return Array.from(seen.values()).sort(byNameTh);
373
+ }
374
+ function listAmphures(index, provinceId) {
375
+ const seen = /* @__PURE__ */ new Map();
376
+ const addFrom = (r) => {
377
+ if (!seen.has(r.amphureId)) {
378
+ seen.set(r.amphureId, {
379
+ id: r.amphureId,
380
+ nameTh: r.amphureNameTh,
381
+ nameEn: r.amphureNameEn,
382
+ provinceId: r.provinceId
383
+ });
384
+ }
385
+ };
386
+ if (index.byProvince) {
387
+ const recordIndices = index.byProvince.get(provinceId);
388
+ if (!recordIndices) return [];
389
+ for (const idx of recordIndices) addFrom(index.records[idx]);
390
+ } else {
391
+ for (const r of index.records) {
392
+ if (r.provinceId === provinceId) addFrom(r);
393
+ }
394
+ }
395
+ return Array.from(seen.values()).sort(byNameTh);
396
+ }
397
+ function listTambons(index, amphureId) {
398
+ const toSummary = (r) => ({
399
+ id: r.tambonId,
400
+ nameTh: r.tambonNameTh,
401
+ nameEn: r.tambonNameEn,
402
+ amphureId: r.amphureId,
403
+ zipCode: r.zipCode
142
404
  });
143
- return scored.slice(0, limit).map(({ idx }) => index.records[idx]);
405
+ let result;
406
+ if (index.byAmphure) {
407
+ const recordIndices = index.byAmphure.get(amphureId);
408
+ if (!recordIndices) return [];
409
+ result = recordIndices.map((idx) => toSummary(index.records[idx]));
410
+ } else {
411
+ result = index.records.filter((r) => r.amphureId === amphureId).map(toSummary);
412
+ }
413
+ return result.sort(byNameTh);
144
414
  }
145
415
 
146
416
  // src/core/formatter.ts
147
- function formatThaiAddressSuggestion(record) {
417
+ function formatThaiAddressSuggestion(record, options) {
418
+ const labelTh = `${record.tambonNameTh} > ${record.amphureNameTh} > ${record.provinceNameTh} ${record.zipCode}`;
419
+ const labelEn = `${record.tambonNameEn} > ${record.amphureNameEn} > ${record.provinceNameEn} ${record.zipCode}`;
148
420
  return {
149
421
  id: String(record.tambonId),
150
- label: `${record.tambonNameTh} > ${record.amphureNameTh} > ${record.provinceNameTh} ${record.zipCode}`,
422
+ label: options?.locale === "en" ? labelEn : labelTh,
423
+ labelTh,
424
+ labelEn,
151
425
  tambon: record.tambonNameTh,
152
426
  tambonEn: record.tambonNameEn,
153
427
  amphure: record.amphureNameTh,
@@ -175,63 +449,7 @@ function resolveThaiAddress(record) {
175
449
  postalCode: record.zipCode
176
450
  };
177
451
  }
178
- function useThaiAddressAutocomplete(options) {
179
- const { index, limit = 10, debounce: debounceMs = 200, threshold = 0.4 } = options;
180
- const [query, setQueryState] = useState("");
181
- const [suggestions, setSuggestions] = useState([]);
182
- const timerRef = useRef(null);
183
- const matchedRecordsMapRef = useRef(/* @__PURE__ */ new Map());
184
- const setQuery = useCallback((value) => {
185
- setQueryState(value);
186
- }, []);
187
- useEffect(() => {
188
- if (timerRef.current) clearTimeout(timerRef.current);
189
- if (query.length === 0) {
190
- setSuggestions([]);
191
- matchedRecordsMapRef.current = /* @__PURE__ */ new Map();
192
- return;
193
- }
194
- timerRef.current = setTimeout(() => {
195
- const records = searchThaiAddress(index, query, { limit, threshold });
196
- const formatted = records.map(formatThaiAddressSuggestion);
197
- const recordMap = /* @__PURE__ */ new Map();
198
- for (let i = 0; i < records.length; i++) {
199
- recordMap.set(formatted[i].id, records[i]);
200
- }
201
- matchedRecordsMapRef.current = recordMap;
202
- setSuggestions(formatted);
203
- }, debounceMs);
204
- return () => {
205
- if (timerRef.current) clearTimeout(timerRef.current);
206
- };
207
- }, [query, index, limit, threshold, debounceMs]);
208
- const selectSuggestion = useCallback(
209
- (item) => {
210
- const record = matchedRecordsMapRef.current.get(item.id);
211
- if (!record) {
212
- throw new Error(`[thaizip] No record found for suggestion id "${item.id}". Make sure to use suggestions returned by this hook.`);
213
- }
214
- setSuggestions([]);
215
- matchedRecordsMapRef.current = /* @__PURE__ */ new Map();
216
- return resolveThaiAddress(record);
217
- },
218
- []
219
- );
220
- const clear = useCallback(() => {
221
- setQueryState("");
222
- setSuggestions([]);
223
- matchedRecordsMapRef.current = /* @__PURE__ */ new Map();
224
- }, []);
225
- return {
226
- query,
227
- setQuery,
228
- suggestions,
229
- isOpen: query.length > 0 && suggestions.length > 0,
230
- selectSuggestion,
231
- clear
232
- };
233
- }
234
452
 
235
- export { buildThaiAddressIndex, clearDefaultIndex, formatThaiAddressSuggestion, normalizeThaiAddressText, resolveThaiAddress, searchThaiAddress, useThaiAddressAutocomplete };
453
+ export { applyRomanizationAliases, buildThaiAddressIndex, formatThaiAddressSuggestion, listAmphures, listProvinces, listTambons, lookupByZipCode, normalizeThaiAddressText, resolveThaiAddress, searchThaiAddress, validateRawData };
236
454
  //# sourceMappingURL=index.js.map
237
455
  //# sourceMappingURL=index.js.map