@wherabouts/react-ui 0.1.0 → 0.1.1
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 +23 -5
- package/dist/index.cjs +249 -257
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -45
- package/dist/index.d.ts +97 -45
- package/dist/index.js +249 -257
- package/dist/index.js.map +1 -1
- package/dist/styles.css +23 -26
- package/docs/README.md +16 -0
- package/docs/address-autocomplete.md +208 -0
- package/docs/address-field-group.md +152 -0
- package/docs/address-form-field.md +198 -0
- package/docs/forward-geocode-input.md +115 -0
- package/docs/reverse-geocode-input.md +124 -0
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -73,8 +73,8 @@ keyboard navigation, and customizable rendering.
|
|
|
73
73
|
<AddressAutocomplete
|
|
74
74
|
client={client}
|
|
75
75
|
onSelect={(address) => setAddress(address)}
|
|
76
|
-
minCharsToSearch={
|
|
77
|
-
debounceMs={
|
|
76
|
+
minCharsToSearch={4}
|
|
77
|
+
debounceMs={250}
|
|
78
78
|
maxSuggestions={8}
|
|
79
79
|
enableGeolocation
|
|
80
80
|
/>
|
|
@@ -86,9 +86,9 @@ keyboard navigation, and customizable rendering.
|
|
|
86
86
|
| `onSelect` | `(address: AddressWithParsed) => void` | — | Called when a suggestion is chosen. |
|
|
87
87
|
| `onQueryChange` | `(query: string) => void` | — | Called as the input text changes. |
|
|
88
88
|
| `placeholder` | `string` | — | Input placeholder. |
|
|
89
|
-
| `debounceMs` | `number` | `
|
|
90
|
-
| `minCharsToSearch` | `number` | `
|
|
91
|
-
| `maxSuggestions` | `number` | `
|
|
89
|
+
| `debounceMs` | `number` | `300` | Debounce before querying the API. |
|
|
90
|
+
| `minCharsToSearch` | `number` | `2` | Minimum characters before searching. |
|
|
91
|
+
| `maxSuggestions` | `number` | `5` | Max suggestions to show. |
|
|
92
92
|
| `enableGeolocation` | `boolean` | `false` | Use the browser's location to bias results (proximity). |
|
|
93
93
|
| `userLat` / `userLng` | `number` | — | Explicit proximity bias instead of geolocation. |
|
|
94
94
|
| `sessionToken` | `string` | — | Group a run of keystrokes into one billable search (see `newSessionToken()` in the SDK). |
|
|
@@ -159,6 +159,24 @@ full address.
|
|
|
159
159
|
- Exported types: `AddressWithParsed`, `AddressI18nStrings`, `AddressValidateFn`,
|
|
160
160
|
`AddressSuggestionInput`, and each component's `*Props`.
|
|
161
161
|
|
|
162
|
+
## Per-component documentation
|
|
163
|
+
|
|
164
|
+
Full per-component guides — multiple examples, accessibility notes, and recipes —
|
|
165
|
+
live in [`docs/`](./docs/README.md).
|
|
166
|
+
|
|
167
|
+
## Interactive docs (Storybook)
|
|
168
|
+
|
|
169
|
+
This package ships a Storybook with live, interactive examples of every component.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pnpm --filter @wherabouts/react-ui storybook
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Live stories call the real API. Set `VITE_DEMO_API_KEY` (a publishable,
|
|
176
|
+
origin-scoped key) and optionally `VITE_DEMO_API_BASE_URL` (default
|
|
177
|
+
`https://api.wherabouts.com`) to enable results; without a key, components still
|
|
178
|
+
render with a configuration banner.
|
|
179
|
+
|
|
162
180
|
## Styling
|
|
163
181
|
|
|
164
182
|
The package ships a prebuilt `styles.css` (import it once, as shown above). Components use
|
package/dist/index.cjs
CHANGED
|
@@ -5,22 +5,42 @@ var react = require('react');
|
|
|
5
5
|
var reactDom = require('react-dom');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
|
|
8
|
-
// src/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
// src/components/address-autocomplete.tsx
|
|
9
|
+
function useAddressGeolocation(enabled) {
|
|
10
|
+
const [lat, setLat] = react.useState(void 0);
|
|
11
|
+
const [lng, setLng] = react.useState(void 0);
|
|
12
|
+
const [loading, setLoading] = react.useState(false);
|
|
13
|
+
const [error, setError] = react.useState(null);
|
|
14
|
+
react.useEffect(() => {
|
|
15
|
+
if (!enabled) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (typeof navigator === "undefined" || !("geolocation" in navigator)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
setLoading(true);
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
navigator.geolocation.getCurrentPosition(
|
|
24
|
+
(position) => {
|
|
25
|
+
if (!controller.signal.aborted) {
|
|
26
|
+
setLat(position.coords.latitude);
|
|
27
|
+
setLng(position.coords.longitude);
|
|
28
|
+
setError(null);
|
|
29
|
+
setLoading(false);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
(err) => {
|
|
33
|
+
if (!controller.signal.aborted) {
|
|
34
|
+
setError(err);
|
|
35
|
+
setLoading(false);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
return () => {
|
|
40
|
+
controller.abort();
|
|
41
|
+
};
|
|
42
|
+
}, [enabled]);
|
|
43
|
+
return { lat, lng, loading, error };
|
|
24
44
|
}
|
|
25
45
|
|
|
26
46
|
// ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
|
|
@@ -2502,41 +2522,23 @@ var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);
|
|
|
2502
2522
|
function cn(...inputs) {
|
|
2503
2523
|
return twMerge(clsx(inputs));
|
|
2504
2524
|
}
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
setLat(position.coords.latitude);
|
|
2523
|
-
setLng(position.coords.longitude);
|
|
2524
|
-
setError(null);
|
|
2525
|
-
setLoading(false);
|
|
2526
|
-
}
|
|
2527
|
-
},
|
|
2528
|
-
(err) => {
|
|
2529
|
-
if (!controller.signal.aborted) {
|
|
2530
|
-
setError(err);
|
|
2531
|
-
setLoading(false);
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
);
|
|
2535
|
-
return () => {
|
|
2536
|
-
controller.abort();
|
|
2537
|
-
};
|
|
2538
|
-
}, [enabled]);
|
|
2539
|
-
return { lat, lng, loading, error };
|
|
2525
|
+
|
|
2526
|
+
// src/utils/parse-address.ts
|
|
2527
|
+
var COUNTRY_NAMES = {
|
|
2528
|
+
AU: "Australia"
|
|
2529
|
+
};
|
|
2530
|
+
function toAddressWithParsed(suggestion) {
|
|
2531
|
+
return {
|
|
2532
|
+
id: suggestion.id,
|
|
2533
|
+
formattedAddress: suggestion.formattedAddress,
|
|
2534
|
+
latitude: suggestion.latitude,
|
|
2535
|
+
longitude: suggestion.longitude,
|
|
2536
|
+
streetAddress: suggestion.streetAddress,
|
|
2537
|
+
suburb: suggestion.locality,
|
|
2538
|
+
state: suggestion.state,
|
|
2539
|
+
postcode: suggestion.postcode,
|
|
2540
|
+
country: COUNTRY_NAMES[suggestion.country] ?? suggestion.country
|
|
2541
|
+
};
|
|
2540
2542
|
}
|
|
2541
2543
|
var DEFAULT_I18N = {
|
|
2542
2544
|
noResults: "No addresses found",
|
|
@@ -2780,186 +2782,6 @@ function AddressAutocomplete({
|
|
|
2780
2782
|
}
|
|
2781
2783
|
);
|
|
2782
2784
|
}
|
|
2783
|
-
function AddressFormField({
|
|
2784
|
-
label,
|
|
2785
|
-
labelClassName,
|
|
2786
|
-
errorClassName,
|
|
2787
|
-
error,
|
|
2788
|
-
required,
|
|
2789
|
-
disabled,
|
|
2790
|
-
id: customId,
|
|
2791
|
-
className,
|
|
2792
|
-
...autocompleteProps
|
|
2793
|
-
}) {
|
|
2794
|
-
const id = customId ?? "wherabouts-field";
|
|
2795
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2796
|
-
"div",
|
|
2797
|
-
{
|
|
2798
|
-
"data-slot": "address-form-field",
|
|
2799
|
-
className: "flex flex-col gap-2",
|
|
2800
|
-
children: [
|
|
2801
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2802
|
-
"label",
|
|
2803
|
-
{
|
|
2804
|
-
htmlFor: id,
|
|
2805
|
-
className: cn(
|
|
2806
|
-
"block text-sm font-medium text-gray-900",
|
|
2807
|
-
labelClassName
|
|
2808
|
-
),
|
|
2809
|
-
children: [
|
|
2810
|
-
label,
|
|
2811
|
-
required && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "ml-1 text-red-600", children: "*" })
|
|
2812
|
-
]
|
|
2813
|
-
}
|
|
2814
|
-
),
|
|
2815
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2816
|
-
AddressAutocomplete,
|
|
2817
|
-
{
|
|
2818
|
-
...autocompleteProps,
|
|
2819
|
-
id,
|
|
2820
|
-
required,
|
|
2821
|
-
disabled,
|
|
2822
|
-
error,
|
|
2823
|
-
className
|
|
2824
|
-
}
|
|
2825
|
-
),
|
|
2826
|
-
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2827
|
-
"p",
|
|
2828
|
-
{
|
|
2829
|
-
role: "alert",
|
|
2830
|
-
"aria-live": "polite",
|
|
2831
|
-
className: cn(
|
|
2832
|
-
"text-sm text-red-600",
|
|
2833
|
-
errorClassName
|
|
2834
|
-
),
|
|
2835
|
-
children: error
|
|
2836
|
-
}
|
|
2837
|
-
)
|
|
2838
|
-
]
|
|
2839
|
-
}
|
|
2840
|
-
);
|
|
2841
|
-
}
|
|
2842
|
-
function ReverseGeocodeInput({
|
|
2843
|
-
client,
|
|
2844
|
-
latitude,
|
|
2845
|
-
longitude,
|
|
2846
|
-
onResult,
|
|
2847
|
-
className,
|
|
2848
|
-
disabled,
|
|
2849
|
-
placeholder = "Address will appear here",
|
|
2850
|
-
id
|
|
2851
|
-
}) {
|
|
2852
|
-
const { address, distance } = react$1.useReverseGeocode(
|
|
2853
|
-
client,
|
|
2854
|
-
latitude != null && longitude != null ? { lat: latitude, lng: longitude } : null
|
|
2855
|
-
);
|
|
2856
|
-
react.useEffect(() => {
|
|
2857
|
-
onResult?.({
|
|
2858
|
-
address: address?.formattedAddress ?? null,
|
|
2859
|
-
distance: distance ?? null
|
|
2860
|
-
});
|
|
2861
|
-
}, [address, distance, onResult]);
|
|
2862
|
-
const displayText = address?.formattedAddress ?? "";
|
|
2863
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2864
|
-
"input",
|
|
2865
|
-
{
|
|
2866
|
-
id,
|
|
2867
|
-
"data-slot": "geocode-input",
|
|
2868
|
-
type: "text",
|
|
2869
|
-
readOnly: true,
|
|
2870
|
-
disabled,
|
|
2871
|
-
value: displayText,
|
|
2872
|
-
placeholder,
|
|
2873
|
-
className: cn(
|
|
2874
|
-
"block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
|
|
2875
|
-
className
|
|
2876
|
-
)
|
|
2877
|
-
}
|
|
2878
|
-
);
|
|
2879
|
-
}
|
|
2880
|
-
var toGeocodeAddress = (address) => address ? {
|
|
2881
|
-
id: address.id,
|
|
2882
|
-
formattedAddress: address.formattedAddress,
|
|
2883
|
-
latitude: address.latitude,
|
|
2884
|
-
longitude: address.longitude
|
|
2885
|
-
} : null;
|
|
2886
|
-
function useForwardGeocode(client, query) {
|
|
2887
|
-
const [data, setData] = react.useState(null);
|
|
2888
|
-
const [loading, setLoading] = react.useState(false);
|
|
2889
|
-
const [error, setError] = react.useState(null);
|
|
2890
|
-
react.useEffect(() => {
|
|
2891
|
-
if (!query) {
|
|
2892
|
-
setData(null);
|
|
2893
|
-
setError(null);
|
|
2894
|
-
return;
|
|
2895
|
-
}
|
|
2896
|
-
const controller = new AbortController();
|
|
2897
|
-
async function fetch() {
|
|
2898
|
-
setLoading(true);
|
|
2899
|
-
setError(null);
|
|
2900
|
-
try {
|
|
2901
|
-
const response = await client.geocode.forward(
|
|
2902
|
-
{ q: query },
|
|
2903
|
-
{ signal: controller.signal }
|
|
2904
|
-
);
|
|
2905
|
-
if (controller.signal.aborted) {
|
|
2906
|
-
return;
|
|
2907
|
-
}
|
|
2908
|
-
setData(toGeocodeAddress(response.address));
|
|
2909
|
-
} catch (err) {
|
|
2910
|
-
if (controller.signal.aborted) {
|
|
2911
|
-
return;
|
|
2912
|
-
}
|
|
2913
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2914
|
-
setData(null);
|
|
2915
|
-
} finally {
|
|
2916
|
-
if (!controller.signal.aborted) {
|
|
2917
|
-
setLoading(false);
|
|
2918
|
-
}
|
|
2919
|
-
}
|
|
2920
|
-
}
|
|
2921
|
-
fetch();
|
|
2922
|
-
return () => {
|
|
2923
|
-
controller.abort();
|
|
2924
|
-
};
|
|
2925
|
-
}, [client, query]);
|
|
2926
|
-
return { data, loading, error };
|
|
2927
|
-
}
|
|
2928
|
-
function ForwardGeocodeInput({
|
|
2929
|
-
client,
|
|
2930
|
-
query,
|
|
2931
|
-
onResult,
|
|
2932
|
-
className,
|
|
2933
|
-
disabled,
|
|
2934
|
-
placeholder = "Coordinates will appear here",
|
|
2935
|
-
id
|
|
2936
|
-
}) {
|
|
2937
|
-
const { data } = useForwardGeocode(client, query);
|
|
2938
|
-
react.useEffect(() => {
|
|
2939
|
-
onResult?.({
|
|
2940
|
-
latitude: data?.latitude ?? null,
|
|
2941
|
-
longitude: data?.longitude ?? null,
|
|
2942
|
-
formattedAddress: data?.formattedAddress ?? null
|
|
2943
|
-
});
|
|
2944
|
-
}, [data, onResult]);
|
|
2945
|
-
const displayText = data ? `${data.latitude.toFixed(4)}, ${data.longitude.toFixed(4)}` : "";
|
|
2946
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2947
|
-
"input",
|
|
2948
|
-
{
|
|
2949
|
-
id,
|
|
2950
|
-
"data-slot": "geocode-input",
|
|
2951
|
-
type: "text",
|
|
2952
|
-
readOnly: true,
|
|
2953
|
-
disabled,
|
|
2954
|
-
value: displayText,
|
|
2955
|
-
placeholder,
|
|
2956
|
-
className: cn(
|
|
2957
|
-
"block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
|
|
2958
|
-
className
|
|
2959
|
-
)
|
|
2960
|
-
}
|
|
2961
|
-
);
|
|
2962
|
-
}
|
|
2963
2785
|
function AddressFieldGroup({
|
|
2964
2786
|
client,
|
|
2965
2787
|
value,
|
|
@@ -2988,8 +2810,8 @@ function AddressFieldGroup({
|
|
|
2988
2810
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2989
2811
|
"div",
|
|
2990
2812
|
{
|
|
2991
|
-
"data-slot": "address-field-group",
|
|
2992
2813
|
className: cn("flex flex-col gap-4", className),
|
|
2814
|
+
"data-slot": "address-field-group",
|
|
2993
2815
|
children: [
|
|
2994
2816
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2995
2817
|
AddressAutocomplete,
|
|
@@ -3003,28 +2825,28 @@ function AddressFieldGroup({
|
|
|
3003
2825
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3004
2826
|
"div",
|
|
3005
2827
|
{
|
|
3006
|
-
"data-slot": "address-field-group-inputs",
|
|
3007
2828
|
className: "grid grid-cols-2 gap-4",
|
|
2829
|
+
"data-slot": "address-field-group-inputs",
|
|
3008
2830
|
children: [
|
|
3009
2831
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2", children: [
|
|
3010
2832
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3011
2833
|
"label",
|
|
3012
2834
|
{
|
|
3013
|
-
htmlFor: "field-street",
|
|
3014
2835
|
className: "mb-1 block font-medium text-foreground text-sm",
|
|
2836
|
+
htmlFor: "field-street",
|
|
3015
2837
|
children: streetLabel
|
|
3016
2838
|
}
|
|
3017
2839
|
),
|
|
3018
2840
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3019
2841
|
"input",
|
|
3020
2842
|
{
|
|
3021
|
-
|
|
3022
|
-
type: "text",
|
|
2843
|
+
className: "block h-8 w-full rounded-none border border-input bg-transparent px-2.5 py-1 text-foreground text-xs outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30",
|
|
3023
2844
|
disabled,
|
|
3024
|
-
|
|
2845
|
+
id: "field-street",
|
|
3025
2846
|
onChange: (e) => handleFieldChange("street", e.target.value),
|
|
3026
|
-
|
|
3027
|
-
|
|
2847
|
+
placeholder: "Street address",
|
|
2848
|
+
type: "text",
|
|
2849
|
+
value: value.street
|
|
3028
2850
|
}
|
|
3029
2851
|
)
|
|
3030
2852
|
] }),
|
|
@@ -3032,21 +2854,21 @@ function AddressFieldGroup({
|
|
|
3032
2854
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3033
2855
|
"label",
|
|
3034
2856
|
{
|
|
3035
|
-
htmlFor: "field-suburb",
|
|
3036
2857
|
className: "mb-1 block font-medium text-foreground text-sm",
|
|
2858
|
+
htmlFor: "field-suburb",
|
|
3037
2859
|
children: suburbLabel
|
|
3038
2860
|
}
|
|
3039
2861
|
),
|
|
3040
2862
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3041
2863
|
"input",
|
|
3042
2864
|
{
|
|
3043
|
-
|
|
3044
|
-
type: "text",
|
|
2865
|
+
className: "block h-8 w-full rounded-none border border-input bg-transparent px-2.5 py-1 text-foreground text-xs outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30",
|
|
3045
2866
|
disabled,
|
|
3046
|
-
|
|
2867
|
+
id: "field-suburb",
|
|
3047
2868
|
onChange: (e) => handleFieldChange("suburb", e.target.value),
|
|
3048
|
-
|
|
3049
|
-
|
|
2869
|
+
placeholder: "Suburb",
|
|
2870
|
+
type: "text",
|
|
2871
|
+
value: value.suburb
|
|
3050
2872
|
}
|
|
3051
2873
|
)
|
|
3052
2874
|
] }),
|
|
@@ -3054,21 +2876,21 @@ function AddressFieldGroup({
|
|
|
3054
2876
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3055
2877
|
"label",
|
|
3056
2878
|
{
|
|
3057
|
-
htmlFor: "field-state",
|
|
3058
2879
|
className: "mb-1 block font-medium text-foreground text-sm",
|
|
2880
|
+
htmlFor: "field-state",
|
|
3059
2881
|
children: stateLabel
|
|
3060
2882
|
}
|
|
3061
2883
|
),
|
|
3062
2884
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3063
2885
|
"input",
|
|
3064
2886
|
{
|
|
3065
|
-
|
|
3066
|
-
type: "text",
|
|
2887
|
+
className: "block h-8 w-full rounded-none border border-input bg-transparent px-2.5 py-1 text-foreground text-xs outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30",
|
|
3067
2888
|
disabled,
|
|
3068
|
-
|
|
2889
|
+
id: "field-state",
|
|
3069
2890
|
onChange: (e) => handleFieldChange("state", e.target.value),
|
|
3070
|
-
|
|
3071
|
-
|
|
2891
|
+
placeholder: "State",
|
|
2892
|
+
type: "text",
|
|
2893
|
+
value: value.state
|
|
3072
2894
|
}
|
|
3073
2895
|
)
|
|
3074
2896
|
] }),
|
|
@@ -3076,21 +2898,21 @@ function AddressFieldGroup({
|
|
|
3076
2898
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3077
2899
|
"label",
|
|
3078
2900
|
{
|
|
3079
|
-
htmlFor: "field-postcode",
|
|
3080
2901
|
className: "mb-1 block font-medium text-foreground text-sm",
|
|
2902
|
+
htmlFor: "field-postcode",
|
|
3081
2903
|
children: postcodeLabel
|
|
3082
2904
|
}
|
|
3083
2905
|
),
|
|
3084
2906
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3085
2907
|
"input",
|
|
3086
2908
|
{
|
|
3087
|
-
|
|
3088
|
-
type: "text",
|
|
2909
|
+
className: "block h-8 w-full rounded-none border border-input bg-transparent px-2.5 py-1 text-foreground text-xs outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30",
|
|
3089
2910
|
disabled,
|
|
3090
|
-
|
|
2911
|
+
id: "field-postcode",
|
|
3091
2912
|
onChange: (e) => handleFieldChange("postcode", e.target.value),
|
|
3092
|
-
|
|
3093
|
-
|
|
2913
|
+
placeholder: "Postcode",
|
|
2914
|
+
type: "text",
|
|
2915
|
+
value: value.postcode
|
|
3094
2916
|
}
|
|
3095
2917
|
)
|
|
3096
2918
|
] })
|
|
@@ -3101,6 +2923,176 @@ function AddressFieldGroup({
|
|
|
3101
2923
|
}
|
|
3102
2924
|
);
|
|
3103
2925
|
}
|
|
2926
|
+
function AddressFormField({
|
|
2927
|
+
label,
|
|
2928
|
+
labelClassName,
|
|
2929
|
+
errorClassName,
|
|
2930
|
+
error,
|
|
2931
|
+
required,
|
|
2932
|
+
disabled,
|
|
2933
|
+
id: customId,
|
|
2934
|
+
className,
|
|
2935
|
+
...autocompleteProps
|
|
2936
|
+
}) {
|
|
2937
|
+
const id = customId ?? "wherabouts-field";
|
|
2938
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", "data-slot": "address-form-field", children: [
|
|
2939
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2940
|
+
"label",
|
|
2941
|
+
{
|
|
2942
|
+
className: cn(
|
|
2943
|
+
"block font-medium text-gray-900 text-sm",
|
|
2944
|
+
labelClassName
|
|
2945
|
+
),
|
|
2946
|
+
htmlFor: id,
|
|
2947
|
+
children: [
|
|
2948
|
+
label,
|
|
2949
|
+
required && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "ml-1 text-red-600", children: "*" })
|
|
2950
|
+
]
|
|
2951
|
+
}
|
|
2952
|
+
),
|
|
2953
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2954
|
+
AddressAutocomplete,
|
|
2955
|
+
{
|
|
2956
|
+
...autocompleteProps,
|
|
2957
|
+
className,
|
|
2958
|
+
disabled,
|
|
2959
|
+
error,
|
|
2960
|
+
id,
|
|
2961
|
+
required
|
|
2962
|
+
}
|
|
2963
|
+
),
|
|
2964
|
+
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2965
|
+
"p",
|
|
2966
|
+
{
|
|
2967
|
+
"aria-live": "polite",
|
|
2968
|
+
className: cn("text-red-600 text-sm", errorClassName),
|
|
2969
|
+
role: "alert",
|
|
2970
|
+
children: error
|
|
2971
|
+
}
|
|
2972
|
+
)
|
|
2973
|
+
] });
|
|
2974
|
+
}
|
|
2975
|
+
var toGeocodeAddress = (address) => address ? {
|
|
2976
|
+
id: address.id,
|
|
2977
|
+
formattedAddress: address.formattedAddress,
|
|
2978
|
+
latitude: address.latitude,
|
|
2979
|
+
longitude: address.longitude
|
|
2980
|
+
} : null;
|
|
2981
|
+
function useForwardGeocode(client, query) {
|
|
2982
|
+
const [data, setData] = react.useState(null);
|
|
2983
|
+
const [loading, setLoading] = react.useState(false);
|
|
2984
|
+
const [error, setError] = react.useState(null);
|
|
2985
|
+
react.useEffect(() => {
|
|
2986
|
+
if (!query) {
|
|
2987
|
+
setData(null);
|
|
2988
|
+
setError(null);
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
const controller = new AbortController();
|
|
2992
|
+
async function fetch() {
|
|
2993
|
+
setLoading(true);
|
|
2994
|
+
setError(null);
|
|
2995
|
+
try {
|
|
2996
|
+
const response = await client.geocode.forward(
|
|
2997
|
+
{ q: query },
|
|
2998
|
+
{ signal: controller.signal }
|
|
2999
|
+
);
|
|
3000
|
+
if (controller.signal.aborted) {
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
setData(toGeocodeAddress(response.address));
|
|
3004
|
+
} catch (err) {
|
|
3005
|
+
if (controller.signal.aborted) {
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
3008
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3009
|
+
setData(null);
|
|
3010
|
+
} finally {
|
|
3011
|
+
if (!controller.signal.aborted) {
|
|
3012
|
+
setLoading(false);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
fetch();
|
|
3017
|
+
return () => {
|
|
3018
|
+
controller.abort();
|
|
3019
|
+
};
|
|
3020
|
+
}, [client, query]);
|
|
3021
|
+
return { data, loading, error };
|
|
3022
|
+
}
|
|
3023
|
+
function ForwardGeocodeInput({
|
|
3024
|
+
client,
|
|
3025
|
+
query,
|
|
3026
|
+
onResult,
|
|
3027
|
+
className,
|
|
3028
|
+
disabled,
|
|
3029
|
+
placeholder = "Coordinates will appear here",
|
|
3030
|
+
id
|
|
3031
|
+
}) {
|
|
3032
|
+
const { data } = useForwardGeocode(client, query);
|
|
3033
|
+
react.useEffect(() => {
|
|
3034
|
+
onResult?.({
|
|
3035
|
+
latitude: data?.latitude ?? null,
|
|
3036
|
+
longitude: data?.longitude ?? null,
|
|
3037
|
+
formattedAddress: data?.formattedAddress ?? null
|
|
3038
|
+
});
|
|
3039
|
+
}, [data, onResult]);
|
|
3040
|
+
const displayText = data ? `${data.latitude.toFixed(4)}, ${data.longitude.toFixed(4)}` : "";
|
|
3041
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3042
|
+
"input",
|
|
3043
|
+
{
|
|
3044
|
+
className: cn(
|
|
3045
|
+
"block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
|
|
3046
|
+
className
|
|
3047
|
+
),
|
|
3048
|
+
"data-slot": "geocode-input",
|
|
3049
|
+
disabled,
|
|
3050
|
+
id,
|
|
3051
|
+
placeholder,
|
|
3052
|
+
readOnly: true,
|
|
3053
|
+
type: "text",
|
|
3054
|
+
value: displayText
|
|
3055
|
+
}
|
|
3056
|
+
);
|
|
3057
|
+
}
|
|
3058
|
+
function ReverseGeocodeInput({
|
|
3059
|
+
client,
|
|
3060
|
+
latitude,
|
|
3061
|
+
longitude,
|
|
3062
|
+
onResult,
|
|
3063
|
+
className,
|
|
3064
|
+
disabled,
|
|
3065
|
+
placeholder = "Address will appear here",
|
|
3066
|
+
id
|
|
3067
|
+
}) {
|
|
3068
|
+
const { address, distance } = react$1.useReverseGeocode(
|
|
3069
|
+
client,
|
|
3070
|
+
latitude != null && longitude != null ? { lat: latitude, lng: longitude } : null
|
|
3071
|
+
);
|
|
3072
|
+
react.useEffect(() => {
|
|
3073
|
+
onResult?.({
|
|
3074
|
+
address: address?.formattedAddress ?? null,
|
|
3075
|
+
distance: distance ?? null
|
|
3076
|
+
});
|
|
3077
|
+
}, [address, distance, onResult]);
|
|
3078
|
+
const displayText = address?.formattedAddress ?? "";
|
|
3079
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3080
|
+
"input",
|
|
3081
|
+
{
|
|
3082
|
+
className: cn(
|
|
3083
|
+
"block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
|
|
3084
|
+
className
|
|
3085
|
+
),
|
|
3086
|
+
"data-slot": "geocode-input",
|
|
3087
|
+
disabled,
|
|
3088
|
+
id,
|
|
3089
|
+
placeholder,
|
|
3090
|
+
readOnly: true,
|
|
3091
|
+
type: "text",
|
|
3092
|
+
value: displayText
|
|
3093
|
+
}
|
|
3094
|
+
);
|
|
3095
|
+
}
|
|
3104
3096
|
|
|
3105
3097
|
exports.AddressAutocomplete = AddressAutocomplete;
|
|
3106
3098
|
exports.AddressFieldGroup = AddressFieldGroup;
|