@mapcomponents/ra-geospatial 1.0.4 → 1.5.5

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.
Files changed (37) hide show
  1. package/.babelrc +12 -0
  2. package/.storybook/main.ts +19 -0
  3. package/.storybook/manager.js +6 -0
  4. package/.storybook/mapcomponents_logo.png +0 -0
  5. package/.storybook/preview.ts +27 -0
  6. package/.storybook/style.css +20 -0
  7. package/.storybook/wheregroupTheme.js +9 -0
  8. package/README.md +71 -1
  9. package/assets/ra_geospatial_screenshots.png +0 -0
  10. package/eslint.config.cjs +3 -0
  11. package/package.json +22 -35
  12. package/project.json +8 -0
  13. package/src/components/GeospatialInput.stories.tsx +83 -0
  14. package/src/components/GeospatialInput.tsx +14 -17
  15. package/src/components/GeospatialInputMap.tsx +172 -169
  16. package/src/components/GeospatialShow.stories.tsx +84 -0
  17. package/src/components/GeospatialShow.tsx +15 -17
  18. package/src/components/GeospatialShowMap.tsx +53 -58
  19. package/src/contexts/DataContext.jsx +66 -0
  20. package/src/contexts/dataProvider.tsx +30 -0
  21. package/src/contexts/lsDataProvider.js +142 -0
  22. package/src/decorators/ReactAdminDefaultDecorator.tsx +41 -0
  23. package/src/index.ts +2 -2
  24. package/src/layout/GisLayout.jsx +97 -0
  25. package/src/ra_components/Poi.tsx +42 -0
  26. package/src/ra_components/Property.tsx +42 -0
  27. package/src/ra_components/Route.tsx +42 -0
  28. package/src/ra_components/raGeospatialProps.ts +5 -0
  29. package/src/ra_components/raGeospatialWebGisProps.ts +5 -0
  30. package/src/types.d.ts +3 -2
  31. package/tsconfig.json +7 -101
  32. package/tsconfig.lib.json +29 -0
  33. package/vite.config.ts +49 -0
  34. package/dist/index.esm.js +0 -155
  35. package/dist/index.esm.js.map +0 -1
  36. package/package-lock.json +0 -16564
  37. package/rollup.config.js +0 -50
@@ -1,182 +1,185 @@
1
- import React, { useContext, useEffect, useRef, useState } from "react";
2
- import { InputProps, useInput, useRecordContext } from "react-admin";
1
+ import React, { useEffect, useState } from 'react';
2
+ import { InputProps, useInput, useRecordContext } from 'react-admin';
3
3
  import {
4
- stringify as wellknownStringify,
5
- parse as wellknownParse,
6
- GeoJSONGeometry,
7
- GeoJSONFeature,
8
- GeoJSONPoint,
9
- } from "wellknown";
4
+ parse as wellknownParse,
5
+ stringify as wellknownStringify,
6
+ } from 'wellknown';
7
+
10
8
  import {
11
- useMap,
12
- MapLibreMap,
13
- MlFeatureEditor,
14
- MlGeoJsonLayer,
15
- } from "@mapcomponents/react-maplibre";
16
- import { LngLatLike } from "maplibre-gl";
17
- import { feature, centroid } from "@turf/turf";
18
- import { Feature } from "@turf/helpers";
9
+ MapLibreMap,
10
+ MlFeatureEditor,
11
+ MlGeoJsonLayer,
12
+ useMap,
13
+ } from '@mapcomponents/react-maplibre';
14
+ import { LngLatLike } from 'maplibre-gl';
15
+ import { centroid, feature } from '@turf/turf';
16
+ import { Feature } from '@turf/helpers';
17
+ import { Geometry } from 'geojson';
19
18
 
20
19
  export interface GeospatialInputMapProps extends InputProps<any> {
21
- MapLibreMapProps?: React.ComponentProps<typeof MapLibreMap>;
22
- geometrytype?: "point" | "line" | "polygon";
23
- embeddedMap?: boolean;
24
- mapId?: string;
20
+ MapLibreMapProps?: React.ComponentProps<typeof MapLibreMap>;
21
+ geometrytype?: 'point' | 'line' | 'polygon';
22
+ embeddedMap?: boolean;
23
+ mapId?: string;
25
24
  }
26
25
 
27
26
  function GeospatialInputMap(props: GeospatialInputMapProps) {
28
- const source = props?.source;
29
- const record = useRecordContext();
30
- const mapHook = useMap({mapId:props?.mapId});
31
-
32
- const [geojson, setGeojson] = useState<typeof feature>();
33
- const [oldGeoJson, setOldGeoJson] = useState<typeof feature>();
34
- const {
35
- field: { name, onChange, ...rest },
36
- fieldState,
37
- formState,
38
- isRequired,
39
- } = useInput(props);
40
-
41
- useEffect(() => {
42
- if (typeof record === "undefined" || !record[source]) return;
43
-
44
- let _geoJson = {
45
- type: "Feature",
46
- properties: {},
47
- geometry: wellknownParse(record[source]),
48
- };
49
-
50
- setGeojson(_geoJson as unknown as typeof feature);
51
- setOldGeoJson(_geoJson as unknown as typeof feature);
52
- }, [record, props.source]);
53
-
54
- useEffect(() => {
55
- if (!mapHook.map) return;
56
-
57
- if (typeof record !== "undefined" && record[source]) {
58
- const _center = centroid(
59
- wellknownParse(record[source]) as typeof Feature
60
- );
61
-
62
- if (_center?.geometry?.coordinates) {
63
- mapHook.map.setCenter(_center.geometry.coordinates as LngLatLike);
64
- }
65
- }
66
- }, [mapHook.map]);
67
-
68
- return (
69
- <>
70
- {props.embeddedMap && (
71
- <MapLibreMap
72
- {...props?.MapLibreMapProps}
73
- options={{
74
- zoom: 14,
75
- style:
76
- "https://wms.wheregroup.com/tileserver/style/klokantech-basic.json",
77
- center: [0, 0],
78
- ...props?.MapLibreMapProps?.options,
79
- }}
80
- style={{
81
- width: "100%",
82
- height: "400px",
83
- ...props?.MapLibreMapProps?.style,
84
- }}
85
- />
86
- )}
87
-
88
- {props.type === "point" && (
89
- <>
90
- {oldGeoJson && (
91
- <MlGeoJsonLayer
92
- mapId={props?.mapId}
93
- geojson={oldGeoJson as typeof feature}
94
- paint={{
95
- "circle-radius": 8,
96
- "circle-color": "#6f6f96",
97
- "circle-stroke-color": "white",
98
- "circle-stroke-width": 3,
99
- "circle-opacity": 0.8,
100
- }}
101
- type="circle"
102
- insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
103
- />
104
- )}
105
-
106
- <MlFeatureEditor
107
- mapId={props?.mapId}
108
- geojson={geojson as typeof feature}
109
- mode={geojson ? "custom_select" : "draw_point"}
110
- onChange={(_geojson) => {
111
- if (typeof _geojson[0] !== "undefined") {
112
- onChange(wellknownStringify(_geojson[0] as GeoJSONGeometry));
113
- }
114
- }}
115
- />
116
- </>
117
- )}
118
- {props.type === "polygon" && (
119
- <>
120
- {oldGeoJson && (
121
- <MlGeoJsonLayer
122
- mapId={props?.mapId}
123
- geojson={oldGeoJson as typeof feature}
124
- paint={{
125
- "fill-color": "#6f6f96",
126
- "fill-opacity": 0.6,
127
- }}
128
- type="fill"
129
- insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
130
- />
131
- )}
132
-
133
- <MlFeatureEditor
134
- mapId={props?.mapId}
135
- geojson={geojson as typeof feature}
136
- mode={geojson ? "custom_select" : "draw_polygon"}
137
- onChange={(_geojson) => {
138
- if (typeof _geojson[0] !== "undefined") {
139
- onChange(wellknownStringify(_geojson[0] as GeoJSONGeometry));
140
- }
141
- }}
142
- />
143
- </>
144
- )}
145
- {props.type === "line" && (
146
- <>
147
- {oldGeoJson && (
148
- <MlGeoJsonLayer
149
- mapId={props?.mapId}
150
- geojson={oldGeoJson as typeof feature}
151
- paint={{
152
- "line-width": 6,
153
- "line-color": "#6f6f96",
154
- "line-opacity": 0.6,
155
- }}
156
- type="line"
157
- insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
158
- />
159
- )}
160
-
161
- <MlFeatureEditor
162
- mapId={props?.mapId}
163
- geojson={geojson as typeof feature}
164
- mode={geojson ? "custom_select" : "draw_line_string"}
165
- onChange={(_geojson) => {
166
- if (typeof _geojson[0] !== "undefined") {
167
- onChange(wellknownStringify(_geojson[0] as GeoJSONGeometry));
168
- }
169
- }}
170
- />
171
- </>
172
- )}
173
- </>
174
- );
27
+ const source = props?.source;
28
+ const record = useRecordContext();
29
+ const mapHook = useMap({ mapId: props?.mapId });
30
+
31
+ const [geojson, setGeojson] = useState<typeof feature>();
32
+ const [oldGeoJson, setOldGeoJson] = useState<typeof feature>();
33
+ const input = useInput(props);
34
+
35
+ const {
36
+ field: { onChange },
37
+ } = input;
38
+
39
+ useEffect(() => {
40
+ if (typeof record === 'undefined' || !record[source]) return;
41
+
42
+ const _geoJson = {
43
+ type: 'Feature',
44
+ properties: {},
45
+ geometry: wellknownParse(record[source]),
46
+ };
47
+
48
+ setGeojson(_geoJson as unknown as typeof feature);
49
+ setOldGeoJson(_geoJson as unknown as typeof feature);
50
+ }, [record, props.source]);
51
+
52
+ useEffect(() => {
53
+ if (!mapHook.map) return;
54
+
55
+ if (typeof record !== 'undefined' && record[source]) {
56
+ const _center = centroid(wellknownParse(record[source]) as typeof Feature);
57
+
58
+ if (_center?.geometry?.coordinates) {
59
+ mapHook.map.setCenter(_center.geometry.coordinates as LngLatLike);
60
+ }
61
+ }
62
+ }, [mapHook.map]);
63
+
64
+ return (
65
+ <>
66
+ {props.embeddedMap && (
67
+ <MapLibreMap
68
+ {...props?.MapLibreMapProps}
69
+ options={{
70
+ zoom: 14,
71
+ style: 'https://wms.wheregroup.com/tileserver/style/klokantech-basic.json',
72
+ center: Array.isArray(props?.MapLibreMapProps?.options?.center) && props.MapLibreMapProps.options.center.length === 2
73
+ ? [props.MapLibreMapProps.options.center[0], props.MapLibreMapProps.options.center[1]]
74
+ : [0, 0],
75
+ ...props?.MapLibreMapProps?.options,
76
+ }}
77
+ style={{
78
+ width: '100%',
79
+ height: '400px',
80
+ ...props?.MapLibreMapProps?.style,
81
+ }}
82
+ />
83
+ )}
84
+
85
+ {props.type === 'point' && (
86
+ <>
87
+ {oldGeoJson && (
88
+ <MlGeoJsonLayer
89
+ mapId={props?.mapId}
90
+ geojson={oldGeoJson as typeof feature}
91
+ options={{
92
+ paint: {
93
+ 'circle-radius': 8,
94
+ 'circle-color': '#6f6f96',
95
+ 'circle-stroke-color': 'white',
96
+ 'circle-stroke-width': 3,
97
+ 'circle-opacity': 0.8,
98
+ },
99
+ }}
100
+ type="circle"
101
+ insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
102
+ />
103
+ )}
104
+
105
+ <MlFeatureEditor
106
+ mapId={props?.mapId}
107
+ geojson={geojson as typeof feature}
108
+ mode={geojson ? 'simple_select' : 'draw_point'}
109
+ onChange={(_geojson) => {
110
+ if (typeof _geojson[0] !== 'undefined') {
111
+ onChange(wellknownStringify(_geojson[0] as unknown as Geometry));
112
+ }
113
+ }}
114
+ />
115
+ </>
116
+ )}
117
+ {props.type === 'polygon' && (
118
+ <>
119
+ {oldGeoJson && (
120
+ <MlGeoJsonLayer
121
+ mapId={props?.mapId}
122
+ geojson={oldGeoJson as typeof feature}
123
+ options={{
124
+ paint: {
125
+ 'fill-color': '#6f6f96',
126
+ 'fill-opacity': 0.6,
127
+ },
128
+ }}
129
+ type="fill"
130
+ insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
131
+ />
132
+ )}
133
+
134
+ <MlFeatureEditor
135
+ mapId={props?.mapId}
136
+ geojson={geojson as typeof feature}
137
+ mode={geojson ? 'simple_select' : 'draw_polygon'}
138
+ onChange={(_geojson) => {
139
+ if (typeof _geojson[0] !== 'undefined') {
140
+ onChange(wellknownStringify(_geojson[0] as unknown as Geometry));
141
+ }
142
+ }}
143
+ />
144
+ </>
145
+ )}
146
+ {props.type === 'line' && (
147
+ <>
148
+ {oldGeoJson && (
149
+ <MlGeoJsonLayer
150
+ mapId={props?.mapId}
151
+ geojson={oldGeoJson as typeof feature}
152
+ options={{
153
+ paint: {
154
+ 'line-width': 6,
155
+ 'line-color': '#6f6f96',
156
+ 'line-opacity': 0.6,
157
+ },
158
+ }}
159
+ type="line"
160
+ insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
161
+ />
162
+ )}
163
+
164
+ <MlFeatureEditor
165
+ mapId={props?.mapId}
166
+ geojson={geojson as typeof feature}
167
+ mode={geojson ? 'simple_select' : 'draw_line_string'}
168
+ onChange={(_geojson) => {
169
+ if (typeof _geojson[0] !== 'undefined') {
170
+ onChange(wellknownStringify(_geojson[0] as unknown as Geometry));
171
+ }
172
+ }}
173
+ />
174
+ </>
175
+ )}
176
+ </>
177
+ );
175
178
  }
176
179
 
177
180
  GeospatialInputMap.defaultProps = {
178
- type: "point",
179
- embeddedMap: true,
181
+ type: 'point',
182
+ embeddedMap: true,
180
183
  };
181
184
 
182
185
  export default GeospatialInputMap;
@@ -0,0 +1,84 @@
1
+ import type { Meta } from '@storybook/react';
2
+ import GeospatialShow from './GeospatialShow';
3
+ import { ReactAdminDefaultDecorator } from '../decorators/ReactAdminDefaultDecorator';
4
+ import { PoiShow, PoiShowWebGis } from '../ra_components/Poi';
5
+ import { PropertyShow, PropertyShowWebGis } from '../ra_components/Property';
6
+ import { RouteShow, RouteShowWebGis } from '../ra_components/Route';
7
+ import GisLayout from '../layout/GisLayout';
8
+
9
+ const meta = {
10
+ component: GeospatialShow,
11
+ title: 'MapComponents/GeospatialShow',
12
+ decorators: [ReactAdminDefaultDecorator],
13
+ } satisfies Meta<typeof GeospatialShow>;
14
+
15
+ export default meta;
16
+
17
+ export const PoisShow = PoiShow.bind({});
18
+
19
+ PoisShow.args = {
20
+ primary: true,
21
+ embeddedMap: true,
22
+ };
23
+
24
+ PoisShow.parameters = {
25
+ name: 'pois',
26
+ };
27
+
28
+ export const PropertiesShow = PropertyShow.bind({});
29
+
30
+ PropertiesShow.args = {
31
+ primary: true,
32
+ embeddedMap: true,
33
+ };
34
+
35
+ PropertiesShow.parameters = {
36
+ name: 'properties',
37
+ };
38
+
39
+ export const RoutesShow = RouteShow.bind({});
40
+
41
+ RoutesShow.args = {
42
+ primary: true,
43
+ embeddedMap: true,
44
+ };
45
+
46
+ RoutesShow.parameters = {
47
+ name: 'routes',
48
+ };
49
+
50
+ export const PoisShowGIS = PoiShowWebGis.bind({});
51
+
52
+ PoisShowGIS.args = {
53
+ primary: true,
54
+ embeddedMap: false,
55
+ };
56
+
57
+ PoisShowGIS.parameters = {
58
+ name: 'pois',
59
+ layout: GisLayout,
60
+ };
61
+
62
+ export const PropertiesShowGIS = PropertyShowWebGis.bind({});
63
+
64
+ PropertiesShowGIS.args = {
65
+ primary: true,
66
+ embeddedMap: false,
67
+ };
68
+
69
+ PropertiesShowGIS.parameters = {
70
+ name: 'properties',
71
+ layout: GisLayout,
72
+ };
73
+
74
+ export const RoutesShowGIS = RouteShowWebGis.bind({});
75
+
76
+ RoutesShowGIS.args = {
77
+ primary: true,
78
+ embeddedMap: false,
79
+ };
80
+
81
+ RoutesShowGIS.parameters = {
82
+ name: 'routes',
83
+ layout: GisLayout,
84
+ };
@@ -1,24 +1,22 @@
1
- import React from "react";
2
- import { MapComponentsProvider } from "@mapcomponents/react-maplibre";
3
- import GeometryShowMap, {
4
- GeospatialShowMapProps,
5
- } from "./GeospatialShowMap.js";
1
+ import { MapComponentsProvider } from '@mapcomponents/react-maplibre';
2
+ import GeometryShowMap, { GeospatialShowMapProps } from './GeospatialShowMap.js';
6
3
 
7
4
  function GeospatialShow(props: GeospatialShowMapProps) {
8
- return (
9
- <>
10
- {props.embeddedMap ? (
11
- <MapComponentsProvider>
12
- <GeometryShowMap {...props} />
13
- </MapComponentsProvider>
14
- ) : (
15
- <GeometryShowMap {...props} />
16
- )}
17
- </>
18
- );
5
+ return (
6
+ <>
7
+ {props.embeddedMap ? (
8
+ <MapComponentsProvider>
9
+ <GeometryShowMap {...props} />
10
+ </MapComponentsProvider>
11
+ ) : (
12
+ <GeometryShowMap {...props} />
13
+ )}
14
+ </>
15
+ );
19
16
  }
20
17
  GeospatialShow.defaultProps = {
21
- embeddedMap: true,
18
+ embeddedMap: true,
22
19
  };
23
20
 
24
21
  export default GeospatialShow;
22
+
@@ -1,74 +1,69 @@
1
- import React, { useEffect, useState } from "react";
2
- import { InputProps, useRecordContext } from "react-admin";
3
- import { parse as wellknownParse, GeoJSONPoint } from "wellknown";
4
- import {
5
- MapLibreMap,
6
- MlGeoJsonLayer,
7
- useMap,
8
- } from "@mapcomponents/react-maplibre";
9
- import { LngLatLike } from "maplibre-gl";
10
- import { feature, centroid } from "@turf/turf";
11
- import { Feature } from "@turf/helpers";
1
+ import React, { useEffect, useState } from 'react';
2
+ import { InputProps, useRecordContext } from 'react-admin';
3
+ import { parse as wellknownParse } from 'wellknown';
4
+ import { MapLibreMap, MlGeoJsonLayer, useMap } from '@mapcomponents/react-maplibre';
5
+ import { LngLatLike } from 'maplibre-gl';
6
+ import { feature, centroid } from '@turf/turf';
7
+ import { Feature } from '@turf/helpers';
12
8
 
13
9
  export interface GeospatialShowMapProps extends InputProps<any> {
14
- MapLibreMapProps?: React.ComponentProps<typeof MapLibreMap>;
15
- embeddedMap?: boolean;
16
- mapId?: string;
10
+ MapLibreMapProps?: React.ComponentProps<typeof MapLibreMap>;
11
+ embeddedMap?: boolean;
12
+ mapId?: string;
17
13
  }
18
14
 
19
15
  function GeospatialShowMap(props: GeospatialShowMapProps) {
20
- const source = props.source;
21
- const record = useRecordContext();
22
- const mapHook = useMap();
16
+ const source = props.source;
17
+ const record = useRecordContext();
18
+ const mapHook = useMap();
23
19
 
24
- const [geojson, setGeojson] = useState<typeof feature>();
25
- useEffect(() => {
26
- if (!record?.[source]) return;
20
+ const [geojson, setGeojson] = useState<typeof feature>();
21
+ useEffect(() => {
22
+ if (!record?.[source]) return;
27
23
 
28
- const _geometry = wellknownParse(record[source]);
24
+ const _geometry = wellknownParse(record[source]);
29
25
 
30
- if (_geometry) {
31
- setGeojson({
32
- type: "Feature",
33
- properties: {},
34
- geometry: _geometry,
35
- } as unknown as typeof feature);
36
- }
37
- }, [record]);
26
+ if (_geometry) {
27
+ setGeojson({
28
+ type: 'Feature',
29
+ properties: {},
30
+ geometry: _geometry,
31
+ } as unknown as typeof feature);
32
+ }
33
+ }, [record]);
38
34
 
39
- useEffect(() => {
40
- if (!mapHook.map || !geojson) return;
35
+ useEffect(() => {
36
+ if (!mapHook.map || !geojson) return;
41
37
 
42
- const _center = centroid(geojson as typeof Feature);
38
+ const _center = centroid(geojson as typeof Feature);
43
39
 
44
- if (_center?.geometry?.coordinates) {
45
- mapHook.map.setCenter(_center.geometry.coordinates as LngLatLike);
46
- }
47
- }, [mapHook.map, geojson]);
40
+ if (_center?.geometry?.coordinates) {
41
+ mapHook.map.setCenter(_center.geometry.coordinates as LngLatLike);
42
+ }
43
+ }, [mapHook.map, geojson]);
48
44
 
49
- return (
50
- <>
51
- {props.embeddedMap && (
52
- <MapLibreMap
53
- {...props?.MapLibreMapProps}
54
- options={{
55
- zoom: 14,
56
- style:
57
- "https://wms.wheregroup.com/tileserver/style/klokantech-basic.json",
58
- center: [0, 0],
59
- ...props?.MapLibreMapProps?.options,
60
- }}
61
- style={{
62
- width: "100%",
63
- height: "400px",
64
- ...props?.MapLibreMapProps?.style,
65
- }}
66
- />
67
- )}
45
+ return (
46
+ <>
47
+ {props.embeddedMap && (
48
+ <MapLibreMap
49
+ {...props?.MapLibreMapProps}
50
+ options={{
51
+ zoom: 14,
52
+ style: 'https://wms.wheregroup.com/tileserver/style/klokantech-basic.json',
53
+ center: [0, 0],
54
+ ...props?.MapLibreMapProps?.options,
55
+ }}
56
+ style={{
57
+ width: '100%',
58
+ height: '400px',
59
+ ...props?.MapLibreMapProps?.style,
60
+ }}
61
+ />
62
+ )}
68
63
 
69
- {geojson && <MlGeoJsonLayer geojson={geojson}></MlGeoJsonLayer>}
70
- </>
71
- );
64
+ {geojson && <MlGeoJsonLayer geojson={geojson}></MlGeoJsonLayer>}
65
+ </>
66
+ );
72
67
  }
73
68
 
74
69
  export default GeospatialShowMap;