@mapcomponents/ra-geospatial 1.0.4 → 1.5.0-2

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 +25 -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 +21 -35
  12. package/project.json +14 -0
  13. package/src/components/GeospatialInput.stories.tsx +83 -0
  14. package/src/components/GeospatialInput.tsx +14 -17
  15. package/src/components/GeospatialInputMap.tsx +175 -170
  16. package/src/components/GeospatialShow.stories.tsx +84 -0
  17. package/src/components/GeospatialShow.tsx +14 -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 +138 -0
  22. package/src/decorators/ReactAdminDefaultDecorator.tsx +40 -0
  23. package/src/index.ts +2 -2
  24. package/src/layout/GisLayout.jsx +90 -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,187 @@
1
- import React, { useContext, useEffect, useRef, useState } from "react";
2
- import { InputProps, useInput, useRecordContext } from "react-admin";
3
- import {
4
- stringify as wellknownStringify,
5
- parse as wellknownParse,
6
- GeoJSONGeometry,
7
- GeoJSONFeature,
8
- GeoJSONPoint,
9
- } from "wellknown";
1
+ import React, { useEffect, useState } from 'react';
2
+ import { InputProps, useInput, useRecordContext } from 'react-admin';
3
+ import { parse as wellknownParse, stringify as wellknownStringify } from 'wellknown';
4
+
10
5
  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";
6
+ MapLibreMap,
7
+ MlFeatureEditor,
8
+ MlGeoJsonLayer,
9
+ useMap,
10
+ } from '@mapcomponents/react-maplibre';
11
+ import { LngLatLike } from 'maplibre-gl';
12
+ import { centroid, feature } from '@turf/turf';
13
+ import { Feature } from '@turf/helpers';
14
+ import { Geometry } from 'geojson';
19
15
 
20
16
  export interface GeospatialInputMapProps extends InputProps<any> {
21
- MapLibreMapProps?: React.ComponentProps<typeof MapLibreMap>;
22
- geometrytype?: "point" | "line" | "polygon";
23
- embeddedMap?: boolean;
24
- mapId?: string;
17
+ MapLibreMapProps?: React.ComponentProps<typeof MapLibreMap>;
18
+ geometrytype?: 'point' | 'line' | 'polygon';
19
+ embeddedMap?: boolean;
20
+ mapId?: string;
25
21
  }
26
22
 
27
23
  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
- );
24
+ const source = props?.source;
25
+ const record = useRecordContext();
26
+ const mapHook = useMap({ mapId: props?.mapId });
27
+
28
+ const [geojson, setGeojson] = useState<typeof feature>();
29
+ const [oldGeoJson, setOldGeoJson] = useState<typeof feature>();
30
+ const input = useInput(props);
31
+
32
+ const {
33
+ field: { onChange },
34
+ } = input;
35
+
36
+ useEffect(() => {
37
+ if (typeof record === 'undefined' || !record[source]) return;
38
+
39
+ const _geoJson = {
40
+ type: 'Feature',
41
+ properties: {},
42
+ geometry: wellknownParse(record[source]),
43
+ };
44
+
45
+ setGeojson(_geoJson as unknown as typeof feature);
46
+ setOldGeoJson(_geoJson as unknown as typeof feature);
47
+ }, [record, props.source]);
48
+
49
+ useEffect(() => {
50
+ if (!mapHook.map) return;
51
+
52
+ if (typeof record !== 'undefined' && record[source]) {
53
+ const _center = centroid(wellknownParse(record[source]) as typeof Feature);
54
+
55
+ if (_center?.geometry?.coordinates) {
56
+ mapHook.map.setCenter(_center.geometry.coordinates as LngLatLike);
57
+ }
58
+ }
59
+ }, [mapHook.map]);
60
+
61
+ return (
62
+ <>
63
+ {props.embeddedMap && (
64
+ <MapLibreMap
65
+ {...props?.MapLibreMapProps}
66
+ options={{
67
+ zoom: 14,
68
+ style: 'https://wms.wheregroup.com/tileserver/style/klokantech-basic.json',
69
+ center:
70
+ Array.isArray(props?.MapLibreMapProps?.options?.center) &&
71
+ props.MapLibreMapProps.options.center.length === 2
72
+ ? [
73
+ props.MapLibreMapProps.options.center[0],
74
+ props.MapLibreMapProps.options.center[1],
75
+ ]
76
+ : [0, 0],
77
+ ...props?.MapLibreMapProps?.options,
78
+ }}
79
+ style={{
80
+ width: '100%',
81
+ height: '400px',
82
+ ...props?.MapLibreMapProps?.style,
83
+ }}
84
+ />
85
+ )}
86
+
87
+ {props.type === 'point' && (
88
+ <>
89
+ {oldGeoJson && (
90
+ <MlGeoJsonLayer
91
+ mapId={props?.mapId}
92
+ geojson={oldGeoJson as typeof feature}
93
+ options={{
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
+ }}
102
+ type="circle"
103
+ insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
104
+ />
105
+ )}
106
+
107
+ <MlFeatureEditor
108
+ mapId={props?.mapId}
109
+ geojson={geojson as typeof feature}
110
+ mode={geojson ? 'simple_select' : 'draw_point'}
111
+ onChange={(_geojson) => {
112
+ if (typeof _geojson[0] !== 'undefined') {
113
+ onChange(wellknownStringify(_geojson[0] as unknown as Geometry));
114
+ }
115
+ }}
116
+ />
117
+ </>
118
+ )}
119
+ {props.type === 'polygon' && (
120
+ <>
121
+ {oldGeoJson && (
122
+ <MlGeoJsonLayer
123
+ mapId={props?.mapId}
124
+ geojson={oldGeoJson as typeof feature}
125
+ options={{
126
+ paint: {
127
+ 'fill-color': '#6f6f96',
128
+ 'fill-opacity': 0.6,
129
+ },
130
+ }}
131
+ type="fill"
132
+ insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
133
+ />
134
+ )}
135
+
136
+ <MlFeatureEditor
137
+ mapId={props?.mapId}
138
+ geojson={geojson as typeof feature}
139
+ mode={geojson ? 'simple_select' : 'draw_polygon'}
140
+ onChange={(_geojson) => {
141
+ if (typeof _geojson[0] !== 'undefined') {
142
+ onChange(wellknownStringify(_geojson[0] as unknown as Geometry));
143
+ }
144
+ }}
145
+ />
146
+ </>
147
+ )}
148
+ {props.type === 'line' && (
149
+ <>
150
+ {oldGeoJson && (
151
+ <MlGeoJsonLayer
152
+ mapId={props?.mapId}
153
+ geojson={oldGeoJson as typeof feature}
154
+ options={{
155
+ paint: {
156
+ 'line-width': 6,
157
+ 'line-color': '#6f6f96',
158
+ 'line-opacity': 0.6,
159
+ },
160
+ }}
161
+ type="line"
162
+ insertBeforeLayer="gl-draw-polygon-fill-inactive.cold"
163
+ />
164
+ )}
165
+
166
+ <MlFeatureEditor
167
+ mapId={props?.mapId}
168
+ geojson={geojson as typeof feature}
169
+ mode={geojson ? 'simple_select' : 'draw_line_string'}
170
+ onChange={(_geojson) => {
171
+ if (typeof _geojson[0] !== 'undefined') {
172
+ onChange(wellknownStringify(_geojson[0] as unknown as Geometry));
173
+ }
174
+ }}
175
+ />
176
+ </>
177
+ )}
178
+ </>
179
+ );
175
180
  }
176
181
 
177
182
  GeospatialInputMap.defaultProps = {
178
- type: "point",
179
- embeddedMap: true,
183
+ type: 'point',
184
+ embeddedMap: true,
180
185
  };
181
186
 
182
187
  export default GeospatialInputMap;
@@ -0,0 +1,84 @@
1
+ import type { Meta } from '@storybook/react-vite';
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,21 @@
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;
@@ -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;