@dative-gpi/foundation-shared-components 1.0.33 → 1.0.35
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/components/FSClickable.vue +9 -0
- package/components/FSDialogFormBody.vue +4 -4
- package/components/FSDialogMultiFormBody.vue +3 -3
- package/components/FSDialogSubmit.vue +3 -3
- package/components/FSFadeOut.vue +10 -3
- package/components/autocompletes/FSAutocompleteLanguage.vue +18 -39
- package/components/autocompletes/FSAutocompleteTimeZone.vue +19 -37
- package/components/fields/FSAutocompleteField.vue +422 -254
- package/components/fields/FSAutocompleteTag.vue +100 -0
- package/components/fields/FSSelectField.vue +3 -3
- package/components/fields/FSTextField.vue +11 -7
- package/components/fields/FSTreeViewField.vue +3 -3
- package/components/fields/periodicField/FSPeriodicDailyField.vue +17 -10
- package/components/fields/periodicField/FSPeriodicMonthlyField.vue +29 -15
- package/components/fields/periodicField/FSPeriodicWeeklyField.vue +13 -7
- package/components/fields/periodicField/FSPeriodicYearlyField.vue +19 -10
- package/components/lists/FSFilterButton.vue +19 -20
- package/components/lists/FSHiddenButton.vue +10 -12
- package/components/map/FSMap.vue +240 -399
- package/components/map/FSMapFeatureGroup.vue +51 -0
- package/components/map/FSMapLayerButton.vue +2 -2
- package/components/map/FSMapMarker.vue +116 -0
- package/components/map/FSMapMarkerClusterGroup.vue +67 -0
- package/components/map/FSMapOverlay.vue +69 -83
- package/components/map/FSMapPolygon.vue +81 -0
- package/components/map/FSMapTileLayer.vue +50 -0
- package/components/map/keys.ts +4 -0
- package/composables/useAddress.ts +2 -2
- package/package.json +4 -4
- package/styles/components/fs_card.scss +0 -1
- package/styles/components/fs_clickable.scss +1 -1
- package/styles/components/fs_fade_out.scss +2 -1
- package/styles/components/fs_map.scss +36 -30
- package/styles/components/fs_tabs.scss +4 -0
- package/styles/components/index.scss +0 -1
- package/utils/leafletMarkers.ts +8 -2
- package/components/autocompletes/FSAutocompleteTag.vue +0 -138
- package/components/map/FSMapEditPointAddressOverlay.vue +0 -164
- package/styles/components/fs_map_overlay.scss +0 -38
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { inject, provide, ref, type Ref } from 'vue';
|
|
7
|
+
|
|
8
|
+
import { type Map, FeatureGroup } from 'leaflet';
|
|
9
|
+
import { INJECTION_FSMAP_MAP } from './keys';
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
name: 'FSMapFeatureGroup',
|
|
13
|
+
props: {
|
|
14
|
+
expectedLayers: {
|
|
15
|
+
type: Number,
|
|
16
|
+
default: 0,
|
|
17
|
+
required: false
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
setup(props, { emit }) {
|
|
21
|
+
const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
|
|
22
|
+
let added = false;
|
|
23
|
+
|
|
24
|
+
if(!map) {
|
|
25
|
+
throw new Error('FSMapFeatureGroup must be used inside a FSMap component');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if(!map.value) {
|
|
29
|
+
throw new Error('FSMapFeatureGroup must be used inside a FSMap component with a map');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const featureGroup = ref<FeatureGroup>(new FeatureGroup());
|
|
33
|
+
|
|
34
|
+
provide('featureGroup', featureGroup);
|
|
35
|
+
|
|
36
|
+
featureGroup.value.on("layeradd", () => {
|
|
37
|
+
if(!map.value) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const layers = featureGroup.value.getLayers();
|
|
42
|
+
|
|
43
|
+
if(layers.length === props.expectedLayers && !added) {
|
|
44
|
+
featureGroup.value.addTo(map.value);
|
|
45
|
+
added = true;
|
|
46
|
+
emit("update:bounds", featureGroup.value.getBounds());
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
</script>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { inject, type PropType, onMounted, type Ref, watch, ref } from 'vue';
|
|
7
|
+
|
|
8
|
+
import { type Map, type DivIcon, divIcon, type LatLng, marker, type Marker, type MarkerClusterGroup, type Layer } from 'leaflet';
|
|
9
|
+
|
|
10
|
+
import { useColors } from "../../composables";
|
|
11
|
+
|
|
12
|
+
import { gpsMarkerHtml, locationMarkerHtml, pinMarkerHtml } from '../../utils/leafletMarkers';
|
|
13
|
+
import { INJECTION_FSMAP_MAP, INJECTION_FSMAP_MARKERCLUSTERGROUP } from './keys';
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
name: 'FSMapMarker',
|
|
17
|
+
props: {
|
|
18
|
+
variant: {
|
|
19
|
+
type: String as PropType<'gps' | 'location' | 'pin'>,
|
|
20
|
+
default: 'location',
|
|
21
|
+
required: false
|
|
22
|
+
},
|
|
23
|
+
color: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: 'primary',
|
|
26
|
+
required: false
|
|
27
|
+
},
|
|
28
|
+
latlng: {
|
|
29
|
+
type: Object as PropType<Pick<LatLng, "lat" | "lng"> | null>,
|
|
30
|
+
required: true
|
|
31
|
+
},
|
|
32
|
+
icon: {
|
|
33
|
+
type: String,
|
|
34
|
+
required: false
|
|
35
|
+
},
|
|
36
|
+
selected: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: false,
|
|
39
|
+
required: false
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
emits: ['click'],
|
|
43
|
+
setup(props, { emit }) {
|
|
44
|
+
const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
|
|
45
|
+
const markerClusterGroup = inject<Ref<MarkerClusterGroup | null>>(INJECTION_FSMAP_MARKERCLUSTERGROUP, ref(null));
|
|
46
|
+
|
|
47
|
+
const { getColors } = useColors();
|
|
48
|
+
|
|
49
|
+
const lastMarker = ref<Marker | null>(null);
|
|
50
|
+
|
|
51
|
+
if(!map) {
|
|
52
|
+
throw new Error('FSMapTileLayer must be used inside a FSMap component');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if(!map.value) {
|
|
56
|
+
throw new Error('FSMapTileLayer must be used inside a FSMap component with a map');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const updateMarker = () => {
|
|
60
|
+
if(!map.value || !props.latlng) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if(lastMarker.value) {
|
|
65
|
+
if(markerClusterGroup && markerClusterGroup.value) {
|
|
66
|
+
markerClusterGroup.value.removeLayer(lastMarker.value);
|
|
67
|
+
} else {
|
|
68
|
+
map.value.removeLayer(lastMarker.value as Layer);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let icon: DivIcon | null = null;
|
|
73
|
+
if(props.variant === 'gps') {
|
|
74
|
+
const size = 16;
|
|
75
|
+
icon = divIcon({
|
|
76
|
+
html: gpsMarkerHtml(),
|
|
77
|
+
className: 'fs-map-mylocation',
|
|
78
|
+
iconSize: [size, size],
|
|
79
|
+
iconAnchor: [size / 2, size / 2],
|
|
80
|
+
});
|
|
81
|
+
} else if(props.variant === 'location' && props.icon) {
|
|
82
|
+
const size = 36;
|
|
83
|
+
icon = divIcon({
|
|
84
|
+
html: locationMarkerHtml(props.icon, getColors(props.color).base),
|
|
85
|
+
iconSize: [size, size],
|
|
86
|
+
className: props.selected ? 'fs-map-location fs-map-location-selected' : 'fs-map-location',
|
|
87
|
+
iconAnchor: [size / 2, size / 2],
|
|
88
|
+
});
|
|
89
|
+
} else {
|
|
90
|
+
const size = 20;
|
|
91
|
+
icon = divIcon({
|
|
92
|
+
html: pinMarkerHtml(getColors(props.color).base),
|
|
93
|
+
iconSize: [size, size],
|
|
94
|
+
className: props.selected ? 'fs-map-location fs-map-location-selected' : 'fs-map-location',
|
|
95
|
+
iconAnchor: [size / 2, size / 2],
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
lastMarker.value = marker(props.latlng, { icon });
|
|
100
|
+
lastMarker.value.on('click', (e) => {
|
|
101
|
+
emit('click', e);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if(markerClusterGroup && markerClusterGroup.value) {
|
|
105
|
+
lastMarker.value.addTo(markerClusterGroup.value);
|
|
106
|
+
} else {
|
|
107
|
+
lastMarker.value.addTo(map.value);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
onMounted(updateMarker);
|
|
112
|
+
|
|
113
|
+
watch(() => [props.variant, props.color, props.latlng, props.selected], updateMarker);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
</script>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { inject, provide, ref, type Ref } from 'vue';
|
|
7
|
+
|
|
8
|
+
import { type Map, MarkerClusterGroup, divIcon } from 'leaflet';
|
|
9
|
+
|
|
10
|
+
import { clusterMarkerHtml } from '../../utils/leafletMarkers';
|
|
11
|
+
import { INJECTION_FSMAP_MAP } from './keys';
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
name: 'FSMapMarkerClusterGroup',
|
|
15
|
+
props: {
|
|
16
|
+
expectedLayers: {
|
|
17
|
+
type: Number,
|
|
18
|
+
default: 0,
|
|
19
|
+
required: false
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
setup(props, { emit }) {
|
|
23
|
+
const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
|
|
24
|
+
let added = false;
|
|
25
|
+
|
|
26
|
+
if(!map) {
|
|
27
|
+
throw new Error('FSMapMarkerClusterGroup must be used inside a FSMap component');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if(!map.value) {
|
|
31
|
+
throw new Error('FSMapMarkerClusterGroup must be used inside a FSMap component with a map');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const markerClusterGroup = ref<MarkerClusterGroup>(new MarkerClusterGroup({
|
|
35
|
+
spiderfyOnMaxZoom: false,
|
|
36
|
+
showCoverageOnHover: false,
|
|
37
|
+
disableClusteringAtZoom: 17,
|
|
38
|
+
iconCreateFunction: function (cluster: any) {
|
|
39
|
+
const size = 36;
|
|
40
|
+
|
|
41
|
+
return divIcon({
|
|
42
|
+
html: clusterMarkerHtml(cluster.getChildCount()),
|
|
43
|
+
className: 'fs-map-location fs-map-location-full',
|
|
44
|
+
iconSize: [size, size],
|
|
45
|
+
iconAnchor: [size / 2, size / 2],
|
|
46
|
+
});
|
|
47
|
+
}}
|
|
48
|
+
));
|
|
49
|
+
|
|
50
|
+
provide('markerClusterGroup', markerClusterGroup);
|
|
51
|
+
|
|
52
|
+
markerClusterGroup.value.on("layeradd", () => {
|
|
53
|
+
if(!map.value) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const layers = markerClusterGroup.value.getLayers();
|
|
58
|
+
|
|
59
|
+
if(layers.length === props.expectedLayers && !added) {
|
|
60
|
+
markerClusterGroup.value.addTo(map.value);
|
|
61
|
+
added = true;
|
|
62
|
+
emit("update:bounds", markerClusterGroup.value.getBounds());
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
</script>
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<v-overlay
|
|
3
|
+
v-if="isExtraSmall"
|
|
4
|
+
:modelValue="$props.mode === 'expand'"
|
|
5
|
+
:contained="true"
|
|
6
|
+
@click="$emit('update:mode', 'collapse')"
|
|
7
|
+
zIndex="0"
|
|
8
|
+
/>
|
|
9
|
+
<div
|
|
3
10
|
v-show="isExtraSmall"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
width="hug"
|
|
8
|
-
gap="2px"
|
|
9
|
-
:height="$props.mode === 'expand' ? '100%' : ($props.mode === 'half' ? '50%' : 'hug')"
|
|
10
|
-
:id="`left-overlay-mobile-${$props.mapId}`"
|
|
11
|
-
:style="style"
|
|
12
|
-
@click="$event.target === mobileOverlayElement?.$el ? $emit('update:mode', 'collapse') : null"
|
|
11
|
+
ref="mobileOverlayWrapper"
|
|
12
|
+
class="fs-map-overlay-mobile"
|
|
13
|
+
:style="{ height: $props.mode === 'expand' ? '90%' : ($props.mode === 'half' ? '50%' : '20px') }"
|
|
13
14
|
>
|
|
14
15
|
<FSCard
|
|
15
|
-
|
|
16
|
+
width="100%"
|
|
17
|
+
height="100%"
|
|
16
18
|
:elevation="true"
|
|
17
19
|
:border="false"
|
|
18
20
|
>
|
|
19
21
|
<FSCol
|
|
20
|
-
height="
|
|
22
|
+
height="100%"
|
|
21
23
|
gap="0px"
|
|
22
24
|
>
|
|
23
25
|
<FSRow
|
|
@@ -31,62 +33,38 @@
|
|
|
31
33
|
/>
|
|
32
34
|
</FSRow>
|
|
33
35
|
<FSCol
|
|
34
|
-
|
|
36
|
+
v-if="$props.mode !== 'collapse'"
|
|
35
37
|
height="fill"
|
|
38
|
+
style="min-height: 0;"
|
|
36
39
|
>
|
|
37
40
|
<slot
|
|
38
|
-
name="
|
|
41
|
+
name="body"
|
|
39
42
|
/>
|
|
40
|
-
<FSFadeOut
|
|
41
|
-
maskHeight="0px"
|
|
42
|
-
:height="$props.mode === 'collapse' ? '0px' : '100%'"
|
|
43
|
-
>
|
|
44
|
-
<slot
|
|
45
|
-
name="leftoverlay-body"
|
|
46
|
-
/>
|
|
47
|
-
</FSFadeOut>
|
|
48
43
|
</FSCol>
|
|
49
44
|
</FSCol>
|
|
50
45
|
</FSCard>
|
|
51
|
-
</
|
|
52
|
-
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<FSCard
|
|
53
49
|
v-show="!isExtraSmall"
|
|
54
|
-
class="fs-map-overlay-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
:
|
|
58
|
-
:style="style"
|
|
50
|
+
class="fs-map-overlay-desktop"
|
|
51
|
+
ref="desktopOverlay"
|
|
52
|
+
:elevation="true"
|
|
53
|
+
:border="false"
|
|
59
54
|
>
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
:elevation="true"
|
|
63
|
-
:border="false"
|
|
55
|
+
<FSCol
|
|
56
|
+
height="fill"
|
|
64
57
|
>
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
/>
|
|
71
|
-
<FSFadeOut
|
|
72
|
-
maskHeight="0"
|
|
73
|
-
height="100%"
|
|
74
|
-
>
|
|
75
|
-
<slot
|
|
76
|
-
name="leftoverlay-body"
|
|
77
|
-
/>
|
|
78
|
-
</FSFadeOut>
|
|
79
|
-
</FSCol>
|
|
80
|
-
</FSCard>
|
|
81
|
-
</FSCol>
|
|
58
|
+
<slot
|
|
59
|
+
name="body"
|
|
60
|
+
/>
|
|
61
|
+
</FSCol>
|
|
62
|
+
</FSCard>
|
|
82
63
|
</template>
|
|
83
64
|
|
|
84
65
|
<script lang="ts">
|
|
85
|
-
import {
|
|
86
|
-
|
|
66
|
+
import { defineComponent, type PropType, onUnmounted, onMounted, ref } from "vue";
|
|
87
67
|
import { useBreakpoints } from "../../composables";
|
|
88
|
-
|
|
89
|
-
import FSFadeOut from "../FSFadeOut.vue";
|
|
90
68
|
import FSButton from "../FSButton.vue";
|
|
91
69
|
import FSCard from "../FSCard.vue";
|
|
92
70
|
import FSCol from "../FSCol.vue";
|
|
@@ -95,56 +73,64 @@ import FSRow from "../FSRow.vue";
|
|
|
95
73
|
export default defineComponent({
|
|
96
74
|
name: "FSMapOverlay",
|
|
97
75
|
props: {
|
|
98
|
-
height: {
|
|
99
|
-
type: [String, Number] as PropType<string | number | null>,
|
|
100
|
-
required: false,
|
|
101
|
-
default: "100%"
|
|
102
|
-
},
|
|
103
76
|
mode: {
|
|
104
77
|
type: String as PropType<"collapse" | "half" | "expand">,
|
|
105
78
|
required: false,
|
|
106
79
|
default: "collapse"
|
|
107
|
-
},
|
|
108
|
-
mapId: {
|
|
109
|
-
type: String,
|
|
110
|
-
required: true
|
|
111
80
|
}
|
|
112
81
|
},
|
|
113
82
|
components: {
|
|
114
|
-
FSFadeOut,
|
|
115
83
|
FSButton,
|
|
116
84
|
FSCard,
|
|
117
85
|
FSCol,
|
|
118
86
|
FSRow
|
|
119
87
|
},
|
|
120
|
-
emits: ["update:mode"],
|
|
121
|
-
setup(
|
|
88
|
+
emits: ["update:mode", "update:height", "update:width"],
|
|
89
|
+
setup(_, { emit }) {
|
|
122
90
|
const { isExtraSmall } = useBreakpoints();
|
|
123
91
|
|
|
124
|
-
const
|
|
125
|
-
const
|
|
92
|
+
const mobileOverlayWrapper = ref<HTMLDivElement | null>(null);
|
|
93
|
+
const desktopOverlay = ref<InstanceType<typeof FSCard> | null>(null);
|
|
94
|
+
|
|
95
|
+
const mobileResizeObserver = ref<ResizeObserver | null>(null);
|
|
96
|
+
const desktopResizeObserver = ref<ResizeObserver | null>(null);
|
|
97
|
+
|
|
98
|
+
onMounted(() => {
|
|
99
|
+
mobileResizeObserver.value = new ResizeObserver(entries => {
|
|
100
|
+
entries.forEach((entry) => {
|
|
101
|
+
emit("update:height", entry.contentRect.height);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
desktopResizeObserver.value = new ResizeObserver(entries => {
|
|
106
|
+
entries.forEach((entry) => {
|
|
107
|
+
emit("update:width", entry.contentRect.width);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (mobileOverlayWrapper.value) {
|
|
112
|
+
mobileResizeObserver.value.observe(mobileOverlayWrapper.value);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (desktopOverlay.value) {
|
|
116
|
+
desktopResizeObserver.value.observe(desktopOverlay.value.$el);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
126
119
|
|
|
127
|
-
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
"--fs-map-overlay-max-height": `calc(${props.height} - 40px)`,
|
|
131
|
-
"--fs-map-overlay-card-height": "95%",
|
|
132
|
-
};
|
|
120
|
+
onUnmounted((): void => {
|
|
121
|
+
if (mobileResizeObserver.value) {
|
|
122
|
+
mobileResizeObserver.value.disconnect();
|
|
133
123
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"--fs-map-overlay-max-height": `calc(${props.height} - 40px)`,
|
|
137
|
-
"--fs-map-overlay-card-height": "100%",
|
|
138
|
-
};
|
|
124
|
+
if (desktopResizeObserver.value) {
|
|
125
|
+
desktopResizeObserver.value.disconnect();
|
|
139
126
|
}
|
|
140
127
|
});
|
|
141
128
|
|
|
142
129
|
return {
|
|
143
|
-
leftOverlayMenuMobile,
|
|
144
|
-
mobileOverlayElement,
|
|
145
130
|
isExtraSmall,
|
|
146
|
-
|
|
131
|
+
mobileOverlayWrapper,
|
|
132
|
+
desktopOverlay
|
|
147
133
|
};
|
|
148
134
|
}
|
|
149
135
|
});
|
|
150
|
-
</script>
|
|
136
|
+
</script>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { inject, type PropType, onMounted, type Ref, watch, ref } from 'vue';
|
|
7
|
+
|
|
8
|
+
import { type Map, type LatLng, type Polygon, type FeatureGroup, polygon } from 'leaflet';
|
|
9
|
+
|
|
10
|
+
import { useColors } from "../../composables";
|
|
11
|
+
import { INJECTION_FSMAP_FEATUREGROUP, INJECTION_FSMAP_MAP } from './keys';
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
name: 'FSMapPolygon',
|
|
15
|
+
props: {
|
|
16
|
+
color: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: 'primary',
|
|
19
|
+
required: false
|
|
20
|
+
},
|
|
21
|
+
latlngs: {
|
|
22
|
+
type: Array as PropType<Pick<LatLng, "lat" | "lng">[] | null>,
|
|
23
|
+
required: true
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
emits: ['click'],
|
|
27
|
+
setup(props, { emit }) {
|
|
28
|
+
const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
|
|
29
|
+
const featureGroup = inject<Ref<FeatureGroup | null>>(INJECTION_FSMAP_FEATUREGROUP, ref(null));
|
|
30
|
+
|
|
31
|
+
const { getColors } = useColors();
|
|
32
|
+
|
|
33
|
+
const lastPolygon = ref<Polygon | null>(null);
|
|
34
|
+
|
|
35
|
+
if(!map) {
|
|
36
|
+
throw new Error('FSMapTileLayer must be used inside a FSMap component');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if(!map.value) {
|
|
40
|
+
throw new Error('FSMapTileLayer must be used inside a FSMap component with a map');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const updatePolygon = () => {
|
|
44
|
+
if(!map.value || !props.latlngs) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if(lastPolygon.value) {
|
|
49
|
+
if(featureGroup && featureGroup.value) {
|
|
50
|
+
featureGroup.value.removeLayer(lastPolygon.value);
|
|
51
|
+
} else {
|
|
52
|
+
map.value.removeLayer(lastPolygon.value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const color = getColors(props.color).base;
|
|
57
|
+
lastPolygon.value = polygon(props.latlngs.map((coord) => [coord.lat, coord.lng]), {
|
|
58
|
+
color: color,
|
|
59
|
+
fillColor: color + "50",
|
|
60
|
+
fillOpacity: 0.5,
|
|
61
|
+
className: 'fs-map-area',
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
lastPolygon.value.on('click', (e) => {
|
|
65
|
+
emit('click', e);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if(featureGroup && featureGroup.value) {
|
|
69
|
+
lastPolygon.value.addTo(featureGroup.value);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
lastPolygon.value.addTo(map.value);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
onMounted(updatePolygon);
|
|
77
|
+
|
|
78
|
+
watch(() => [props.color, props.latlngs], updatePolygon);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
</script>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { inject, type PropType, onMounted, type Ref, watch } from 'vue';
|
|
7
|
+
|
|
8
|
+
import type { Map, Layer } from 'leaflet';
|
|
9
|
+
|
|
10
|
+
import { INJECTION_FSMAP_MAP } from './keys';
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: 'FSMapTileLayer',
|
|
14
|
+
props: {
|
|
15
|
+
layer: {
|
|
16
|
+
type: Object as PropType<Layer>,
|
|
17
|
+
required: false
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
setup(props) {
|
|
21
|
+
const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
|
|
22
|
+
|
|
23
|
+
const lastLayer = props.layer;
|
|
24
|
+
|
|
25
|
+
if(!map) {
|
|
26
|
+
throw new Error('FSMapTileLayer must be used inside a FSMap component');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if(!map.value) {
|
|
30
|
+
throw new Error('FSMapTileLayer must be used inside a FSMap component with a map');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const updateLayer = () => {
|
|
34
|
+
if (!props.layer || !map.value) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if(lastLayer) {
|
|
39
|
+
map.value.removeLayer(lastLayer);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
props.layer.addTo(map.value);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
onMounted(updateLayer);
|
|
46
|
+
|
|
47
|
+
watch(() => props.layer, updateLayer);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Place } from "@dative-gpi/foundation-shared-domain/models";
|
|
2
|
-
import { Address } from "@dative-gpi/foundation-shared-domain/models";
|
|
3
1
|
import _ from "lodash";
|
|
4
2
|
|
|
3
|
+
import { Address, type Place } from "@dative-gpi/foundation-shared-domain/models";
|
|
4
|
+
|
|
5
5
|
export const useAddress = () => {
|
|
6
6
|
const enabled = true;
|
|
7
7
|
let initialized = false;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dative-gpi/foundation-shared-components",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.35",
|
|
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": "1.0.
|
|
14
|
-
"@dative-gpi/foundation-shared-services": "1.0.
|
|
13
|
+
"@dative-gpi/foundation-shared-domain": "1.0.35",
|
|
14
|
+
"@dative-gpi/foundation-shared-services": "1.0.35"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"@dative-gpi/bones-ui": "^0.0.75",
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"sass": "1.71.1",
|
|
36
36
|
"sass-loader": "13.3.2"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "10111fadbf8f2207213a9d5f13ae4c3c4f71f0bc"
|
|
39
39
|
}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
@extend .fs-hide-y-scrollbar;
|
|
3
3
|
|
|
4
4
|
transition: all 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
|
5
|
-
max-height: var(--fs-fade-out-height);
|
|
5
|
+
max-height: var(--fs-fade-out-max-height);
|
|
6
6
|
padding: var(--fs-fade-out-padding);
|
|
7
|
+
height: var(--fs-fade-out-height);
|
|
7
8
|
width: var(--fs-fade-out-width);
|
|
8
9
|
flex-direction: column;
|
|
9
10
|
position: relative;
|