@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/dist/index.js CHANGED
@@ -3,22 +3,42 @@ import { useMemo, useRef, useState, useEffect } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
- // src/utils/parse-address.ts
7
- var COUNTRY_NAMES = {
8
- AU: "Australia"
9
- };
10
- function toAddressWithParsed(suggestion) {
11
- return {
12
- id: suggestion.id,
13
- formattedAddress: suggestion.formattedAddress,
14
- latitude: suggestion.latitude,
15
- longitude: suggestion.longitude,
16
- streetAddress: suggestion.streetAddress,
17
- suburb: suggestion.locality,
18
- state: suggestion.state,
19
- postcode: suggestion.postcode,
20
- country: COUNTRY_NAMES[suggestion.country] ?? suggestion.country
21
- };
6
+ // src/components/address-autocomplete.tsx
7
+ function useAddressGeolocation(enabled) {
8
+ const [lat, setLat] = useState(void 0);
9
+ const [lng, setLng] = useState(void 0);
10
+ const [loading, setLoading] = useState(false);
11
+ const [error, setError] = useState(null);
12
+ useEffect(() => {
13
+ if (!enabled) {
14
+ return;
15
+ }
16
+ if (typeof navigator === "undefined" || !("geolocation" in navigator)) {
17
+ return;
18
+ }
19
+ setLoading(true);
20
+ const controller = new AbortController();
21
+ navigator.geolocation.getCurrentPosition(
22
+ (position) => {
23
+ if (!controller.signal.aborted) {
24
+ setLat(position.coords.latitude);
25
+ setLng(position.coords.longitude);
26
+ setError(null);
27
+ setLoading(false);
28
+ }
29
+ },
30
+ (err) => {
31
+ if (!controller.signal.aborted) {
32
+ setError(err);
33
+ setLoading(false);
34
+ }
35
+ }
36
+ );
37
+ return () => {
38
+ controller.abort();
39
+ };
40
+ }, [enabled]);
41
+ return { lat, lng, loading, error };
22
42
  }
23
43
 
24
44
  // ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
@@ -2500,41 +2520,23 @@ var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);
2500
2520
  function cn(...inputs) {
2501
2521
  return twMerge(clsx(inputs));
2502
2522
  }
2503
- function useAddressGeolocation(enabled) {
2504
- const [lat, setLat] = useState(void 0);
2505
- const [lng, setLng] = useState(void 0);
2506
- const [loading, setLoading] = useState(false);
2507
- const [error, setError] = useState(null);
2508
- useEffect(() => {
2509
- if (!enabled) {
2510
- return;
2511
- }
2512
- if (typeof navigator === "undefined" || !("geolocation" in navigator)) {
2513
- return;
2514
- }
2515
- setLoading(true);
2516
- const controller = new AbortController();
2517
- navigator.geolocation.getCurrentPosition(
2518
- (position) => {
2519
- if (!controller.signal.aborted) {
2520
- setLat(position.coords.latitude);
2521
- setLng(position.coords.longitude);
2522
- setError(null);
2523
- setLoading(false);
2524
- }
2525
- },
2526
- (err) => {
2527
- if (!controller.signal.aborted) {
2528
- setError(err);
2529
- setLoading(false);
2530
- }
2531
- }
2532
- );
2533
- return () => {
2534
- controller.abort();
2535
- };
2536
- }, [enabled]);
2537
- return { lat, lng, loading, error };
2523
+
2524
+ // src/utils/parse-address.ts
2525
+ var COUNTRY_NAMES = {
2526
+ AU: "Australia"
2527
+ };
2528
+ function toAddressWithParsed(suggestion) {
2529
+ return {
2530
+ id: suggestion.id,
2531
+ formattedAddress: suggestion.formattedAddress,
2532
+ latitude: suggestion.latitude,
2533
+ longitude: suggestion.longitude,
2534
+ streetAddress: suggestion.streetAddress,
2535
+ suburb: suggestion.locality,
2536
+ state: suggestion.state,
2537
+ postcode: suggestion.postcode,
2538
+ country: COUNTRY_NAMES[suggestion.country] ?? suggestion.country
2539
+ };
2538
2540
  }
2539
2541
  var DEFAULT_I18N = {
2540
2542
  noResults: "No addresses found",
@@ -2778,186 +2780,6 @@ function AddressAutocomplete({
2778
2780
  }
2779
2781
  );
2780
2782
  }
2781
- function AddressFormField({
2782
- label,
2783
- labelClassName,
2784
- errorClassName,
2785
- error,
2786
- required,
2787
- disabled,
2788
- id: customId,
2789
- className,
2790
- ...autocompleteProps
2791
- }) {
2792
- const id = customId ?? "wherabouts-field";
2793
- return /* @__PURE__ */ jsxs(
2794
- "div",
2795
- {
2796
- "data-slot": "address-form-field",
2797
- className: "flex flex-col gap-2",
2798
- children: [
2799
- /* @__PURE__ */ jsxs(
2800
- "label",
2801
- {
2802
- htmlFor: id,
2803
- className: cn(
2804
- "block text-sm font-medium text-gray-900",
2805
- labelClassName
2806
- ),
2807
- children: [
2808
- label,
2809
- required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-1 text-red-600", children: "*" })
2810
- ]
2811
- }
2812
- ),
2813
- /* @__PURE__ */ jsx(
2814
- AddressAutocomplete,
2815
- {
2816
- ...autocompleteProps,
2817
- id,
2818
- required,
2819
- disabled,
2820
- error,
2821
- className
2822
- }
2823
- ),
2824
- error && /* @__PURE__ */ jsx(
2825
- "p",
2826
- {
2827
- role: "alert",
2828
- "aria-live": "polite",
2829
- className: cn(
2830
- "text-sm text-red-600",
2831
- errorClassName
2832
- ),
2833
- children: error
2834
- }
2835
- )
2836
- ]
2837
- }
2838
- );
2839
- }
2840
- function ReverseGeocodeInput({
2841
- client,
2842
- latitude,
2843
- longitude,
2844
- onResult,
2845
- className,
2846
- disabled,
2847
- placeholder = "Address will appear here",
2848
- id
2849
- }) {
2850
- const { address, distance } = useReverseGeocode(
2851
- client,
2852
- latitude != null && longitude != null ? { lat: latitude, lng: longitude } : null
2853
- );
2854
- useEffect(() => {
2855
- onResult?.({
2856
- address: address?.formattedAddress ?? null,
2857
- distance: distance ?? null
2858
- });
2859
- }, [address, distance, onResult]);
2860
- const displayText = address?.formattedAddress ?? "";
2861
- return /* @__PURE__ */ jsx(
2862
- "input",
2863
- {
2864
- id,
2865
- "data-slot": "geocode-input",
2866
- type: "text",
2867
- readOnly: true,
2868
- disabled,
2869
- value: displayText,
2870
- placeholder,
2871
- className: cn(
2872
- "block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
2873
- className
2874
- )
2875
- }
2876
- );
2877
- }
2878
- var toGeocodeAddress = (address) => address ? {
2879
- id: address.id,
2880
- formattedAddress: address.formattedAddress,
2881
- latitude: address.latitude,
2882
- longitude: address.longitude
2883
- } : null;
2884
- function useForwardGeocode(client, query) {
2885
- const [data, setData] = useState(null);
2886
- const [loading, setLoading] = useState(false);
2887
- const [error, setError] = useState(null);
2888
- useEffect(() => {
2889
- if (!query) {
2890
- setData(null);
2891
- setError(null);
2892
- return;
2893
- }
2894
- const controller = new AbortController();
2895
- async function fetch() {
2896
- setLoading(true);
2897
- setError(null);
2898
- try {
2899
- const response = await client.geocode.forward(
2900
- { q: query },
2901
- { signal: controller.signal }
2902
- );
2903
- if (controller.signal.aborted) {
2904
- return;
2905
- }
2906
- setData(toGeocodeAddress(response.address));
2907
- } catch (err) {
2908
- if (controller.signal.aborted) {
2909
- return;
2910
- }
2911
- setError(err instanceof Error ? err : new Error(String(err)));
2912
- setData(null);
2913
- } finally {
2914
- if (!controller.signal.aborted) {
2915
- setLoading(false);
2916
- }
2917
- }
2918
- }
2919
- fetch();
2920
- return () => {
2921
- controller.abort();
2922
- };
2923
- }, [client, query]);
2924
- return { data, loading, error };
2925
- }
2926
- function ForwardGeocodeInput({
2927
- client,
2928
- query,
2929
- onResult,
2930
- className,
2931
- disabled,
2932
- placeholder = "Coordinates will appear here",
2933
- id
2934
- }) {
2935
- const { data } = useForwardGeocode(client, query);
2936
- useEffect(() => {
2937
- onResult?.({
2938
- latitude: data?.latitude ?? null,
2939
- longitude: data?.longitude ?? null,
2940
- formattedAddress: data?.formattedAddress ?? null
2941
- });
2942
- }, [data, onResult]);
2943
- const displayText = data ? `${data.latitude.toFixed(4)}, ${data.longitude.toFixed(4)}` : "";
2944
- return /* @__PURE__ */ jsx(
2945
- "input",
2946
- {
2947
- id,
2948
- "data-slot": "geocode-input",
2949
- type: "text",
2950
- readOnly: true,
2951
- disabled,
2952
- value: displayText,
2953
- placeholder,
2954
- className: cn(
2955
- "block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
2956
- className
2957
- )
2958
- }
2959
- );
2960
- }
2961
2783
  function AddressFieldGroup({
2962
2784
  client,
2963
2785
  value,
@@ -2986,8 +2808,8 @@ function AddressFieldGroup({
2986
2808
  return /* @__PURE__ */ jsxs(
2987
2809
  "div",
2988
2810
  {
2989
- "data-slot": "address-field-group",
2990
2811
  className: cn("flex flex-col gap-4", className),
2812
+ "data-slot": "address-field-group",
2991
2813
  children: [
2992
2814
  /* @__PURE__ */ jsx(
2993
2815
  AddressAutocomplete,
@@ -3001,28 +2823,28 @@ function AddressFieldGroup({
3001
2823
  /* @__PURE__ */ jsxs(
3002
2824
  "div",
3003
2825
  {
3004
- "data-slot": "address-field-group-inputs",
3005
2826
  className: "grid grid-cols-2 gap-4",
2827
+ "data-slot": "address-field-group-inputs",
3006
2828
  children: [
3007
2829
  /* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
3008
2830
  /* @__PURE__ */ jsx(
3009
2831
  "label",
3010
2832
  {
3011
- htmlFor: "field-street",
3012
2833
  className: "mb-1 block font-medium text-foreground text-sm",
2834
+ htmlFor: "field-street",
3013
2835
  children: streetLabel
3014
2836
  }
3015
2837
  ),
3016
2838
  /* @__PURE__ */ jsx(
3017
2839
  "input",
3018
2840
  {
3019
- id: "field-street",
3020
- type: "text",
2841
+ 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",
3021
2842
  disabled,
3022
- value: value.street,
2843
+ id: "field-street",
3023
2844
  onChange: (e) => handleFieldChange("street", e.target.value),
3024
- 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",
3025
- placeholder: "Street address"
2845
+ placeholder: "Street address",
2846
+ type: "text",
2847
+ value: value.street
3026
2848
  }
3027
2849
  )
3028
2850
  ] }),
@@ -3030,21 +2852,21 @@ function AddressFieldGroup({
3030
2852
  /* @__PURE__ */ jsx(
3031
2853
  "label",
3032
2854
  {
3033
- htmlFor: "field-suburb",
3034
2855
  className: "mb-1 block font-medium text-foreground text-sm",
2856
+ htmlFor: "field-suburb",
3035
2857
  children: suburbLabel
3036
2858
  }
3037
2859
  ),
3038
2860
  /* @__PURE__ */ jsx(
3039
2861
  "input",
3040
2862
  {
3041
- id: "field-suburb",
3042
- type: "text",
2863
+ 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",
3043
2864
  disabled,
3044
- value: value.suburb,
2865
+ id: "field-suburb",
3045
2866
  onChange: (e) => handleFieldChange("suburb", e.target.value),
3046
- 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",
3047
- placeholder: "Suburb"
2867
+ placeholder: "Suburb",
2868
+ type: "text",
2869
+ value: value.suburb
3048
2870
  }
3049
2871
  )
3050
2872
  ] }),
@@ -3052,21 +2874,21 @@ function AddressFieldGroup({
3052
2874
  /* @__PURE__ */ jsx(
3053
2875
  "label",
3054
2876
  {
3055
- htmlFor: "field-state",
3056
2877
  className: "mb-1 block font-medium text-foreground text-sm",
2878
+ htmlFor: "field-state",
3057
2879
  children: stateLabel
3058
2880
  }
3059
2881
  ),
3060
2882
  /* @__PURE__ */ jsx(
3061
2883
  "input",
3062
2884
  {
3063
- id: "field-state",
3064
- type: "text",
2885
+ 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",
3065
2886
  disabled,
3066
- value: value.state,
2887
+ id: "field-state",
3067
2888
  onChange: (e) => handleFieldChange("state", e.target.value),
3068
- 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",
3069
- placeholder: "State"
2889
+ placeholder: "State",
2890
+ type: "text",
2891
+ value: value.state
3070
2892
  }
3071
2893
  )
3072
2894
  ] }),
@@ -3074,21 +2896,21 @@ function AddressFieldGroup({
3074
2896
  /* @__PURE__ */ jsx(
3075
2897
  "label",
3076
2898
  {
3077
- htmlFor: "field-postcode",
3078
2899
  className: "mb-1 block font-medium text-foreground text-sm",
2900
+ htmlFor: "field-postcode",
3079
2901
  children: postcodeLabel
3080
2902
  }
3081
2903
  ),
3082
2904
  /* @__PURE__ */ jsx(
3083
2905
  "input",
3084
2906
  {
3085
- id: "field-postcode",
3086
- type: "text",
2907
+ 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",
3087
2908
  disabled,
3088
- value: value.postcode,
2909
+ id: "field-postcode",
3089
2910
  onChange: (e) => handleFieldChange("postcode", e.target.value),
3090
- 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",
3091
- placeholder: "Postcode"
2911
+ placeholder: "Postcode",
2912
+ type: "text",
2913
+ value: value.postcode
3092
2914
  }
3093
2915
  )
3094
2916
  ] })
@@ -3099,6 +2921,176 @@ function AddressFieldGroup({
3099
2921
  }
3100
2922
  );
3101
2923
  }
2924
+ function AddressFormField({
2925
+ label,
2926
+ labelClassName,
2927
+ errorClassName,
2928
+ error,
2929
+ required,
2930
+ disabled,
2931
+ id: customId,
2932
+ className,
2933
+ ...autocompleteProps
2934
+ }) {
2935
+ const id = customId ?? "wherabouts-field";
2936
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", "data-slot": "address-form-field", children: [
2937
+ /* @__PURE__ */ jsxs(
2938
+ "label",
2939
+ {
2940
+ className: cn(
2941
+ "block font-medium text-gray-900 text-sm",
2942
+ labelClassName
2943
+ ),
2944
+ htmlFor: id,
2945
+ children: [
2946
+ label,
2947
+ required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-1 text-red-600", children: "*" })
2948
+ ]
2949
+ }
2950
+ ),
2951
+ /* @__PURE__ */ jsx(
2952
+ AddressAutocomplete,
2953
+ {
2954
+ ...autocompleteProps,
2955
+ className,
2956
+ disabled,
2957
+ error,
2958
+ id,
2959
+ required
2960
+ }
2961
+ ),
2962
+ error && /* @__PURE__ */ jsx(
2963
+ "p",
2964
+ {
2965
+ "aria-live": "polite",
2966
+ className: cn("text-red-600 text-sm", errorClassName),
2967
+ role: "alert",
2968
+ children: error
2969
+ }
2970
+ )
2971
+ ] });
2972
+ }
2973
+ var toGeocodeAddress = (address) => address ? {
2974
+ id: address.id,
2975
+ formattedAddress: address.formattedAddress,
2976
+ latitude: address.latitude,
2977
+ longitude: address.longitude
2978
+ } : null;
2979
+ function useForwardGeocode(client, query) {
2980
+ const [data, setData] = useState(null);
2981
+ const [loading, setLoading] = useState(false);
2982
+ const [error, setError] = useState(null);
2983
+ useEffect(() => {
2984
+ if (!query) {
2985
+ setData(null);
2986
+ setError(null);
2987
+ return;
2988
+ }
2989
+ const controller = new AbortController();
2990
+ async function fetch() {
2991
+ setLoading(true);
2992
+ setError(null);
2993
+ try {
2994
+ const response = await client.geocode.forward(
2995
+ { q: query },
2996
+ { signal: controller.signal }
2997
+ );
2998
+ if (controller.signal.aborted) {
2999
+ return;
3000
+ }
3001
+ setData(toGeocodeAddress(response.address));
3002
+ } catch (err) {
3003
+ if (controller.signal.aborted) {
3004
+ return;
3005
+ }
3006
+ setError(err instanceof Error ? err : new Error(String(err)));
3007
+ setData(null);
3008
+ } finally {
3009
+ if (!controller.signal.aborted) {
3010
+ setLoading(false);
3011
+ }
3012
+ }
3013
+ }
3014
+ fetch();
3015
+ return () => {
3016
+ controller.abort();
3017
+ };
3018
+ }, [client, query]);
3019
+ return { data, loading, error };
3020
+ }
3021
+ function ForwardGeocodeInput({
3022
+ client,
3023
+ query,
3024
+ onResult,
3025
+ className,
3026
+ disabled,
3027
+ placeholder = "Coordinates will appear here",
3028
+ id
3029
+ }) {
3030
+ const { data } = useForwardGeocode(client, query);
3031
+ useEffect(() => {
3032
+ onResult?.({
3033
+ latitude: data?.latitude ?? null,
3034
+ longitude: data?.longitude ?? null,
3035
+ formattedAddress: data?.formattedAddress ?? null
3036
+ });
3037
+ }, [data, onResult]);
3038
+ const displayText = data ? `${data.latitude.toFixed(4)}, ${data.longitude.toFixed(4)}` : "";
3039
+ return /* @__PURE__ */ jsx(
3040
+ "input",
3041
+ {
3042
+ className: cn(
3043
+ "block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
3044
+ className
3045
+ ),
3046
+ "data-slot": "geocode-input",
3047
+ disabled,
3048
+ id,
3049
+ placeholder,
3050
+ readOnly: true,
3051
+ type: "text",
3052
+ value: displayText
3053
+ }
3054
+ );
3055
+ }
3056
+ function ReverseGeocodeInput({
3057
+ client,
3058
+ latitude,
3059
+ longitude,
3060
+ onResult,
3061
+ className,
3062
+ disabled,
3063
+ placeholder = "Address will appear here",
3064
+ id
3065
+ }) {
3066
+ const { address, distance } = useReverseGeocode(
3067
+ client,
3068
+ latitude != null && longitude != null ? { lat: latitude, lng: longitude } : null
3069
+ );
3070
+ useEffect(() => {
3071
+ onResult?.({
3072
+ address: address?.formattedAddress ?? null,
3073
+ distance: distance ?? null
3074
+ });
3075
+ }, [address, distance, onResult]);
3076
+ const displayText = address?.formattedAddress ?? "";
3077
+ return /* @__PURE__ */ jsx(
3078
+ "input",
3079
+ {
3080
+ className: cn(
3081
+ "block h-8 w-full cursor-default rounded-none border border-input bg-muted/40 px-2.5 py-1 text-foreground text-xs",
3082
+ className
3083
+ ),
3084
+ "data-slot": "geocode-input",
3085
+ disabled,
3086
+ id,
3087
+ placeholder,
3088
+ readOnly: true,
3089
+ type: "text",
3090
+ value: displayText
3091
+ }
3092
+ );
3093
+ }
3102
3094
 
3103
3095
  export { AddressAutocomplete, AddressFieldGroup, AddressFormField, ForwardGeocodeInput, ReverseGeocodeInput, cn, toAddressWithParsed };
3104
3096
  //# sourceMappingURL=index.js.map