@dative-gpi/foundation-shared-components 0.0.177 → 0.0.178

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.
@@ -68,7 +68,7 @@ export default defineComponent({
68
68
  variant: {
69
69
  type: String as PropType<"base" | "light" | "dark">,
70
70
  required: false,
71
- default: "dark"
71
+ default: "base"
72
72
  },
73
73
  vertical: {
74
74
  type: Boolean as PropType<boolean>,
@@ -114,4 +114,4 @@ export default defineComponent({
114
114
  };
115
115
  }
116
116
  });
117
- </script>
117
+ </script>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <FSAutocompleteField
3
+ :clearable="false"
4
+ :toggleSet="false"
5
+ :multiple="false"
6
+ :items="places"
7
+ :modelValue="modelValuePlace"
8
+ @update:modelValue="onUpdate"
9
+ v-model:search="search"
10
+ v-bind="$attrs"
11
+ />
12
+ </template>
13
+
14
+ <script lang="ts">
15
+ import { defineComponent, onMounted, ref, watch } from "vue";
16
+
17
+ import { useAutocomplete } from "@dative-gpi/foundation-shared-components/composables";
18
+ import { useAddress } from "../../composables/useAddress";
19
+
20
+ import type { Address, Place } from "@dative-gpi/foundation-shared-domain/models";
21
+
22
+ import FSAutocompleteField from "@dative-gpi/foundation-shared-components/components/fields/FSAutocompleteField.vue";
23
+
24
+ export default defineComponent({
25
+ name: "FSAutocompleteAddress",
26
+ components: {
27
+ FSAutocompleteField
28
+ },
29
+ props: {
30
+ modelValue: {
31
+ type: Function as () => Address | null,
32
+ required: false,
33
+ default: null
34
+ },
35
+ },
36
+ emits: ["update:modelValue"],
37
+ setup(props, { emit }) {
38
+ const { search: searchAddress, get: getAddress } = useAddress();
39
+
40
+ const places = ref<Place[]>([]);
41
+ const modelValuePlace = ref<Place | null>(null);
42
+
43
+ const innerFetch = async (search: string | null) => {
44
+ if (search === null) {
45
+ return Promise.resolve([]);
46
+ }
47
+ places.value = await searchAddress(search);
48
+ return Promise.resolve([]);
49
+ };
50
+
51
+ const innerUpdate = async (value: { id: string; label: string; } | { id: string; label: string; }[] | null) => {
52
+ if (value === null) {
53
+ emit("update:modelValue", null);
54
+ return;
55
+ }
56
+ if (Array.isArray(value)) {
57
+ value = value[0];
58
+ }
59
+ const address = await getAddress(value);
60
+ emit("update:modelValue", address );
61
+ };
62
+
63
+ const { search, onUpdate } = useAutocomplete(
64
+ places,
65
+ [],
66
+ emit,
67
+ innerFetch,
68
+ innerUpdate,
69
+ (item) => (item).id,
70
+ (item) => (item).label,
71
+ true,
72
+ false
73
+ );
74
+
75
+ const addressToPlace = (address: Address): Place => {
76
+ return {
77
+ id: address.placeId,
78
+ label: address.placeLabel
79
+ };
80
+ };
81
+
82
+ onMounted(() => {
83
+ if(!props.modelValue) {
84
+ return;
85
+ }
86
+ modelValuePlace.value = addressToPlace(props.modelValue);
87
+ });
88
+
89
+ watch(() => props.modelValue, (newValue) => {
90
+ if(!newValue) {
91
+ return;
92
+ }
93
+ modelValuePlace.value = addressToPlace(newValue);
94
+ });
95
+
96
+ return {
97
+ modelValuePlace,
98
+ places,
99
+ search,
100
+ onUpdate
101
+ };
102
+ }
103
+ });
104
+ </script>
@@ -314,6 +314,7 @@ import FSRow from "../FSRow.vue";
314
314
 
315
315
  export default defineComponent({
316
316
  name: "FSAutocompleteField",
317
+ inheritAttrs: false,
317
318
  components: {
318
319
  FSSearchField,
319
320
  FSDialogMenu,
@@ -355,7 +356,7 @@ export default defineComponent({
355
356
  default: "label"
356
357
  },
357
358
  modelValue: {
358
- type: [Array, String] as PropType<string[] | string | null>,
359
+ type: [Array, String, Object] as PropType<string[] | string | null | any>,
359
360
  required: false,
360
361
  default: null
361
362
  },
@@ -0,0 +1,113 @@
1
+ import type { Place } from "@dative-gpi/foundation-shared-domain/models";
2
+ import { Address } from "@dative-gpi/foundation-shared-domain/models";
3
+ import _ from "lodash";
4
+
5
+ export const useAddress = () => {
6
+ const enabled = true;
7
+ let initialized = false;
8
+ let searchService: google.maps.places.AutocompleteService;
9
+ let placeService: google.maps.places.PlacesService;
10
+ let sessionId: google.maps.places.AutocompleteSessionToken;
11
+
12
+ const init = async () => {
13
+ await window.initMap;
14
+ searchService = new google.maps.places.AutocompleteService();
15
+ placeService = new google.maps.places.PlacesService(
16
+ document.getElementById("places") as HTMLDivElement
17
+ );
18
+ sessionId = new google.maps.places.AutocompleteSessionToken();
19
+ initialized = true;
20
+ }
21
+
22
+
23
+ const search = async (search: string): Promise<Place[]> => {
24
+ if(!initialized){
25
+ await init();
26
+ }
27
+
28
+ return _search(search).then(result => {
29
+ return _.map(result, r => ({ id: r.place_id, label: r.description }));
30
+ }).catch(() => {
31
+ return [];
32
+ });
33
+ }
34
+
35
+ const get = async (place: Place): Promise<Address> => {
36
+ if(!initialized){
37
+ await init();
38
+ }
39
+
40
+ const response = await _get(place.id);
41
+ sessionId = new google.maps.places.AutocompleteSessionToken();
42
+ if (response.address_components && response.formatted_address && response.geometry) {
43
+ return new Address({
44
+ formattedAddress: response.formatted_address,
45
+ locality: _find(response.address_components, "locality"),
46
+ country: _find(response.address_components, "country"),
47
+ latitude: response.geometry.location?.lat() ?? 0,
48
+ longitude: response.geometry.location?.lng() ?? 0,
49
+
50
+ placeId: place.id,
51
+ placeLabel: place.label,
52
+ })
53
+ }
54
+ throw new Error("missing informations");
55
+ }
56
+
57
+ const _search = (search: string) => {
58
+ if (!enabled) {
59
+ throw new Error("offline mode, do not call this method");
60
+ }
61
+ return new Promise<google.maps.places.AutocompletePrediction[]>(
62
+ (resolve, reject) => {
63
+ searchService!.getPlacePredictions(
64
+ {
65
+ input: search,
66
+ sessionToken: sessionId!
67
+ },
68
+ function (result, status) {
69
+ if (status != google.maps.places.PlacesServiceStatus.OK || !result) {
70
+ reject(status);
71
+ } else {
72
+ resolve(result);
73
+ }
74
+ }
75
+ );
76
+ }
77
+ );
78
+ }
79
+
80
+ const _get = (id: string) => {
81
+ if (!enabled) {
82
+ throw new Error("offline mode, do not call this method");
83
+ }
84
+ return new Promise<google.maps.places.PlaceResult>((resolve, reject) => {
85
+ placeService!.getDetails(
86
+ {
87
+ placeId: id,
88
+ sessionToken: sessionId!,
89
+ fields: ["formatted_address", "geometry", "address_components", "name"]
90
+ },
91
+ (result, status) => {
92
+ if (status != google.maps.places.PlacesServiceStatus.OK || !result) {
93
+ reject(status);
94
+ } else {
95
+ resolve(result);
96
+ }
97
+ }
98
+ );
99
+ });
100
+ }
101
+
102
+ const _find = (components: google.maps.GeocoderAddressComponent[], type: string): string => {
103
+ const found = _.find(components, c =>
104
+ _.some(c.types, t => t === type)
105
+ );
106
+ return (found && found.long_name) || "";
107
+ }
108
+
109
+ return {
110
+ search,
111
+ get
112
+ }
113
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dative-gpi/foundation-shared-components",
3
3
  "sideEffects": false,
4
- "version": "0.0.177",
4
+ "version": "0.0.178",
5
5
  "description": "",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -10,8 +10,8 @@
10
10
  "author": "",
11
11
  "license": "ISC",
12
12
  "dependencies": {
13
- "@dative-gpi/foundation-shared-domain": "0.0.177",
14
- "@dative-gpi/foundation-shared-services": "0.0.177"
13
+ "@dative-gpi/foundation-shared-domain": "0.0.178",
14
+ "@dative-gpi/foundation-shared-services": "0.0.178"
15
15
  },
16
16
  "peerDependencies": {
17
17
  "@dative-gpi/bones-ui": "^0.0.75",
@@ -32,8 +32,9 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/color": "3.0.6",
35
+ "@types/google.maps": "^3.55.10",
35
36
  "sass": "1.71.1",
36
37
  "sass-loader": "13.3.2"
37
38
  },
38
- "gitHead": "74456c52854b727eb9ab7a7ccb4a264e8e4ed15f"
39
+ "gitHead": "965b5f2c9bdb926c03d5a17f94991d2fc2621e51"
39
40
  }
package/plugins/index.ts CHANGED
@@ -1 +1,2 @@
1
- export * from "./colorPlugin";
1
+ export * from "./colorPlugin";
2
+ export * from "./mapsPlugin";
@@ -0,0 +1,37 @@
1
+ import type { Plugin } from "vue";
2
+
3
+ export const MapsPlugin: Plugin = {
4
+ install: (_app, options: MapsOptions) => {
5
+ if(window?.initMap) {
6
+ return;
7
+ }
8
+ const key = options?.key ?? import.meta.env.VITE_GOOGLE_MAPS_API_KEY;
9
+ const maps = document.createElement("script");
10
+ maps.setAttribute(
11
+ "src",
12
+ `https://maps.googleapis.com/maps/api/js?key=${key}&loading=async&libraries=geometry,places`
13
+ );
14
+
15
+ let resolvePromise: (value: void) => void;
16
+
17
+ const promise = new Promise<void>((resolve) => {
18
+ resolvePromise = resolve;
19
+ });
20
+
21
+ window.initMap = promise;
22
+
23
+ maps.onload = () => {
24
+ resolvePromise();
25
+ };
26
+
27
+ document.head.appendChild(maps);
28
+
29
+ const autocomplete = document.createElement("div");
30
+ autocomplete.id = "places";
31
+ document.body.appendChild(autocomplete);
32
+ }
33
+ }
34
+
35
+ export interface MapsOptions {
36
+ key?: string;
37
+ }
package/shims-plugin.d.ts CHANGED
@@ -6,4 +6,6 @@ declare module "vue" {
6
6
  interface ComponentCustomProperties {
7
7
  $color: (key: ColorBase) => string;
8
8
  }
9
- }
9
+ }
10
+
11
+ declare module 'googlemaps';
@@ -0,0 +1,3 @@
1
+ declare interface Window {
2
+ initMap?: Promise<void>;
3
+ }