@open-pioneer/map 1.3.0-dev.20260207195315 → 1.3.0-dev.20260211111005

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/CHANGELOG.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # @open-pioneer/map
2
2
 
3
- ## 1.3.0-dev.20260207195315
3
+ ## 1.3.0-dev.20260211111005
4
4
 
5
5
  ### Minor Changes
6
6
 
7
+ - 9b5d5f3: Support for new common container props (role, aria-_, data-_ and css)
7
8
  - 2ceb1ca: MapModel: implement new `loading` property.
8
9
  This property is `true` if the map is currently loading any resources, `false` otherwise.
9
10
  The property is based on OpenLayers `loadstart` and `loadend` events (see [Documentation](https://openlayers.org/en/latest/apidoc/module-ol_MapEvent-MapEvent.html#event:loadstart)).
11
+ - d54ccfd: Update to Chakra UI 3.32.0
10
12
  - 2ceb1ca: MapContainer: allow configuration of `rootProps` and `containerProps`.
11
13
  This can be used to set custom attributes on the respective DOM elements.
12
14
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@open-pioneer/map",
4
- "version": "1.3.0-dev.20260207195315",
4
+ "version": "1.3.0-dev.20260211111005",
5
5
  "description": "This package integrates OpenLayers maps into an open pioneer trails application.",
6
6
  "keywords": [
7
7
  "open-pioneer-trails"
@@ -14,15 +14,16 @@
14
14
  "directory": "src/packages/map"
15
15
  },
16
16
  "dependencies": {
17
- "@chakra-ui/react": "^3.31.0",
18
- "@open-pioneer/core": "^4.4.0",
19
- "@open-pioneer/http": "^4.4.0",
20
- "@open-pioneer/react-utils": "^4.4.0",
21
- "@open-pioneer/runtime": "^4.4.0",
17
+ "@chakra-ui/react": "^3.32.0",
18
+ "@open-pioneer/core": "4.5.0-dev.20260211105402",
19
+ "@open-pioneer/http": "4.5.0-dev.20260211105402",
20
+ "@open-pioneer/react-utils": "4.5.0-dev.20260211105402",
21
+ "@open-pioneer/reactivity": "4.5.0-dev.20260211105402",
22
+ "@open-pioneer/runtime": "4.5.0-dev.20260211105402",
22
23
  "ol": "^10.7.0",
23
24
  "proj4": "^2.20.2",
24
- "react": "^19.2.3",
25
- "react-dom": "^19.2.3",
25
+ "react": "^19.2.4",
26
+ "react-dom": "^19.2.4",
26
27
  "react-use": "^17.6.0",
27
28
  "uuid": "^13.0.0",
28
29
  "@conterra/reactivity-core": "^0.8.1",
package/ui/MapAnchor.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { Box } from '@chakra-ui/react';
3
- import { useCommonComponentProps } from '@open-pioneer/react-utils';
3
+ import { useCommonComponentProps, mergeChakraProps } from '@open-pioneer/react-utils';
4
4
  import { useMemo } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { computeMapAnchorStyles } from './computeMapAnchorStyles.js';
@@ -11,14 +11,17 @@ function MapAnchor(props) {
11
11
  const { position = defaultPosition, children, horizontalGap, verticalGap } = props;
12
12
  const { containerProps } = useCommonComponentProps("map-anchor", props);
13
13
  const { mapAnchorsHost } = useMapContainerContext();
14
- const styleProps = useMemo(
14
+ const css = useMemo(
15
15
  () => computeMapAnchorStyles(position, horizontalGap, verticalGap),
16
16
  [position, horizontalGap, verticalGap]
17
17
  );
18
- return createPortal(
19
- /* @__PURE__ */ jsx(Box, { ...containerProps, ...styleProps, children }),
20
- mapAnchorsHost
18
+ const boxProps = mergeChakraProps(
19
+ {
20
+ css
21
+ },
22
+ containerProps
21
23
  );
24
+ return createPortal(/* @__PURE__ */ jsx(Box, { ...boxProps, children }), mapAnchorsHost);
22
25
  }
23
26
 
24
27
  export { MapAnchor };
@@ -1 +1 @@
1
- {"version":3,"file":"MapAnchor.js","sources":["MapAnchor.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box } from \"@chakra-ui/react\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { ReactNode, useMemo } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { computeMapAnchorStyles } from \"./computeMapAnchorStyles\";\nimport { useMapContainerContext } from \"./MapContainerContext\";\n\n/**\n * The position of an anchor on the map.\n *\n * This is either a predefined position (like a corner) or a completely manual position.\n *\n * @group UI Components and Hooks\n */\nexport type MapAnchorPosition =\n | \"manual\"\n | \"top-left\"\n | \"top-right\"\n | \"top-center\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"bottom-center\"\n | \"left-center\"\n | \"right-center\"\n | \"center\";\n\nconst defaultPosition: MapAnchorPosition = \"top-right\";\n\n/**\n * @group UI Components and Hooks\n */\nexport interface MapAnchorProps extends CommonComponentProps {\n /**\n * The position of the anchor container above the map.\n *\n * Use `manual` if you wish to position the anchor manually using absolute positioning.\n * This can be achieved by configuring a css class on the map anchor and using css properties like `left`, `top`, etc.\n *\n * @default \"top-right\"\n */\n position?: MapAnchorPosition;\n\n /**\n * Horizontal gap in pixel applied to anchor container.\n * Only interpreted if a non-manual position is used.\n *\n * @default 0\n */\n horizontalGap?: number;\n\n /**\n * Vertical gap in pixel applied to anchor container.\n * Only interpreted if a non-manual position is used.\n *\n * @default 0 (If positioned at the bottom, default verticalGap == `30`)\n */\n verticalGap?: number;\n\n children?: ReactNode;\n}\n\n/**\n * A map anchor is a layout component that sits on top of the map.\n *\n * It can be used to position widgets (such as zoom buttons) at a specific location.\n *\n * Map anchors respect the map's current _view padding_.\n *\n * @group UI Components and Hooks\n */\nexport function MapAnchor(props: MapAnchorProps): ReactNode {\n const { position = defaultPosition, children, horizontalGap, verticalGap } = props;\n const { containerProps } = useCommonComponentProps(\"map-anchor\", props);\n const { mapAnchorsHost } = useMapContainerContext();\n const styleProps = useMemo(\n () => computeMapAnchorStyles(position, horizontalGap, verticalGap),\n [position, horizontalGap, verticalGap]\n );\n\n return createPortal(\n <Box {...containerProps} {...styleProps}>\n {children}\n </Box>,\n mapAnchorsHost\n );\n}\n"],"names":[],"mappings":";;;;;;;;AA4BA,MAAM,eAAA,GAAqC,WAAA;AA4CpC,SAAS,UAAU,KAAA,EAAkC;AACxD,EAAA,MAAM,EAAE,QAAA,GAAW,eAAA,EAAiB,QAAA,EAAU,aAAA,EAAe,aAAY,GAAI,KAAA;AAC7E,EAAA,MAAM,EAAE,cAAA,EAAe,GAAI,uBAAA,CAAwB,cAAc,KAAK,CAAA;AACtE,EAAA,MAAM,EAAE,cAAA,EAAe,GAAI,sBAAA,EAAuB;AAClD,EAAA,MAAM,UAAA,GAAa,OAAA;AAAA,IACf,MAAM,sBAAA,CAAuB,QAAA,EAAU,aAAA,EAAe,WAAW,CAAA;AAAA,IACjE,CAAC,QAAA,EAAU,aAAA,EAAe,WAAW;AAAA,GACzC;AAEA,EAAA,OAAO,YAAA;AAAA,wBACF,GAAA,EAAA,EAAK,GAAG,cAAA,EAAiB,GAAG,YACxB,QAAA,EACL,CAAA;AAAA,IACA;AAAA,GACJ;AACJ;;;;"}
1
+ {"version":3,"file":"MapAnchor.js","sources":["MapAnchor.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box, BoxProps } from \"@chakra-ui/react\";\nimport {\n CommonComponentProps,\n mergeChakraProps,\n useCommonComponentProps\n} from \"@open-pioneer/react-utils\";\nimport { ReactNode, useMemo } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { computeMapAnchorStyles } from \"./computeMapAnchorStyles\";\nimport { useMapContainerContext } from \"./MapContainerContext\";\n\n/**\n * The position of an anchor on the map.\n *\n * This is either a predefined position (like a corner) or a completely manual position.\n *\n * @group UI Components and Hooks\n */\nexport type MapAnchorPosition =\n | \"manual\"\n | \"top-left\"\n | \"top-right\"\n | \"top-center\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"bottom-center\"\n | \"left-center\"\n | \"right-center\"\n | \"center\";\n\nconst defaultPosition: MapAnchorPosition = \"top-right\";\n\n/**\n * @group UI Components and Hooks\n */\nexport interface MapAnchorProps extends CommonComponentProps {\n /**\n * The position of the anchor container above the map.\n *\n * Use `manual` if you wish to position the anchor manually using absolute positioning.\n * This can be achieved by configuring a css class on the map anchor and using css properties like `left`, `top`, etc.\n *\n * @default \"top-right\"\n */\n position?: MapAnchorPosition;\n\n /**\n * Horizontal gap in pixel applied to anchor container.\n * Only interpreted if a non-manual position is used.\n *\n * @default 0\n */\n horizontalGap?: number;\n\n /**\n * Vertical gap in pixel applied to anchor container.\n * Only interpreted if a non-manual position is used.\n *\n * @default 0 (If positioned at the bottom, default verticalGap == `30`)\n */\n verticalGap?: number;\n\n children?: ReactNode;\n}\n\n/**\n * A map anchor is a layout component that sits on top of the map.\n *\n * It can be used to position widgets (such as zoom buttons) at a specific location.\n *\n * Map anchors respect the map's current _view padding_.\n *\n * @group UI Components and Hooks\n */\nexport function MapAnchor(props: MapAnchorProps): ReactNode {\n const { position = defaultPosition, children, horizontalGap, verticalGap } = props;\n const { containerProps } = useCommonComponentProps(\"map-anchor\", props);\n const { mapAnchorsHost } = useMapContainerContext();\n const css = useMemo(\n () => computeMapAnchorStyles(position, horizontalGap, verticalGap),\n [position, horizontalGap, verticalGap]\n );\n\n const boxProps = mergeChakraProps<BoxProps>(\n {\n css\n },\n containerProps\n );\n return createPortal(<Box {...boxProps}>{children}</Box>, mapAnchorsHost);\n}\n"],"names":[],"mappings":";;;;;;;;AAgCA,MAAM,eAAA,GAAqC,WAAA;AA4CpC,SAAS,UAAU,KAAA,EAAkC;AACxD,EAAA,MAAM,EAAE,QAAA,GAAW,eAAA,EAAiB,QAAA,EAAU,aAAA,EAAe,aAAY,GAAI,KAAA;AAC7E,EAAA,MAAM,EAAE,cAAA,EAAe,GAAI,uBAAA,CAAwB,cAAc,KAAK,CAAA;AACtE,EAAA,MAAM,EAAE,cAAA,EAAe,GAAI,sBAAA,EAAuB;AAClD,EAAA,MAAM,GAAA,GAAM,OAAA;AAAA,IACR,MAAM,sBAAA,CAAuB,QAAA,EAAU,aAAA,EAAe,WAAW,CAAA;AAAA,IACjE,CAAC,QAAA,EAAU,aAAA,EAAe,WAAW;AAAA,GACzC;AAEA,EAAA,MAAM,QAAA,GAAW,gBAAA;AAAA,IACb;AAAA,MACI;AAAA,KACJ;AAAA,IACA;AAAA,GACJ;AACA,EAAA,OAAO,6BAAa,GAAA,CAAC,GAAA,EAAA,EAAK,GAAG,QAAA,EAAW,QAAA,EAAS,GAAQ,cAAc,CAAA;AAC3E;;;;"}
@@ -1,7 +1,8 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { chakra } from '@chakra-ui/react';
3
3
  import { createLogger } from '@open-pioneer/core';
4
- import { useCommonComponentProps } from '@open-pioneer/react-utils';
4
+ import { useCommonComponentProps, mergeChakraProps } from '@open-pioneer/react-utils';
5
+ import { useReactiveSnapshot } from '@open-pioneer/reactivity';
5
6
  import { sourceId$9 as sourceId } from '../_virtual/source-info.js';
6
7
  import { useRef, useState, useEffect, useMemo } from 'react';
7
8
  import { MapContainerContextProvider } from './MapContainerContext.js';
@@ -10,62 +11,56 @@ import { useMapModelValue } from './hooks/useMapModel.js';
10
11
  const LOG = createLogger(sourceId);
11
12
  function MapContainer(props) {
12
13
  const {
13
- viewPadding,
14
+ viewPadding: viewPaddingProp,
14
15
  viewPaddingChangeBehavior,
15
16
  children,
16
17
  role = "application",
17
18
  "aria-label": ariaLabel,
18
19
  "aria-labelledby": ariaLabelledBy,
19
20
  rootProps,
20
- containerProps
21
+ containerProps,
22
+ ...restProps
21
23
  } = props;
22
24
  const { containerProps: rootContainerProps } = useCommonComponentProps(
23
25
  "map-container-root",
24
- props
26
+ restProps
27
+ // hide role, aria label etc from helper
25
28
  );
26
29
  const mapContainer = useRef(null);
27
30
  const mapAnchorsHost = useRef(null);
28
31
  const map = useMapModelValue(props);
32
+ const viewPadding = useViewPadding(viewPaddingProp);
29
33
  const [ready, setReady] = useState(false);
30
- useEffect(() => {
31
- if (mapContainer.current) {
32
- const resource = registerMapTarget(map, mapContainer.current);
33
- return () => resource?.destroy();
34
- }
35
- }, [map]);
34
+ useMapContainerRegistration(mapContainer, map);
36
35
  useEffect(() => {
37
36
  setReady(true);
38
37
  }, []);
39
- const styleProps = useMemo(() => {
40
- return {
41
- height: "100%",
42
- position: "relative",
43
- // set css variables according to view padding
44
- "--map-padding-top": `${viewPadding?.top ?? 0}px`,
45
- "--map-padding-bottom": `${viewPadding?.bottom ?? 0}px`,
46
- "--map-padding-left": `${viewPadding?.left ?? 0}px`,
47
- "--map-padding-right": `${viewPadding?.right ?? 0}px`
48
- };
49
- }, [viewPadding]);
50
- return /* @__PURE__ */ jsxs(chakra.div, { ...rootProps, ...rootContainerProps, css: styleProps, children: [
51
- /* @__PURE__ */ jsx(
52
- chakra.div,
38
+ const css = useRootCss(viewPadding);
39
+ const mergedRootProps = useMemo(
40
+ () => mergeChakraProps({ css }, rootContainerProps, rootProps ?? {}),
41
+ [css, rootProps, rootContainerProps]
42
+ );
43
+ const mergedContainerProps = useMemo(
44
+ () => mergeChakraProps(
53
45
  {
54
- ...containerProps,
55
46
  className: "map-container",
56
- ref: mapContainer,
57
47
  role,
58
48
  "aria-label": ariaLabel,
59
49
  "aria-labelledby": ariaLabelledBy,
60
50
  h: "100%",
61
51
  w: "100%",
62
52
  tabIndex: 0
63
- }
53
+ },
54
+ containerProps ?? {}
64
55
  ),
56
+ [role, ariaLabel, ariaLabelledBy, containerProps]
57
+ );
58
+ return /* @__PURE__ */ jsxs(chakra.div, { ...mergedRootProps, children: [
59
+ /* @__PURE__ */ jsx(chakra.div, { ref: mapContainer, ...mergedContainerProps }),
65
60
  /* @__PURE__ */ jsx(chakra.div, { ref: mapAnchorsHost, className: "map-anchors", children: ready && map && /* @__PURE__ */ jsx(
66
61
  MapContainerReady,
67
62
  {
68
- olMap: map.olMap,
63
+ map,
69
64
  mapAnchorsHost: mapAnchorsHost.current,
70
65
  viewPadding,
71
66
  viewPaddingChangeBehavior,
@@ -76,23 +71,61 @@ function MapContainer(props) {
76
71
  }
77
72
  function MapContainerReady(props) {
78
73
  const {
79
- olMap,
74
+ map,
80
75
  mapAnchorsHost,
81
- viewPadding: viewPaddingProp,
76
+ viewPadding,
82
77
  viewPaddingChangeBehavior = "preserve-center",
83
78
  children
84
79
  } = props;
85
- const viewPadding = useMemo(() => {
80
+ useSyncViewPadding(viewPadding, viewPaddingChangeBehavior, map);
81
+ const mapContext = useMemo(() => {
82
+ return {
83
+ mapAnchorsHost
84
+ };
85
+ }, [mapAnchorsHost]);
86
+ return /* @__PURE__ */ jsx(MapContainerContextProvider, { value: mapContext, children });
87
+ }
88
+ function useMapContainerRegistration(mapContainer, map) {
89
+ useEffect(() => {
90
+ if (mapContainer.current) {
91
+ const resource = registerMapTarget(map, mapContainer.current);
92
+ return () => resource?.destroy();
93
+ }
94
+ }, [mapContainer, map]);
95
+ }
96
+ function useRootCss(viewPadding) {
97
+ return useMemo(() => {
98
+ return {
99
+ height: "100%",
100
+ position: "relative",
101
+ // set css variables according to view padding
102
+ "--map-padding-top": `${viewPadding.top}px`,
103
+ "--map-padding-bottom": `${viewPadding.bottom}px`,
104
+ "--map-padding-left": `${viewPadding.left}px`,
105
+ "--map-padding-right": `${viewPadding.right}px`
106
+ };
107
+ }, [viewPadding]);
108
+ }
109
+ function useViewPadding(viewPaddingProp) {
110
+ return useMemo(() => {
86
111
  return {
87
112
  left: viewPaddingProp?.left ?? 0,
88
113
  right: viewPaddingProp?.right ?? 0,
89
114
  top: viewPaddingProp?.top ?? 0,
90
115
  bottom: viewPaddingProp?.bottom ?? 0
91
116
  };
92
- }, [viewPaddingProp]);
117
+ }, [
118
+ viewPaddingProp?.left,
119
+ viewPaddingProp?.right,
120
+ viewPaddingProp?.top,
121
+ viewPaddingProp?.bottom
122
+ ]);
123
+ }
124
+ function useSyncViewPadding(viewPadding, viewPaddingChangeBehavior, map) {
125
+ const mapView = useReactiveSnapshot(() => map.olView, [map]);
93
126
  useEffect(() => {
94
- const mapView = olMap?.getView();
95
- if (!olMap || !mapView) {
127
+ const olMap = map.olMap;
128
+ if (!mapView) {
96
129
  return;
97
130
  }
98
131
  const oldPadding = fromOlPadding(mapView.padding);
@@ -118,13 +151,7 @@ function MapContainerReady(props) {
118
151
  break;
119
152
  }
120
153
  }
121
- }, [viewPadding, olMap, viewPaddingChangeBehavior]);
122
- const mapContext = useMemo(() => {
123
- return {
124
- mapAnchorsHost
125
- };
126
- }, [mapAnchorsHost]);
127
- return /* @__PURE__ */ jsx(MapContainerContextProvider, { value: mapContext, children });
154
+ }, [viewPadding, viewPaddingChangeBehavior, map, mapView]);
128
155
  }
129
156
  function registerMapTarget(mapModel, target) {
130
157
  const mapId = mapModel.id;
@@ -1 +1 @@
1
- {"version":3,"file":"MapContainer.js","sources":["MapContainer.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { BoxProps, chakra } from \"@chakra-ui/react\";\nimport { createLogger, Resource } from \"@open-pioneer/core\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport type OlMap from \"ol/Map\";\nimport { Extent } from \"ol/extent\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { ReactNode, useEffect, useMemo, useRef, useState } from \"react\";\nimport { MapModel, MapPadding } from \"../model/MapModel\";\nimport { MapContainerContextProvider, MapContainerContextType } from \"./MapContainerContext\";\nimport { MapModelProps, useMapModelValue } from \"./hooks/useMapModel\";\n\nconst LOG = createLogger(sourceId);\n\n/**\n * @group UI Components and Hooks\n */\nexport interface MapContainerProps extends CommonComponentProps, MapModelProps {\n /**\n * Sets the map's padding directly.\n * Do not use the view's padding property directly on the OL map.\n *\n * See: https://openlayers.org/en/latest/apidoc/module-ol_View-View.html#padding)\n */\n viewPadding?: MapPadding | undefined;\n\n /**\n * Behavior performed by the map when the view padding changes.\n *\n * - `none`: Do nothing.\n * - `preserve-center`: Ensures that the center point remains the same by animating the view.\n * - `preserve-extent`: Ensures that the extent remains the same by zooming.\n *\n * @default \"preserve-center\"\n */\n viewPaddingChangeBehavior?: \"none\" | \"preserve-center\" | \"preserve-extent\";\n\n children?: ReactNode;\n\n /**\n * Optional role property.\n *\n * This property is directly applied to the map's container div element.\n *\n * @default \"application\"\n */\n role?: string;\n\n /**\n * Optional aria-labelledby property.\n * Do not use together with aria-label.\n *\n * This property is directly applied to the map's container div element.\n */\n \"aria-labelledby\"?: string;\n\n /**\n * Optional aria-label property.\n * Do not use together with aria-label.\n *\n * This property is directly applied to the map's container div element.\n */\n \"aria-label\"?: string;\n\n /**\n * Arbitrary html properties that will be applied to the map container's _root_ element.\n * This is the element that contains the map container and any UI elements (like map anchors, for example).\n *\n * Use these at your own risk since they may be overwritten by the map container root itself.\n *\n * Use cases: setting custom data attributes, registering custom event handlers, ...\n */\n rootProps?: BoxProps;\n\n /**\n * Arbitrary html properties that will be applied to the map container's element.\n * This is the element that _renders_ the OpenLayers map.\n *\n * Use these at your own risk since they may be overwritten by the map container itself.\n *\n * Use cases: setting custom data attributes, registering custom event handlers, ...\n */\n containerProps?: BoxProps;\n}\n\n/**\n * Displays the map with the given id.\n *\n * There can only be at most one MapContainer for every map.\n *\n * @group UI Components and Hooks\n */\nexport function MapContainer(props: MapContainerProps) {\n const {\n viewPadding,\n viewPaddingChangeBehavior,\n children,\n role = \"application\",\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n rootProps,\n containerProps\n } = props;\n const { containerProps: rootContainerProps } = useCommonComponentProps(\n \"map-container-root\",\n props\n );\n const mapContainer = useRef<HTMLDivElement>(null);\n const mapAnchorsHost = useRef<HTMLDivElement>(null);\n const map = useMapModelValue(props);\n\n const [ready, setReady] = useState(false);\n\n useEffect(() => {\n // Mount the map into the DOM\n if (mapContainer.current) {\n const resource = registerMapTarget(map, mapContainer.current);\n return () => resource?.destroy();\n }\n }, [map]);\n\n // Wait for mount to make sure that the map anchors host is available\n useEffect(() => {\n setReady(true);\n }, []);\n\n const styleProps = useMemo(() => {\n return {\n height: \"100%\",\n position: \"relative\",\n\n // set css variables according to view padding\n \"--map-padding-top\": `${viewPadding?.top ?? 0}px`,\n \"--map-padding-bottom\": `${viewPadding?.bottom ?? 0}px`,\n \"--map-padding-left\": `${viewPadding?.left ?? 0}px`,\n \"--map-padding-right\": `${viewPadding?.right ?? 0}px`\n };\n }, [viewPadding]);\n\n return (\n <chakra.div {...rootProps} {...rootContainerProps} css={styleProps}>\n {/* Used by open layers to mount the map. This node receives the keyboard focus when interacting with the map. */}\n <chakra.div\n {...containerProps}\n className=\"map-container\"\n ref={mapContainer}\n role={role}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n h=\"100%\"\n w=\"100%\"\n tabIndex={0}\n />\n\n {/* Contains user widgets (map anchors and raw children). These are separate from the map so they don't interfere with mouse/keyboard events. */}\n <chakra.div ref={mapAnchorsHost} className=\"map-anchors\">\n {ready && map && (\n <MapContainerReady\n olMap={map.olMap}\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n mapAnchorsHost={mapAnchorsHost.current!}\n viewPadding={viewPadding}\n viewPaddingChangeBehavior={viewPaddingChangeBehavior}\n >\n {children}\n </MapContainerReady>\n )}\n </chakra.div>\n </chakra.div>\n );\n}\n\n/**\n * This inner component is rendered when the map has been loaded.\n *\n * It provides the map instance and additional properties down the component tree.\n */\nfunction MapContainerReady(\n props: { olMap: OlMap; mapAnchorsHost: HTMLElement } & Omit<\n MapContainerProps,\n \"mapId\" | \"map\" | \"className\"\n >\n): ReactNode {\n const {\n olMap,\n mapAnchorsHost,\n viewPadding: viewPaddingProp,\n viewPaddingChangeBehavior = \"preserve-center\",\n children\n } = props;\n\n const viewPadding = useMemo<Required<MapPadding>>(() => {\n return {\n left: viewPaddingProp?.left ?? 0,\n right: viewPaddingProp?.right ?? 0,\n top: viewPaddingProp?.top ?? 0,\n bottom: viewPaddingProp?.bottom ?? 0\n };\n }, [viewPaddingProp]);\n\n // Apply view padding\n useEffect(() => {\n const mapView = olMap?.getView();\n if (!olMap || !mapView) {\n return;\n }\n const oldPadding = fromOlPadding(mapView.padding);\n const paddingNotChanged = isPaddingEqual(viewPadding, oldPadding);\n if (paddingNotChanged) {\n return;\n }\n const oldCenter = mapView.getCenter();\n const oldExtent = extentIncludingPadding(olMap, oldPadding);\n\n mapView.padding = toOlPadding(viewPadding);\n switch (viewPaddingChangeBehavior) {\n case \"preserve-center\":\n mapView.animate({ center: oldCenter, duration: 300 });\n break;\n case \"preserve-extent\": {\n if (oldExtent) {\n mapView.animate({\n center: oldCenter,\n resolution: mapView.getResolutionForExtent(oldExtent),\n duration: 300\n });\n }\n break;\n }\n case \"none\":\n }\n }, [viewPadding, olMap, viewPaddingChangeBehavior]);\n\n const mapContext = useMemo((): MapContainerContextType => {\n return {\n mapAnchorsHost\n };\n }, [mapAnchorsHost]);\n return <MapContainerContextProvider value={mapContext}>{children}</MapContainerContextProvider>;\n}\n\nfunction registerMapTarget(mapModel: MapModel, target: HTMLDivElement): Resource | undefined {\n const mapId = mapModel.id;\n const olMap = mapModel.olMap;\n if (olMap.getTarget()) {\n LOG.error(\n `Failed to display the map: the map already has a target. There may be more than one <MapContainer />.`\n );\n return undefined;\n }\n\n LOG.isDebug() && LOG.debug(`Setting target of map '${mapId}':`, target);\n if (!(\"keyboardEventTarget_\" in olMap)) {\n throw new Error(\n \"Internal error: failed to override keyboard event target. The property is no longer present.\"\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (olMap as any).keyboardEventTarget_ = target;\n olMap.setTarget(target);\n\n let unregistered = false;\n return {\n destroy() {\n if (!unregistered) {\n LOG.isDebug() && LOG.debug(`Removing target of map '${mapId}':`, target);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (olMap as any).keyboardEventTarget_ = undefined;\n olMap.setTarget(undefined);\n unregistered = true;\n }\n }\n };\n}\n\n/**\n * Returns the extent visible in the non-padded region of the map.\n */\nfunction extentIncludingPadding(map: OlMap, padding: Required<MapPadding>): Extent | undefined {\n const size = map.getSize();\n if (!size || size.length < 2) {\n return undefined;\n }\n\n const [width, height] = size as [number, number];\n const bottomLeft = map.getCoordinateFromPixel([padding.left, padding.bottom]);\n const topRight = map.getCoordinateFromPixel([\n Math.max(0, width - padding.right),\n Math.max(0, height - padding.top)\n ]);\n if (!bottomLeft || !topRight) {\n return undefined;\n }\n\n const [xmin, ymin] = bottomLeft;\n const [xmax, ymax] = topRight;\n return [xmin, ymin, xmax, ymax] as Extent;\n}\n\nfunction fromOlPadding(padding: number[] | undefined): Required<MapPadding> {\n // top, right, bottom, left\n return {\n top: padding?.[0] ?? 0,\n right: padding?.[1] ?? 0,\n bottom: padding?.[2] ?? 0,\n left: padding?.[3] ?? 0\n };\n}\n\nfunction toOlPadding(padding: Required<MapPadding>): number[] {\n // top, right, bottom, left\n const { top, right, bottom, left } = padding;\n return [top, right, bottom, left];\n}\n\nfunction isPaddingEqual(a: Required<MapPadding>, b: Required<MapPadding>): boolean {\n return a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MapContainer.js","sources":["MapContainer.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { BoxProps, chakra, SystemStyleObject } from \"@chakra-ui/react\";\nimport { createLogger, Resource } from \"@open-pioneer/core\";\nimport {\n CommonComponentProps,\n mergeChakraProps,\n useCommonComponentProps\n} from \"@open-pioneer/react-utils\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport type OlMap from \"ol/Map\";\nimport { Extent } from \"ol/extent\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { ReactNode, RefObject, useEffect, useMemo, useRef, useState } from \"react\";\nimport { MapModel, MapPadding } from \"../model/MapModel\";\nimport { MapContainerContextProvider, MapContainerContextType } from \"./MapContainerContext\";\nimport { MapModelProps, useMapModelValue } from \"./hooks/useMapModel\";\n\nconst LOG = createLogger(sourceId);\n\n/**\n * @group UI Components and Hooks\n */\nexport interface MapContainerProps extends CommonComponentProps, MapModelProps {\n /**\n * Sets the map's padding directly.\n * Do not use the view's padding property directly on the OL map.\n *\n * See: https://openlayers.org/en/latest/apidoc/module-ol_View-View.html#padding)\n */\n viewPadding?: MapPadding | undefined;\n\n /**\n * Behavior performed by the map when the view padding changes.\n *\n * - `none`: Do nothing.\n * - `preserve-center`: Ensures that the center point remains the same by animating the view.\n * - `preserve-extent`: Ensures that the extent remains the same by zooming.\n *\n * @default \"preserve-center\"\n */\n viewPaddingChangeBehavior?: \"none\" | \"preserve-center\" | \"preserve-extent\";\n\n children?: ReactNode;\n\n /**\n * Optional role property.\n *\n * This property is directly applied to the map's container div element.\n *\n * @default \"application\"\n */\n role?: string;\n\n /**\n * Optional aria-labelledby property.\n * Do not use together with aria-label.\n *\n * This property is directly applied to the map's container div element.\n */\n \"aria-labelledby\"?: string;\n\n /**\n * Optional aria-label property.\n * Do not use together with aria-label.\n *\n * This property is directly applied to the map's container div element.\n */\n \"aria-label\"?: string;\n\n /**\n * Arbitrary html properties that will be applied to the map container's _root_ element.\n * This is the element that contains the map container and any UI elements (like map anchors, for example).\n *\n * Use these at your own risk since they may be overwritten by the map container root itself.\n *\n * Use cases: setting custom data attributes, registering custom event handlers, ...\n */\n rootProps?: BoxProps;\n\n /**\n * Arbitrary html properties that will be applied to the map container's element.\n * This is the element that _renders_ the OpenLayers map.\n *\n * Use these at your own risk since they may be overwritten by the map container itself.\n *\n * Use cases: setting custom data attributes, registering custom event handlers, ...\n */\n containerProps?: BoxProps;\n}\n\n/**\n * Displays the map with the given id.\n *\n * There can only be at most one MapContainer for every map.\n *\n * @group UI Components and Hooks\n */\nexport function MapContainer(props: MapContainerProps) {\n const {\n viewPadding: viewPaddingProp,\n viewPaddingChangeBehavior,\n children,\n role = \"application\",\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n rootProps,\n containerProps,\n ...restProps\n } = props;\n const { containerProps: rootContainerProps } = useCommonComponentProps(\n \"map-container-root\",\n restProps // hide role, aria label etc from helper\n );\n const mapContainer = useRef<HTMLDivElement>(null);\n const mapAnchorsHost = useRef<HTMLDivElement>(null);\n const map = useMapModelValue(props);\n const viewPadding = useViewPadding(viewPaddingProp);\n const [ready, setReady] = useState(false);\n\n // Register as renderer for map model\n useMapContainerRegistration(mapContainer, map);\n\n // Wait for mount to make sure that the map anchors host is available\n useEffect(() => {\n setReady(true);\n }, []);\n\n const css = useRootCss(viewPadding);\n const mergedRootProps = useMemo(\n () => mergeChakraProps<BoxProps>({ css }, rootContainerProps, rootProps ?? {}),\n [css, rootProps, rootContainerProps]\n );\n const mergedContainerProps = useMemo(\n () =>\n mergeChakraProps<BoxProps>(\n {\n className: \"map-container\",\n role,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n h: \"100%\",\n w: \"100%\",\n tabIndex: 0\n },\n containerProps ?? {}\n ),\n [role, ariaLabel, ariaLabelledBy, containerProps]\n );\n return (\n <chakra.div {...mergedRootProps}>\n {/* Used by open layers to mount the map. This node receives the keyboard focus when interacting with the map. */}\n <chakra.div ref={mapContainer} {...mergedContainerProps} />\n\n {/* Contains user widgets (map anchors and raw children). These are separate from the map so they don't interfere with mouse/keyboard events. */}\n <chakra.div ref={mapAnchorsHost} className=\"map-anchors\">\n {ready && map && (\n <MapContainerReady\n map={map}\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n mapAnchorsHost={mapAnchorsHost.current!}\n viewPadding={viewPadding}\n viewPaddingChangeBehavior={viewPaddingChangeBehavior}\n >\n {children}\n </MapContainerReady>\n )}\n </chakra.div>\n </chakra.div>\n );\n}\n\n/**\n * This inner component is rendered when the map has been loaded.\n *\n * It provides the map instance and additional properties down the component tree.\n */\nfunction MapContainerReady(\n props: {\n map: MapModel;\n mapAnchorsHost: HTMLElement;\n viewPadding: Required<MapPadding>;\n } & Omit<MapContainerProps, \"mapId\" | \"map\" | \"className\">\n): ReactNode {\n const {\n map,\n mapAnchorsHost,\n viewPadding,\n viewPaddingChangeBehavior = \"preserve-center\",\n children\n } = props;\n\n // Apply view padding\n useSyncViewPadding(viewPadding, viewPaddingChangeBehavior, map);\n\n const mapContext = useMemo((): MapContainerContextType => {\n return {\n mapAnchorsHost\n };\n }, [mapAnchorsHost]);\n return <MapContainerContextProvider value={mapContext}>{children}</MapContainerContextProvider>;\n}\n\n/**\n * Registers the map container as the map's renderer.\n * This can only be done once at a time: there cannot be two renderers for the same map model.\n */\nfunction useMapContainerRegistration(\n mapContainer: RefObject<HTMLDivElement | null>,\n map: MapModel\n) {\n useEffect(() => {\n // Mount the map into the DOM\n if (mapContainer.current) {\n const resource = registerMapTarget(map, mapContainer.current);\n return () => resource?.destroy();\n }\n }, [mapContainer, map]);\n}\n\n/**\n * Custom CSS rules for the root element.\n */\nfunction useRootCss(viewPadding: Required<MapPadding>) {\n return useMemo((): SystemStyleObject => {\n return {\n height: \"100%\",\n position: \"relative\",\n\n // set css variables according to view padding\n \"--map-padding-top\": `${viewPadding.top}px`,\n \"--map-padding-bottom\": `${viewPadding.bottom}px`,\n \"--map-padding-left\": `${viewPadding.left}px`,\n \"--map-padding-right\": `${viewPadding.right}px`\n };\n }, [viewPadding]);\n}\n\n/**\n * Normalizes the view padding property.\n */\nfunction useViewPadding(viewPaddingProp: MapPadding | undefined): Required<MapPadding> {\n return useMemo<Required<MapPadding>>(() => {\n return {\n left: viewPaddingProp?.left ?? 0,\n right: viewPaddingProp?.right ?? 0,\n top: viewPaddingProp?.top ?? 0,\n bottom: viewPaddingProp?.bottom ?? 0\n };\n }, [\n viewPaddingProp?.left,\n viewPaddingProp?.right,\n viewPaddingProp?.top,\n viewPaddingProp?.bottom\n ]);\n}\n\n/**\n * Applies the current view padding to the view.\n */\nfunction useSyncViewPadding(\n viewPadding: Required<MapPadding>,\n viewPaddingChangeBehavior: MapContainerProps[\"viewPaddingChangeBehavior\"],\n map: MapModel\n) {\n const mapView = useReactiveSnapshot(() => map.olView, [map]);\n useEffect(() => {\n const olMap = map.olMap;\n if (!mapView) {\n return;\n }\n\n const oldPadding = fromOlPadding(mapView.padding);\n const paddingNotChanged = isPaddingEqual(viewPadding, oldPadding);\n if (paddingNotChanged) {\n return;\n }\n\n const oldCenter = mapView.getCenter();\n const oldExtent = extentIncludingPadding(olMap, oldPadding);\n mapView.padding = toOlPadding(viewPadding);\n switch (viewPaddingChangeBehavior) {\n case \"preserve-center\":\n mapView.animate({ center: oldCenter, duration: 300 });\n break;\n case \"preserve-extent\": {\n if (oldExtent) {\n mapView.animate({\n center: oldCenter,\n resolution: mapView.getResolutionForExtent(oldExtent),\n duration: 300\n });\n }\n break;\n }\n case \"none\":\n }\n }, [viewPadding, viewPaddingChangeBehavior, map, mapView]);\n}\n\nfunction registerMapTarget(mapModel: MapModel, target: HTMLDivElement): Resource | undefined {\n const mapId = mapModel.id;\n const olMap = mapModel.olMap;\n if (olMap.getTarget()) {\n LOG.error(\n `Failed to display the map: the map already has a target. There may be more than one <MapContainer />.`\n );\n return undefined;\n }\n\n LOG.isDebug() && LOG.debug(`Setting target of map '${mapId}':`, target);\n if (!(\"keyboardEventTarget_\" in olMap)) {\n throw new Error(\n \"Internal error: failed to override keyboard event target. The property is no longer present.\"\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (olMap as any).keyboardEventTarget_ = target;\n olMap.setTarget(target);\n\n let unregistered = false;\n return {\n destroy() {\n if (!unregistered) {\n LOG.isDebug() && LOG.debug(`Removing target of map '${mapId}':`, target);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (olMap as any).keyboardEventTarget_ = undefined;\n olMap.setTarget(undefined);\n unregistered = true;\n }\n }\n };\n}\n\n/**\n * Returns the extent visible in the non-padded region of the map.\n */\nfunction extentIncludingPadding(map: OlMap, padding: Required<MapPadding>): Extent | undefined {\n const size = map.getSize();\n if (!size || size.length < 2) {\n return undefined;\n }\n\n const [width, height] = size as [number, number];\n const bottomLeft = map.getCoordinateFromPixel([padding.left, padding.bottom]);\n const topRight = map.getCoordinateFromPixel([\n Math.max(0, width - padding.right),\n Math.max(0, height - padding.top)\n ]);\n if (!bottomLeft || !topRight) {\n return undefined;\n }\n\n const [xmin, ymin] = bottomLeft;\n const [xmax, ymax] = topRight;\n return [xmin, ymin, xmax, ymax] as Extent;\n}\n\nfunction fromOlPadding(padding: number[] | undefined): Required<MapPadding> {\n // top, right, bottom, left\n return {\n top: padding?.[0] ?? 0,\n right: padding?.[1] ?? 0,\n bottom: padding?.[2] ?? 0,\n left: padding?.[3] ?? 0\n };\n}\n\nfunction toOlPadding(padding: Required<MapPadding>): number[] {\n // top, right, bottom, left\n const { top, right, bottom, left } = padding;\n return [top, right, bottom, left];\n}\n\nfunction isPaddingEqual(a: Required<MapPadding>, b: Required<MapPadding>): boolean {\n return a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left;\n}\n"],"names":[],"mappings":"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"}