@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 +337 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +64 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +312 -0
- package/dist/index.js.map +1 -0
- package/dist/map.cjs +322 -0
- package/dist/map.cjs.map +1 -0
- package/dist/map.d.cts +37 -0
- package/dist/map.d.ts +37 -0
- package/dist/map.js +294 -0
- package/dist/map.js.map +1 -0
- package/package.json +65 -0
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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|