@open-pioneer/legend 0.10.0 → 0.11.0-dev.20250515143825

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,5 +1,17 @@
1
1
  # @open-pioneer/legend
2
2
 
3
+ ## 0.11.0-dev.20250515143825
4
+
5
+ ### Minor Changes
6
+
7
+ - 738390e: Update to Chakra v3
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [738390e]
12
+ - Updated dependencies [738390e]
13
+ - @open-pioneer/map@0.11.0-dev.20250515143825
14
+
3
15
  ## 0.10.0
4
16
 
5
17
  ### Minor Changes
package/Legend.d.ts CHANGED
@@ -15,6 +15,8 @@ export interface LegendItemComponentProps {
15
15
  *
16
16
  * To show a legend for the layer, provide an imageUrl to an image to show
17
17
  * or provide a React component that will be rendered as a legend.
18
+ *
19
+ * LegendItemAttributes should be registered with a layer as the `"legend"` attribute.
18
20
  */
19
21
  export interface LegendItemAttributes {
20
22
  /**
package/Legend.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { WarningTwoIcon } from '@chakra-ui/icons';
3
- import { Box, List, Text, Image } from '@open-pioneer/chakra-integration';
2
+ import { IoIosWarning } from 'react-icons/io';
3
+ import { Box, List, Text, Icon, Image } from '@chakra-ui/react';
4
4
  import { useMapModel, isLayer } from '@open-pioneer/map';
5
5
  import { useCommonComponentProps } from '@open-pioneer/react-utils';
6
6
  import { useReactiveSnapshot } from '@open-pioneer/reactivity';
7
7
  import classNames from 'classnames';
8
8
  import { useIntl } from './_virtual/_virtual-pioneer-module_react-hooks.js';
9
+ import { useState, useEffect, useMemo } from 'react';
9
10
 
10
11
  const Legend = (props) => {
11
12
  const { showBaseLayers = false } = props;
@@ -20,12 +21,12 @@ function LegendList(props) {
20
21
  return /* @__PURE__ */ jsx(LegendItem, { layer, showBaseLayers }, layer.id);
21
22
  });
22
23
  return /* @__PURE__ */ jsx(
23
- List,
24
+ List.Root,
24
25
  {
25
26
  as: "ul",
26
27
  className: "legend-layer-list",
27
28
  listStyleType: "none",
28
- spacing: 2,
29
+ gap: 2,
29
30
  children: legendListItems
30
31
  }
31
32
  );
@@ -87,9 +88,18 @@ function LegendContent(props) {
87
88
  function LegendImage(props) {
88
89
  const intl = useIntl();
89
90
  const { layer, imageUrl } = props;
90
- return /* @__PURE__ */ jsxs(Box, { children: [
91
- /* @__PURE__ */ jsx(Text, { children: layer.title }),
92
- /* @__PURE__ */ jsx(
91
+ const [isError, setIsError] = useState(false);
92
+ useEffect(() => {
93
+ setIsError(false);
94
+ }, [imageUrl]);
95
+ const content = useMemo(() => {
96
+ if (isError) {
97
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
98
+ /* @__PURE__ */ jsx(Icon, { me: 2, children: /* @__PURE__ */ jsx(IoIosWarning, {}) }),
99
+ intl.formatMessage({ id: "fallbackLabel" })
100
+ ] }) });
101
+ }
102
+ return /* @__PURE__ */ jsx(
93
103
  Image,
94
104
  {
95
105
  maxW: "none",
@@ -97,13 +107,13 @@ function LegendImage(props) {
97
107
  src: imageUrl,
98
108
  alt: intl.formatMessage({ id: "altLabel" }, { layerName: layer.title }),
99
109
  className: "legend-item__image",
100
- fallbackStrategy: "onError",
101
- fallback: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
102
- /* @__PURE__ */ jsx(WarningTwoIcon, { me: 2 }),
103
- intl.formatMessage({ id: "fallbackLabel" })
104
- ] }) })
110
+ onError: () => setIsError(true)
105
111
  }
106
- )
112
+ );
113
+ }, [intl, layer.title, imageUrl, isError]);
114
+ return /* @__PURE__ */ jsxs(Box, { children: [
115
+ /* @__PURE__ */ jsx(Text, { children: layer.title }),
116
+ content
107
117
  ] });
108
118
  }
109
119
  function useLayers(map) {
package/Legend.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Legend.js","sources":["Legend.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { WarningTwoIcon } from \"@chakra-ui/icons\";\nimport { Box, Image, List, Text } from \"@open-pioneer/chakra-integration\";\nimport { Layer, AnyLayer, MapModel, useMapModel, MapModelProps, isLayer } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport classNames from \"classnames\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { ComponentType, FC, ReactNode } from \"react\";\n\n/**\n * Properties of a legend item React component.\n */\nexport interface LegendItemComponentProps {\n /**\n * Related layer of the legend.\n */\n layer: AnyLayer;\n}\n\n/**\n * Attributes of the legend attribute that can be specified on a layer.\n *\n * To show a legend for the layer, provide an imageUrl to an image to show\n * or provide a React component that will be rendered as a legend.\n */\nexport interface LegendItemAttributes {\n /**\n * (Optional) URL to an image that will be shown as a legend for the layer.\n */\n imageUrl?: string;\n\n /**\n * (Optional) React component that will be shown as customized legend for the layer.\n */\n Component?: ComponentType<LegendItemComponentProps>;\n}\n\n/**\n * These are special properties for the Legend.\n */\nexport interface LegendProps extends CommonComponentProps, MapModelProps {\n /**\n * Specifies whether legend for active base layer is shown in the legend UI.\n * Defaults to `false`.\n */\n showBaseLayers?: boolean;\n}\n\n/**\n * The `Legend` component can be used to display the legend of layers that are visible in the map.\n */\nexport const Legend: FC<LegendProps> = (props) => {\n const { showBaseLayers = false } = props;\n const { containerProps } = useCommonComponentProps(\"legend\", props);\n const { map } = useMapModel(props);\n\n return (\n <Box {...containerProps}>\n {map ? <LegendList map={map} showBaseLayers={showBaseLayers} /> : null}\n </Box>\n );\n};\n\nfunction LegendList(props: { map: MapModel; showBaseLayers: boolean }): ReactNode {\n const { map, showBaseLayers } = props;\n\n const layers = useLayers(map);\n const legendListItems: ReactNode[] = layers.map((layer) => {\n return (\n <LegendItem key={layer.id} layer={layer} showBaseLayers={showBaseLayers}></LegendItem>\n );\n });\n\n return (\n <List\n // Note: not using UnorderedList because it adds default margins\n as=\"ul\"\n className=\"legend-layer-list\"\n listStyleType=\"none\"\n spacing={2}\n >\n {legendListItems}\n </List>\n );\n}\n\nfunction LegendItem(props: { layer: AnyLayer; showBaseLayers: boolean }): ReactNode {\n const { layer, showBaseLayers } = props;\n const isVisible = useReactiveSnapshot(() => layer.visible, [layer]);\n const childLayers = useChildLayers(layer);\n\n if (!isVisible) {\n return undefined;\n }\n\n if (!showBaseLayers && isLayer(layer) && isBaseLayer(layer)) {\n return undefined;\n }\n\n // legend items for all child layers (sublayers or layers in a group)\n const childItems: ReactNode[] = [];\n if (childLayers?.length) {\n childLayers.forEach((childLayer) => {\n childItems.push(\n <LegendItem\n key={childLayer.id}\n layer={childLayer}\n showBaseLayers={showBaseLayers}\n />\n );\n });\n }\n\n return (\n <>\n <LegendContent layer={layer} showBaseLayers={showBaseLayers} />\n {childItems}\n </>\n );\n}\n\nfunction LegendContent(props: { layer: AnyLayer; showBaseLayers: boolean }) {\n const intl = useIntl();\n\n const { layer, showBaseLayers } = props;\n const baseLayer = isBaseLayer(layer);\n const legendAttributes = useLegendAttributes(layer);\n const legendUrl = useReactiveSnapshot(() => layer.legend, [layer]);\n\n let renderedComponent: ReactNode | undefined;\n if (legendAttributes?.Component) {\n renderedComponent = <legendAttributes.Component layer={layer} />;\n } else if (legendAttributes?.imageUrl) {\n renderedComponent = <LegendImage layer={layer} imageUrl={legendAttributes.imageUrl} />;\n } else {\n if (legendUrl) {\n renderedComponent = <LegendImage layer={layer} imageUrl={legendUrl} />;\n }\n }\n\n return renderedComponent ? (\n <Box as=\"li\" className={classNames(\"legend-item\", `layer-${slug(layer.id)}`)}>\n {showBaseLayers && baseLayer ? (\n /* Render additional text, if layer is a configured basemap */\n <Text as=\"b\">{intl.formatMessage({ id: \"basemapLabel\" })}</Text>\n ) : null}\n {renderedComponent}\n </Box>\n ) : undefined;\n}\n\nfunction LegendImage(props: { imageUrl: string; layer: AnyLayer }) {\n const intl = useIntl();\n\n const { layer, imageUrl } = props;\n\n return (\n <Box>\n <Text>{layer.title}</Text>\n <Image\n maxW=\"none\"\n maxH=\"none\"\n src={imageUrl}\n alt={intl.formatMessage({ id: \"altLabel\" }, { layerName: layer.title })}\n className={\"legend-item__image\"}\n fallbackStrategy={\"onError\"}\n fallback={\n <Box>\n <Text>\n <WarningTwoIcon me={2} />\n {intl.formatMessage({ id: \"fallbackLabel\" })}\n </Text>\n </Box>\n }\n />\n </Box>\n );\n}\n\n/** Returns the top level operational layers in render order (topmost layer first). */\nfunction useLayers(map: MapModel): Layer[] {\n return useReactiveSnapshot(() => {\n const layers = map.layers.getLayers({ sortByDisplayOrder: true }) ?? [];\n layers.reverse(); // render topmost layer first\n return layers;\n }, [map]);\n}\n\n/**\n * Returns the child layers (sublayers or layers belonging to a GroupLayer) of the given layer\n * (or undefined, if the child layer cannot have any).\n * Layers are returned in render order (topmost layer first).\n */\nfunction useChildLayers(layer: AnyLayer): AnyLayer[] | undefined {\n return useReactiveSnapshot(() => {\n const childLayers = layer.children?.getItems();\n if (!childLayers) {\n return undefined;\n }\n\n childLayers.reverse(); // render topmost layer first\n return childLayers;\n }, [layer]);\n}\n\nfunction useLegendAttributes(layer: AnyLayer): LegendItemAttributes | undefined {\n return useReactiveSnapshot(\n () => layer.attributes.legend as LegendItemAttributes | undefined,\n [layer]\n );\n}\n\nfunction isBaseLayer(layer: AnyLayer) {\n return !(\"parentLayer\" in layer) && layer.isBaseLayer;\n}\n\nfunction slug(id: string) {\n return id\n .toLowerCase()\n .replace(/[^a-z0-9 -]/g, \"\")\n .replace(/\\s+/g, \"-\")\n .replace(/-+/g, \"-\");\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Legend.js","sources":["Legend.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { IoIosWarning } from \"react-icons/io\";\nimport { Box, Image, List, Text, Icon } from \"@chakra-ui/react\";\nimport { Layer, AnyLayer, MapModel, useMapModel, MapModelProps, isLayer } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport classNames from \"classnames\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { ComponentType, FC, ReactNode, useEffect, useMemo, useState } from \"react\";\n\n/**\n * Properties of a legend item React component.\n */\nexport interface LegendItemComponentProps {\n /**\n * Related layer of the legend.\n */\n layer: AnyLayer;\n}\n\n/**\n * Attributes of the legend attribute that can be specified on a layer.\n *\n * To show a legend for the layer, provide an imageUrl to an image to show\n * or provide a React component that will be rendered as a legend.\n *\n * LegendItemAttributes should be registered with a layer as the `\"legend\"` attribute.\n */\nexport interface LegendItemAttributes {\n /**\n * (Optional) URL to an image that will be shown as a legend for the layer.\n */\n imageUrl?: string;\n\n /**\n * (Optional) React component that will be shown as customized legend for the layer.\n */\n Component?: ComponentType<LegendItemComponentProps>;\n}\n\n/**\n * These are special properties for the Legend.\n */\nexport interface LegendProps extends CommonComponentProps, MapModelProps {\n /**\n * Specifies whether legend for active base layer is shown in the legend UI.\n * Defaults to `false`.\n */\n showBaseLayers?: boolean;\n}\n\n/**\n * The `Legend` component can be used to display the legend of layers that are visible in the map.\n */\nexport const Legend: FC<LegendProps> = (props) => {\n const { showBaseLayers = false } = props;\n const { containerProps } = useCommonComponentProps(\"legend\", props);\n const { map } = useMapModel(props);\n\n return (\n <Box {...containerProps}>\n {map ? <LegendList map={map} showBaseLayers={showBaseLayers} /> : null}\n </Box>\n );\n};\n\nfunction LegendList(props: { map: MapModel; showBaseLayers: boolean }): ReactNode {\n const { map, showBaseLayers } = props;\n\n const layers = useLayers(map);\n const legendListItems: ReactNode[] = layers.map((layer) => {\n return (\n <LegendItem key={layer.id} layer={layer} showBaseLayers={showBaseLayers}></LegendItem>\n );\n });\n\n return (\n <List.Root\n // Note: not using UnorderedList because it adds default margins\n as=\"ul\"\n className=\"legend-layer-list\"\n listStyleType=\"none\"\n gap={2}\n >\n {legendListItems}\n </List.Root>\n );\n}\n\nfunction LegendItem(props: { layer: AnyLayer; showBaseLayers: boolean }): ReactNode {\n const { layer, showBaseLayers } = props;\n const isVisible = useReactiveSnapshot(() => layer.visible, [layer]);\n const childLayers = useChildLayers(layer);\n\n if (!isVisible) {\n return undefined;\n }\n\n if (!showBaseLayers && isLayer(layer) && isBaseLayer(layer)) {\n return undefined;\n }\n\n // legend items for all child layers (sublayers or layers in a group)\n const childItems: ReactNode[] = [];\n if (childLayers?.length) {\n childLayers.forEach((childLayer) => {\n childItems.push(\n <LegendItem\n key={childLayer.id}\n layer={childLayer}\n showBaseLayers={showBaseLayers}\n />\n );\n });\n }\n\n return (\n <>\n <LegendContent layer={layer} showBaseLayers={showBaseLayers} />\n {childItems}\n </>\n );\n}\n\nfunction LegendContent(props: { layer: AnyLayer; showBaseLayers: boolean }) {\n const intl = useIntl();\n\n const { layer, showBaseLayers } = props;\n const baseLayer = isBaseLayer(layer);\n const legendAttributes = useLegendAttributes(layer);\n const legendUrl = useReactiveSnapshot(() => layer.legend, [layer]);\n\n let renderedComponent: ReactNode | undefined;\n if (legendAttributes?.Component) {\n renderedComponent = <legendAttributes.Component layer={layer} />;\n } else if (legendAttributes?.imageUrl) {\n renderedComponent = <LegendImage layer={layer} imageUrl={legendAttributes.imageUrl} />;\n } else {\n if (legendUrl) {\n renderedComponent = <LegendImage layer={layer} imageUrl={legendUrl} />;\n }\n }\n\n return renderedComponent ? (\n <Box as=\"li\" className={classNames(\"legend-item\", `layer-${slug(layer.id)}`)}>\n {showBaseLayers && baseLayer ? (\n /* Render additional text, if layer is a configured basemap */\n <Text as=\"b\">{intl.formatMessage({ id: \"basemapLabel\" })}</Text>\n ) : null}\n {renderedComponent}\n </Box>\n ) : undefined;\n}\n\nfunction LegendImage(props: { imageUrl: string; layer: AnyLayer }) {\n const intl = useIntl();\n\n const { layer, imageUrl } = props;\n\n const [isError, setIsError] = useState(false);\n useEffect(() => {\n setIsError(false);\n }, [imageUrl]);\n\n const content = useMemo(() => {\n if (isError) {\n return (\n <Box>\n <Text>\n <Icon me={2}>\n <IoIosWarning />\n </Icon>\n {intl.formatMessage({ id: \"fallbackLabel\" })}\n </Text>\n </Box>\n );\n }\n\n return (\n <Image\n maxW=\"none\"\n maxH=\"none\"\n src={imageUrl}\n alt={intl.formatMessage({ id: \"altLabel\" }, { layerName: layer.title })}\n className={\"legend-item__image\"}\n onError={() => setIsError(true)}\n />\n );\n }, [intl, layer.title, imageUrl, isError]);\n\n return (\n <Box>\n <Text>{layer.title}</Text>\n {content}\n </Box>\n );\n}\n\n/** Returns the top level operational layers in render order (topmost layer first). */\nfunction useLayers(map: MapModel): Layer[] {\n return useReactiveSnapshot(() => {\n const layers = map.layers.getLayers({ sortByDisplayOrder: true }) ?? [];\n layers.reverse(); // render topmost layer first\n return layers;\n }, [map]);\n}\n\n/**\n * Returns the child layers (sublayers or layers belonging to a GroupLayer) of the given layer\n * (or undefined, if the child layer cannot have any).\n * Layers are returned in render order (topmost layer first).\n */\nfunction useChildLayers(layer: AnyLayer): AnyLayer[] | undefined {\n return useReactiveSnapshot(() => {\n const childLayers = layer.children?.getItems();\n if (!childLayers) {\n return undefined;\n }\n\n childLayers.reverse(); // render topmost layer first\n return childLayers;\n }, [layer]);\n}\n\nfunction useLegendAttributes(layer: AnyLayer): LegendItemAttributes | undefined {\n return useReactiveSnapshot(\n () => layer.attributes.legend as LegendItemAttributes | undefined,\n [layer]\n );\n}\n\nfunction isBaseLayer(layer: AnyLayer) {\n return !(\"parentLayer\" in layer) && layer.isBaseLayer;\n}\n\nfunction slug(id: string) {\n return id\n .toLowerCase()\n .replace(/[^a-z0-9 -]/g, \"\")\n .replace(/\\s+/g, \"-\")\n .replace(/-+/g, \"-\");\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@open-pioneer/legend",
4
- "version": "0.10.0",
4
+ "version": "0.11.0-dev.20250515143825",
5
5
  "description": "This package provides a legend UI component that allows a user to see legend information for layers in the map.",
6
6
  "keywords": [
7
7
  "open-pioneer-trails"
@@ -14,15 +14,15 @@
14
14
  "directory": "src/packages/legend"
15
15
  },
16
16
  "dependencies": {
17
- "@chakra-ui/icons": "^2.2.4",
18
- "@open-pioneer/chakra-integration": "^3.1.0",
19
- "@open-pioneer/react-utils": "^3.1.0",
20
- "@open-pioneer/runtime": "^3.1.0",
17
+ "@chakra-ui/react": "^3.17.0",
18
+ "@open-pioneer/react-utils": "4.0.0-dev.20250512105016",
19
+ "@open-pioneer/runtime": "4.0.0-dev.20250512105016",
21
20
  "classnames": "^2.3.2",
22
21
  "ol": "^10.5.0",
23
22
  "react": "^19.1.0",
24
- "@open-pioneer/reactivity": "^3.1.0",
25
- "@open-pioneer/map": "^0.10.0"
23
+ "@open-pioneer/reactivity": "4.0.0-dev.20250512105016",
24
+ "react-icons": "^5.3.0",
25
+ "@open-pioneer/map": "0.11.0-dev.20250515143825"
26
26
  },
27
27
  "exports": {
28
28
  "./package.json": "./package.json",