@placeslayer/sdk-react 1.0.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/dist/index.cjs ADDED
@@ -0,0 +1,337 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ CitiesDropdown: () => CitiesDropdown,
24
+ useAutocomplete: () => useAutocomplete,
25
+ useCities: () => useCities,
26
+ useCountries: () => useCountries,
27
+ usePlacesLayerClient: () => usePlacesLayerClient,
28
+ useProvinces: () => useProvinces
29
+ });
30
+ module.exports = __toCommonJS(src_exports);
31
+
32
+ // src/CitiesDropdown.tsx
33
+ var import_react2 = require("react");
34
+ var import_sdk = require("@placeslayer/sdk");
35
+
36
+ // src/hooks/useAutocomplete.ts
37
+ var import_react = require("react");
38
+ var DEBOUNCE_MS = 300;
39
+ function useAutocomplete(client, countryCode, query, opts) {
40
+ const [results, setResults] = (0, import_react.useState)([]);
41
+ const [loading, setLoading] = (0, import_react.useState)(false);
42
+ const [error, setError] = (0, import_react.useState)(null);
43
+ const version = (0, import_react.useRef)(0);
44
+ const timerRef = (0, import_react.useRef)(void 0);
45
+ const delay = opts?.debounceMs ?? DEBOUNCE_MS;
46
+ const search = (0, import_react.useCallback)(() => {
47
+ const trimmed = query.trim();
48
+ if (!trimmed) {
49
+ setResults([]);
50
+ setLoading(false);
51
+ return;
52
+ }
53
+ const current = ++version.current;
54
+ setLoading(true);
55
+ client.autocomplete(countryCode, trimmed, { limit: opts?.limit }).then((data) => {
56
+ if (current === version.current) {
57
+ setResults(data);
58
+ setLoading(false);
59
+ }
60
+ }).catch((err) => {
61
+ if (current === version.current) {
62
+ setError(err instanceof Error ? err : new Error(String(err)));
63
+ setLoading(false);
64
+ }
65
+ });
66
+ }, [client, countryCode, query, opts?.limit]);
67
+ (0, import_react.useEffect)(() => {
68
+ clearTimeout(timerRef.current);
69
+ timerRef.current = setTimeout(search, delay);
70
+ return () => clearTimeout(timerRef.current);
71
+ }, [search, delay]);
72
+ return { results, loading, error };
73
+ }
74
+
75
+ // src/CitiesDropdown.tsx
76
+ var import_jsx_runtime = require("react/jsx-runtime");
77
+ function CitiesDropdown({
78
+ apiKey,
79
+ country,
80
+ province,
81
+ onSelect,
82
+ limit = 10,
83
+ lang = "default",
84
+ placeholder = "Search cities...",
85
+ className,
86
+ baseUrl,
87
+ theme
88
+ }) {
89
+ const clientRef = (0, import_react2.useRef)(null);
90
+ if (!clientRef.current || clientRef.current.apiKey !== apiKey) {
91
+ clientRef.current = new import_sdk.PlacesLayerClient({ apiKey, baseUrl });
92
+ }
93
+ const client = clientRef.current;
94
+ const [query, setQuery] = (0, import_react2.useState)("");
95
+ const [open, setOpen] = (0, import_react2.useState)(false);
96
+ const [activeIndex, setActiveIndex] = (0, import_react2.useState)(-1);
97
+ const containerRef = (0, import_react2.useRef)(null);
98
+ const prevCountry = (0, import_react2.useRef)(country);
99
+ const prevProvince = (0, import_react2.useRef)(province);
100
+ (0, import_react2.useEffect)(() => {
101
+ if (prevCountry.current !== country || prevProvince.current !== province) {
102
+ setQuery("");
103
+ setOpen(false);
104
+ prevCountry.current = country;
105
+ prevProvince.current = province;
106
+ }
107
+ }, [country, province]);
108
+ const { results, loading } = useAutocomplete(client, country, query, {
109
+ limit
110
+ });
111
+ const filtered = province ? results.filter(
112
+ (r) => r.type === "city" && r.province_code === province
113
+ ) : results;
114
+ (0, import_react2.useEffect)(() => {
115
+ const handler = (e) => {
116
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
117
+ setOpen(false);
118
+ }
119
+ };
120
+ document.addEventListener("mousedown", handler);
121
+ return () => document.removeEventListener("mousedown", handler);
122
+ }, []);
123
+ (0, import_react2.useEffect)(() => {
124
+ setActiveIndex(-1);
125
+ }, [filtered.length]);
126
+ const handleSelect = (0, import_react2.useCallback)(
127
+ async (result) => {
128
+ setQuery(result.name);
129
+ setOpen(false);
130
+ const detail = await client.city(result.country_code, result.code);
131
+ onSelect(detail);
132
+ },
133
+ [client, onSelect]
134
+ );
135
+ const handleKeyDown = (e) => {
136
+ if (!open || filtered.length === 0) return;
137
+ switch (e.key) {
138
+ case "ArrowDown":
139
+ e.preventDefault();
140
+ setActiveIndex(
141
+ (prev) => prev < filtered.length - 1 ? prev + 1 : 0
142
+ );
143
+ break;
144
+ case "ArrowUp":
145
+ e.preventDefault();
146
+ setActiveIndex(
147
+ (prev) => prev > 0 ? prev - 1 : filtered.length - 1
148
+ );
149
+ break;
150
+ case "Enter":
151
+ e.preventDefault();
152
+ if (activeIndex >= 0 && activeIndex < filtered.length) {
153
+ handleSelect(filtered[activeIndex]);
154
+ }
155
+ break;
156
+ case "Escape":
157
+ setOpen(false);
158
+ break;
159
+ }
160
+ };
161
+ const t = theme ?? {};
162
+ const borderColor = t.borderColor ?? "#d1d5db";
163
+ const borderRadius = t.borderRadius ?? "6px";
164
+ const background = t.background ?? "#fff";
165
+ const textColor = t.textColor ?? "inherit";
166
+ const secondaryTextColor = t.secondaryTextColor ?? "#6b7280";
167
+ const activeBackground = t.activeBackground ?? "#f3f4f6";
168
+ const fontSize = t.fontSize ?? "14px";
169
+ const s = {
170
+ container: { position: "relative", width: "100%" },
171
+ input: {
172
+ width: "100%",
173
+ padding: "8px 12px",
174
+ fontSize,
175
+ color: textColor,
176
+ background,
177
+ border: `1px solid ${borderColor}`,
178
+ borderRadius,
179
+ outline: "none",
180
+ boxSizing: "border-box"
181
+ },
182
+ list: {
183
+ position: "absolute",
184
+ top: "100%",
185
+ left: 0,
186
+ right: 0,
187
+ margin: "4px 0 0",
188
+ padding: 0,
189
+ listStyle: "none",
190
+ background,
191
+ border: `1px solid ${borderColor}`,
192
+ borderRadius,
193
+ boxShadow: "0 4px 6px -1px rgba(0,0,0,.1)",
194
+ maxHeight: "240px",
195
+ overflowY: "auto",
196
+ zIndex: 50
197
+ },
198
+ item: {
199
+ display: "flex",
200
+ justifyContent: "space-between",
201
+ alignItems: "center",
202
+ padding: "8px 12px",
203
+ cursor: "pointer",
204
+ fontSize,
205
+ color: textColor
206
+ },
207
+ itemActive: { background: activeBackground },
208
+ name: { fontWeight: 500 },
209
+ province: { fontSize: "12px", color: secondaryTextColor },
210
+ status: {
211
+ position: "absolute",
212
+ top: "100%",
213
+ left: 0,
214
+ right: 0,
215
+ margin: "4px 0 0",
216
+ padding: "8px 12px",
217
+ background,
218
+ border: `1px solid ${borderColor}`,
219
+ borderRadius,
220
+ fontSize,
221
+ color: secondaryTextColor
222
+ }
223
+ };
224
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: containerRef, style: s.container, className, children: [
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
226
+ "input",
227
+ {
228
+ type: "text",
229
+ value: query,
230
+ onChange: (e) => {
231
+ setQuery(e.target.value);
232
+ setOpen(true);
233
+ },
234
+ onFocus: () => query.trim() && setOpen(true),
235
+ onKeyDown: handleKeyDown,
236
+ placeholder,
237
+ style: s.input,
238
+ role: "combobox",
239
+ "aria-expanded": open,
240
+ "aria-autocomplete": "list",
241
+ "aria-activedescendant": activeIndex >= 0 ? `pl-option-${activeIndex}` : void 0
242
+ }
243
+ ),
244
+ open && filtered.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { role: "listbox", style: s.list, children: filtered.map((result, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
245
+ "li",
246
+ {
247
+ id: `pl-option-${i}`,
248
+ role: "option",
249
+ "aria-selected": i === activeIndex,
250
+ style: {
251
+ ...s.item,
252
+ ...i === activeIndex ? s.itemActive : {}
253
+ },
254
+ onMouseEnter: () => setActiveIndex(i),
255
+ onMouseDown: (e) => e.preventDefault(),
256
+ onClick: () => handleSelect(result),
257
+ children: [
258
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: s.name, children: result.name }),
259
+ result.province_name && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: s.province, children: result.province_name })
260
+ ]
261
+ },
262
+ result.code
263
+ )) }),
264
+ open && loading && filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: s.status, children: "Loading..." })
265
+ ] });
266
+ }
267
+
268
+ // src/hooks/usePlacesLayer.ts
269
+ var import_react3 = require("react");
270
+ var import_sdk2 = require("@placeslayer/sdk");
271
+ function usePlacesLayerClient(config) {
272
+ const ref = (0, import_react3.useRef)(null);
273
+ if (!ref.current || ref.current.apiKey !== config.apiKey) {
274
+ ref.current = new import_sdk2.PlacesLayerClient(config);
275
+ }
276
+ return ref.current;
277
+ }
278
+
279
+ // src/hooks/useAsync.ts
280
+ var import_react4 = require("react");
281
+ function useAsync(fn, deps) {
282
+ const [data, setData] = (0, import_react4.useState)(null);
283
+ const [loading, setLoading] = (0, import_react4.useState)(true);
284
+ const [error, setError] = (0, import_react4.useState)(null);
285
+ const version = (0, import_react4.useRef)(0);
286
+ const execute = (0, import_react4.useCallback)(() => {
287
+ const current = ++version.current;
288
+ setLoading(true);
289
+ setError(null);
290
+ fn().then((result) => {
291
+ if (current === version.current) {
292
+ setData(result);
293
+ setLoading(false);
294
+ }
295
+ }).catch((err) => {
296
+ if (current === version.current) {
297
+ setError(err instanceof Error ? err : new Error(String(err)));
298
+ setLoading(false);
299
+ }
300
+ });
301
+ }, deps);
302
+ (0, import_react4.useEffect)(() => {
303
+ execute();
304
+ }, [execute]);
305
+ return { data, loading, error, refetch: execute };
306
+ }
307
+
308
+ // src/hooks/useCountries.ts
309
+ function useCountries(client) {
310
+ return useAsync(() => client.countries(), [client]);
311
+ }
312
+
313
+ // src/hooks/useProvinces.ts
314
+ function useProvinces(client, countryCode, opts) {
315
+ return useAsync(
316
+ () => client.provinces(countryCode, opts),
317
+ [client, countryCode, opts?.native]
318
+ );
319
+ }
320
+
321
+ // src/hooks/useCities.ts
322
+ function useCities(client, countryCode, provinceCode, opts) {
323
+ return useAsync(
324
+ () => client.cities(countryCode, provinceCode, opts),
325
+ [client, countryCode, provinceCode, opts?.native]
326
+ );
327
+ }
328
+ // Annotate the CommonJS export names for ESM import in node:
329
+ 0 && (module.exports = {
330
+ CitiesDropdown,
331
+ useAutocomplete,
332
+ useCities,
333
+ useCountries,
334
+ usePlacesLayerClient,
335
+ useProvinces
336
+ });
337
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/CitiesDropdown.tsx","../src/hooks/useAutocomplete.ts","../src/hooks/usePlacesLayer.ts","../src/hooks/useAsync.ts","../src/hooks/useCountries.ts","../src/hooks/useProvinces.ts","../src/hooks/useCities.ts"],"sourcesContent":["export { CitiesDropdown, type CitiesDropdownProps, type CitiesDropdownTheme } from \"./CitiesDropdown\";\nexport { usePlacesLayerClient } from \"./hooks/usePlacesLayer\";\nexport { useCountries } from \"./hooks/useCountries\";\nexport { useProvinces } from \"./hooks/useProvinces\";\nexport { useCities } from \"./hooks/useCities\";\nexport { useAutocomplete, type AutocompleteState } from \"./hooks/useAutocomplete\";\nexport { type AsyncState } from \"./hooks/useAsync\";\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from \"react\";\nimport {\n PlacesLayerClient,\n type AutocompleteResult,\n type CityDetail,\n} from \"@placeslayer/sdk\";\nimport { useAutocomplete } from \"./hooks/useAutocomplete\";\n\nexport interface CitiesDropdownTheme {\n /** Input border color (default: \"#d1d5db\") */\n borderColor?: string;\n /** Input border radius (default: \"6px\") */\n borderRadius?: string;\n /** Dropdown background color (default: \"#fff\") */\n background?: string;\n /** Main text color (default: \"inherit\") */\n textColor?: string;\n /** Secondary text color for province labels (default: \"#6b7280\") */\n secondaryTextColor?: string;\n /** Active/hovered item background (default: \"#f3f4f6\") */\n activeBackground?: string;\n /** Input font size (default: \"14px\") */\n fontSize?: string;\n}\n\nexport interface CitiesDropdownProps {\n apiKey: string;\n country: string;\n province?: string;\n onSelect: (city: CityDetail) => void;\n limit?: number;\n lang?: \"default\" | \"native\";\n placeholder?: string;\n className?: string;\n baseUrl?: string;\n /** Customize dropdown colors and appearance */\n theme?: CitiesDropdownTheme;\n}\n\nexport function CitiesDropdown({\n apiKey,\n country,\n province,\n onSelect,\n limit = 10,\n lang = \"default\",\n placeholder = \"Search cities...\",\n className,\n baseUrl,\n theme,\n}: CitiesDropdownProps) {\n const clientRef = useRef<PlacesLayerClient | null>(null);\n if (\n !clientRef.current ||\n (clientRef.current as unknown as { apiKey: string }).apiKey !== apiKey\n ) {\n clientRef.current = new PlacesLayerClient({ apiKey, baseUrl });\n }\n const client = clientRef.current;\n\n const [query, setQuery] = useState(\"\");\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Reset input when country or province changes\n const prevCountry = useRef(country);\n const prevProvince = useRef(province);\n useEffect(() => {\n if (prevCountry.current !== country || prevProvince.current !== province) {\n setQuery(\"\");\n setOpen(false);\n prevCountry.current = country;\n prevProvince.current = province;\n }\n }, [country, province]);\n\n const { results, loading } = useAutocomplete(client, country, query, {\n limit,\n });\n\n const filtered = province\n ? results.filter(\n (r) => r.type === \"city\" && r.province_code === province\n )\n : results;\n\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(e.target as Node)\n ) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, []);\n\n useEffect(() => {\n setActiveIndex(-1);\n }, [filtered.length]);\n\n const handleSelect = useCallback(\n async (result: AutocompleteResult) => {\n setQuery(result.name);\n setOpen(false);\n\n const detail = await client.city(result.country_code, result.code);\n onSelect(detail);\n },\n [client, onSelect]\n );\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (!open || filtered.length === 0) return;\n\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setActiveIndex((prev) =>\n prev < filtered.length - 1 ? prev + 1 : 0\n );\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setActiveIndex((prev) =>\n prev > 0 ? prev - 1 : filtered.length - 1\n );\n break;\n case \"Enter\":\n e.preventDefault();\n if (activeIndex >= 0 && activeIndex < filtered.length) {\n handleSelect(filtered[activeIndex]);\n }\n break;\n case \"Escape\":\n setOpen(false);\n break;\n }\n };\n\n const t = theme ?? {};\n const borderColor = t.borderColor ?? \"#d1d5db\";\n const borderRadius = t.borderRadius ?? \"6px\";\n const background = t.background ?? \"#fff\";\n const textColor = t.textColor ?? \"inherit\";\n const secondaryTextColor = t.secondaryTextColor ?? \"#6b7280\";\n const activeBackground = t.activeBackground ?? \"#f3f4f6\";\n const fontSize = t.fontSize ?? \"14px\";\n\n const s: Record<string, CSSProperties> = {\n container: { position: \"relative\", width: \"100%\" },\n input: {\n width: \"100%\",\n padding: \"8px 12px\",\n fontSize,\n color: textColor,\n background,\n border: `1px solid ${borderColor}`,\n borderRadius,\n outline: \"none\",\n boxSizing: \"border-box\",\n },\n list: {\n position: \"absolute\",\n top: \"100%\",\n left: 0,\n right: 0,\n margin: \"4px 0 0\",\n padding: 0,\n listStyle: \"none\",\n background,\n border: `1px solid ${borderColor}`,\n borderRadius,\n boxShadow: \"0 4px 6px -1px rgba(0,0,0,.1)\",\n maxHeight: \"240px\",\n overflowY: \"auto\",\n zIndex: 50,\n },\n item: {\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n padding: \"8px 12px\",\n cursor: \"pointer\",\n fontSize,\n color: textColor,\n },\n itemActive: { background: activeBackground },\n name: { fontWeight: 500 },\n province: { fontSize: \"12px\", color: secondaryTextColor },\n status: {\n position: \"absolute\",\n top: \"100%\",\n left: 0,\n right: 0,\n margin: \"4px 0 0\",\n padding: \"8px 12px\",\n background,\n border: `1px solid ${borderColor}`,\n borderRadius,\n fontSize,\n color: secondaryTextColor,\n },\n };\n\n return (\n <div ref={containerRef} style={s.container} className={className}>\n <input\n type=\"text\"\n value={query}\n onChange={(e) => {\n setQuery(e.target.value);\n setOpen(true);\n }}\n onFocus={() => query.trim() && setOpen(true)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n style={s.input}\n role=\"combobox\"\n aria-expanded={open}\n aria-autocomplete=\"list\"\n aria-activedescendant={\n activeIndex >= 0 ? `pl-option-${activeIndex}` : undefined\n }\n />\n {open && filtered.length > 0 && (\n <ul role=\"listbox\" style={s.list}>\n {filtered.map((result, i) => (\n <li\n key={result.code}\n id={`pl-option-${i}`}\n role=\"option\"\n aria-selected={i === activeIndex}\n style={{\n ...s.item,\n ...(i === activeIndex ? s.itemActive : {}),\n }}\n onMouseEnter={() => setActiveIndex(i)}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelect(result)}\n >\n <span style={s.name}>{result.name}</span>\n {result.province_name && (\n <span style={s.province}>{result.province_name}</span>\n )}\n </li>\n ))}\n </ul>\n )}\n {open && loading && filtered.length === 0 && (\n <div style={s.status}>Loading...</div>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { AutocompleteResult, PlacesLayerClient } from \"@placeslayer/sdk\";\n\nconst DEBOUNCE_MS = 300;\n\nexport interface AutocompleteState {\n results: AutocompleteResult[];\n loading: boolean;\n error: Error | null;\n}\n\nexport function useAutocomplete(\n client: PlacesLayerClient,\n countryCode: string,\n query: string,\n opts?: { limit?: number; debounceMs?: number }\n): AutocompleteState {\n const [results, setResults] = useState<AutocompleteResult[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const version = useRef(0);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const delay = opts?.debounceMs ?? DEBOUNCE_MS;\n\n const search = useCallback(() => {\n const trimmed = query.trim();\n if (!trimmed) {\n setResults([]);\n setLoading(false);\n return;\n }\n\n const current = ++version.current;\n setLoading(true);\n\n client\n .autocomplete(countryCode, trimmed, { limit: opts?.limit })\n .then((data) => {\n if (current === version.current) {\n setResults(data);\n setLoading(false);\n }\n })\n .catch((err) => {\n if (current === version.current) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n }\n });\n }, [client, countryCode, query, opts?.limit]);\n\n useEffect(() => {\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(search, delay);\n return () => clearTimeout(timerRef.current);\n }, [search, delay]);\n\n return { results, loading, error };\n}\n","import { useRef } from \"react\";\nimport { PlacesLayerClient, type PlacesLayerConfig } from \"@placeslayer/sdk\";\n\nexport function usePlacesLayerClient(config: PlacesLayerConfig): PlacesLayerClient {\n const ref = useRef<PlacesLayerClient | null>(null);\n\n if (!ref.current || (ref.current as unknown as { apiKey: string }).apiKey !== config.apiKey) {\n ref.current = new PlacesLayerClient(config);\n }\n\n return ref.current;\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport interface AsyncState<T> {\n data: T | null;\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\nexport function useAsync<T>(\n fn: () => Promise<T>,\n deps: unknown[]\n): AsyncState<T> {\n const [data, setData] = useState<T | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const version = useRef(0);\n\n const execute = useCallback(() => {\n const current = ++version.current;\n setLoading(true);\n setError(null);\n\n fn()\n .then((result) => {\n if (current === version.current) {\n setData(result);\n setLoading(false);\n }\n })\n .catch((err) => {\n if (current === version.current) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n }\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, deps);\n\n useEffect(() => {\n execute();\n }, [execute]);\n\n return { data, loading, error, refetch: execute };\n}\n","import type { Country, PlacesLayerClient } from \"@placeslayer/sdk\";\nimport { type AsyncState, useAsync } from \"./useAsync\";\n\nexport function useCountries(client: PlacesLayerClient): AsyncState<Country[]> {\n return useAsync(() => client.countries(), [client]);\n}\n","import type { PlacesLayerClient, Province } from \"@placeslayer/sdk\";\nimport { type AsyncState, useAsync } from \"./useAsync\";\n\nexport function useProvinces(\n client: PlacesLayerClient,\n countryCode: string,\n opts?: { native?: boolean }\n): AsyncState<Province[]> {\n return useAsync(\n () => client.provinces(countryCode, opts),\n [client, countryCode, opts?.native]\n );\n}\n","import type { City, PlacesLayerClient } from \"@placeslayer/sdk\";\nimport { type AsyncState, useAsync } from \"./useAsync\";\n\nexport function useCities(\n client: PlacesLayerClient,\n countryCode: string,\n provinceCode: string,\n opts?: { native?: boolean }\n): AsyncState<City[]> {\n return useAsync(\n () => client.cities(countryCode, provinceCode, opts),\n [client, countryCode, provinceCode, opts?.native]\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_sdk","import_react"]}
@@ -0,0 +1,64 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { CityDetail, PlacesLayerConfig, PlacesLayerClient, Country, Province, City, AutocompleteResult } from '@placeslayer/sdk';
3
+
4
+ interface CitiesDropdownTheme {
5
+ /** Input border color (default: "#d1d5db") */
6
+ borderColor?: string;
7
+ /** Input border radius (default: "6px") */
8
+ borderRadius?: string;
9
+ /** Dropdown background color (default: "#fff") */
10
+ background?: string;
11
+ /** Main text color (default: "inherit") */
12
+ textColor?: string;
13
+ /** Secondary text color for province labels (default: "#6b7280") */
14
+ secondaryTextColor?: string;
15
+ /** Active/hovered item background (default: "#f3f4f6") */
16
+ activeBackground?: string;
17
+ /** Input font size (default: "14px") */
18
+ fontSize?: string;
19
+ }
20
+ interface CitiesDropdownProps {
21
+ apiKey: string;
22
+ country: string;
23
+ province?: string;
24
+ onSelect: (city: CityDetail) => void;
25
+ limit?: number;
26
+ lang?: "default" | "native";
27
+ placeholder?: string;
28
+ className?: string;
29
+ baseUrl?: string;
30
+ /** Customize dropdown colors and appearance */
31
+ theme?: CitiesDropdownTheme;
32
+ }
33
+ declare function CitiesDropdown({ apiKey, country, province, onSelect, limit, lang, placeholder, className, baseUrl, theme, }: CitiesDropdownProps): react_jsx_runtime.JSX.Element;
34
+
35
+ declare function usePlacesLayerClient(config: PlacesLayerConfig): PlacesLayerClient;
36
+
37
+ interface AsyncState<T> {
38
+ data: T | null;
39
+ loading: boolean;
40
+ error: Error | null;
41
+ refetch: () => void;
42
+ }
43
+
44
+ declare function useCountries(client: PlacesLayerClient): AsyncState<Country[]>;
45
+
46
+ declare function useProvinces(client: PlacesLayerClient, countryCode: string, opts?: {
47
+ native?: boolean;
48
+ }): AsyncState<Province[]>;
49
+
50
+ declare function useCities(client: PlacesLayerClient, countryCode: string, provinceCode: string, opts?: {
51
+ native?: boolean;
52
+ }): AsyncState<City[]>;
53
+
54
+ interface AutocompleteState {
55
+ results: AutocompleteResult[];
56
+ loading: boolean;
57
+ error: Error | null;
58
+ }
59
+ declare function useAutocomplete(client: PlacesLayerClient, countryCode: string, query: string, opts?: {
60
+ limit?: number;
61
+ debounceMs?: number;
62
+ }): AutocompleteState;
63
+
64
+ export { type AsyncState, type AutocompleteState, CitiesDropdown, type CitiesDropdownProps, type CitiesDropdownTheme, useAutocomplete, useCities, useCountries, usePlacesLayerClient, useProvinces };
@@ -0,0 +1,64 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { CityDetail, PlacesLayerConfig, PlacesLayerClient, Country, Province, City, AutocompleteResult } from '@placeslayer/sdk';
3
+
4
+ interface CitiesDropdownTheme {
5
+ /** Input border color (default: "#d1d5db") */
6
+ borderColor?: string;
7
+ /** Input border radius (default: "6px") */
8
+ borderRadius?: string;
9
+ /** Dropdown background color (default: "#fff") */
10
+ background?: string;
11
+ /** Main text color (default: "inherit") */
12
+ textColor?: string;
13
+ /** Secondary text color for province labels (default: "#6b7280") */
14
+ secondaryTextColor?: string;
15
+ /** Active/hovered item background (default: "#f3f4f6") */
16
+ activeBackground?: string;
17
+ /** Input font size (default: "14px") */
18
+ fontSize?: string;
19
+ }
20
+ interface CitiesDropdownProps {
21
+ apiKey: string;
22
+ country: string;
23
+ province?: string;
24
+ onSelect: (city: CityDetail) => void;
25
+ limit?: number;
26
+ lang?: "default" | "native";
27
+ placeholder?: string;
28
+ className?: string;
29
+ baseUrl?: string;
30
+ /** Customize dropdown colors and appearance */
31
+ theme?: CitiesDropdownTheme;
32
+ }
33
+ declare function CitiesDropdown({ apiKey, country, province, onSelect, limit, lang, placeholder, className, baseUrl, theme, }: CitiesDropdownProps): react_jsx_runtime.JSX.Element;
34
+
35
+ declare function usePlacesLayerClient(config: PlacesLayerConfig): PlacesLayerClient;
36
+
37
+ interface AsyncState<T> {
38
+ data: T | null;
39
+ loading: boolean;
40
+ error: Error | null;
41
+ refetch: () => void;
42
+ }
43
+
44
+ declare function useCountries(client: PlacesLayerClient): AsyncState<Country[]>;
45
+
46
+ declare function useProvinces(client: PlacesLayerClient, countryCode: string, opts?: {
47
+ native?: boolean;
48
+ }): AsyncState<Province[]>;
49
+
50
+ declare function useCities(client: PlacesLayerClient, countryCode: string, provinceCode: string, opts?: {
51
+ native?: boolean;
52
+ }): AsyncState<City[]>;
53
+
54
+ interface AutocompleteState {
55
+ results: AutocompleteResult[];
56
+ loading: boolean;
57
+ error: Error | null;
58
+ }
59
+ declare function useAutocomplete(client: PlacesLayerClient, countryCode: string, query: string, opts?: {
60
+ limit?: number;
61
+ debounceMs?: number;
62
+ }): AutocompleteState;
63
+
64
+ export { type AsyncState, type AutocompleteState, CitiesDropdown, type CitiesDropdownProps, type CitiesDropdownTheme, useAutocomplete, useCities, useCountries, usePlacesLayerClient, useProvinces };