@open-pioneer/toc 0.11.0-dev.20250515143825 → 0.11.0

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,18 +1,36 @@
1
1
  # @open-pioneer/toc
2
2
 
3
- ## 0.11.0-dev.20250515143825
3
+ ## 0.11.0
4
4
 
5
5
  ### Minor Changes
6
6
 
7
+ - 66179bc: Update to core-packages v4.0.0
7
8
  - 738390e: Update to Chakra v3
8
9
 
9
10
  ### Patch Changes
10
11
 
12
+ - 9376a74: Ensure that icons and other decorative elements are hidden from the screen reader using the `aria-hidden="true"` attribute.
13
+
14
+ The easiest way to do that is to wrap icons into chakra's `<Icon />` component, for example:
15
+
16
+ ```tsx
17
+ import { Icon } from "@chakra-ui/react";
18
+ import { FiX } from "react-icons/fi";
19
+
20
+ <Icon>
21
+ <FiX />
22
+ </Icon>;
23
+ ```
24
+
25
+ - e00186b: Add a tooltip around the menu trigger buttons (map tools and layer tools).
11
26
  - Updated dependencies [738390e]
12
27
  - Updated dependencies [738390e]
28
+ - Updated dependencies [66179bc]
29
+ - Updated dependencies [0a8ff71]
30
+ - Updated dependencies [acd5115]
13
31
  - Updated dependencies [738390e]
14
- - @open-pioneer/map@0.11.0-dev.20250515143825
15
- - @open-pioneer/basemap-switcher@0.11.0-dev.20250515143825
32
+ - @open-pioneer/map@0.11.0
33
+ - @open-pioneer/basemap-switcher@0.11.0
16
34
 
17
35
  ## 0.10.0
18
36
 
package/i18n/de.yaml CHANGED
@@ -4,11 +4,14 @@ messages:
4
4
  operationalLayerLabel: "Layer"
5
5
  childgroupLabel: "Layergruppe {title}"
6
6
  missingLayers: "Es sind keine Layer vorhanden."
7
+
7
8
  group:
8
9
  expand: "Gruppe {title} ausklappen"
9
10
  collapse: "Gruppe {title} einklappen"
11
+
10
12
  error: "Beim Erstellen des Karteninhalts ist ein Fehler aufgetreten."
11
13
  layerNotAvailable: "Layer nicht verfügbar"
14
+
12
15
  toolsLabel: "Kartenwerkzeuge"
13
16
  tools:
14
17
  hideAllLayers: "Alle Karteninhalte ausblenden"
package/i18n/en.yaml CHANGED
@@ -4,11 +4,14 @@ messages:
4
4
  operationalLayerLabel: "Operational layers"
5
5
  childgroupLabel: "Layer group {title}"
6
6
  missingLayers: "There are no layers to display."
7
+
7
8
  group:
8
9
  expand: "Expand group {title}"
9
10
  collapse: "Collapse group {title}"
11
+
10
12
  error: "Error while creating map content."
11
13
  layerNotAvailable: "Layer not available"
14
+
12
15
  toolsLabel: "Map tools"
13
16
  tools:
14
17
  hideAllLayers: "Hide all layers"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@open-pioneer/toc",
4
- "version": "0.11.0-dev.20250515143825",
4
+ "version": "0.11.0",
5
5
  "description": "This package provides a UI component that displays the map content to the user and allows them to control it.",
6
6
  "keywords": [
7
7
  "open-pioneer-trails"
@@ -14,18 +14,18 @@
14
14
  "directory": "src/packages/toc"
15
15
  },
16
16
  "dependencies": {
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",
20
- "classnames": "^2.3.2",
17
+ "@chakra-ui/react": "^3.19.2",
18
+ "@open-pioneer/react-utils": "^4.0.0",
19
+ "@open-pioneer/runtime": "^4.0.0",
20
+ "classnames": "^2.5.1",
21
21
  "ol": "^10.5.0",
22
22
  "react": "^19.1.0",
23
- "react-icons": "^5.3.0",
24
- "@open-pioneer/reactivity": "4.0.0-dev.20250512105016",
25
- "@conterra/reactivity-core": "^0.6.0",
26
- "@open-pioneer/chakra-snippets": "4.0.0-dev.20250512105016",
27
- "@open-pioneer/basemap-switcher": "0.11.0-dev.20250515143825",
28
- "@open-pioneer/map": "0.11.0-dev.20250515143825"
23
+ "react-icons": "^5.5.0",
24
+ "@open-pioneer/reactivity": "^4.0.0",
25
+ "@conterra/reactivity-core": "^0.7.0",
26
+ "@open-pioneer/chakra-snippets": "^4.0.0",
27
+ "@open-pioneer/basemap-switcher": "^0.11.0",
28
+ "@open-pioneer/map": "^0.11.0"
29
29
  },
30
30
  "exports": {
31
31
  "./package.json": "./package.json",
@@ -1,8 +1,8 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { Box, Flex, Spacer, Collapsible, CollapsibleContent, IconButton, Icon } from '@chakra-ui/react';
2
3
  import { reactive } from '@conterra/reactivity-core';
3
- import { Box, Flex, Spacer, Collapsible, CollapsibleContent, IconButton } from '@chakra-ui/react';
4
- import { Tooltip } from '@open-pioneer/chakra-snippets/tooltip';
5
4
  import { Checkbox } from '@open-pioneer/chakra-snippets/checkbox';
5
+ import { Tooltip } from '@open-pioneer/chakra-snippets/tooltip';
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';
@@ -10,7 +10,7 @@ import { memo, useId, useMemo, useEffect } from 'react';
10
10
  import { FiAlertTriangle, FiChevronDown, FiChevronRight } from 'react-icons/fi';
11
11
  import { useTocModel } from '../../model/TocModel.js';
12
12
  import { slug } from '../../utils/slug.js';
13
- import { useChildLayers, useLoadState } from './hooks.js';
13
+ import { useLoadState, useChildLayers } from './hooks.js';
14
14
  import { LayerItemMenu } from './LayerItemMenu.js';
15
15
  import { LayerList } from './LayerList.js';
16
16
 
@@ -21,7 +21,6 @@ const LayerItem = memo(function LayerItem2(props) {
21
21
  const expanded = useReactiveSnapshot(() => tocItem.isExpanded, [tocItem]);
22
22
  const isCollapsible = tocOptions ? tocOptions.collapsibleGroups : false;
23
23
  const layerGroupId = useId();
24
- const childLayers = useChildLayers(layer);
25
24
  const isAvailable = useLoadState(layer) !== "error";
26
25
  const notAvailableLabel = intl.formatMessage({ id: "layerNotAvailable" });
27
26
  const { title, description, isVisible } = useReactiveSnapshot(() => {
@@ -31,17 +30,8 @@ const LayerItem = memo(function LayerItem2(props) {
31
30
  isVisible: layer.visible
32
31
  };
33
32
  }, [layer]);
34
- let nestedChildren;
35
- if (childLayers?.length) {
36
- nestedChildren = /* @__PURE__ */ jsx(
37
- LayerList,
38
- {
39
- layers: childLayers,
40
- ml: 4,
41
- "aria-label": intl.formatMessage({ id: "childgroupLabel" }, { title })
42
- }
43
- );
44
- }
33
+ const nestedChildren = useNestedChildren(layerGroupId, title, layer, intl);
34
+ const hasNestedChildren = !!nestedChildren;
45
35
  return /* @__PURE__ */ jsxs(Box, { as: "li", className: classNames("toc-layer-item", `layer-${slug(layer.id)}`), children: [
46
36
  /* @__PURE__ */ jsxs(
47
37
  Flex,
@@ -61,7 +51,7 @@ const LayerItem = memo(function LayerItem2(props) {
61
51
  layerGroupId,
62
52
  expanded,
63
53
  onClick: () => tocItem.setExpanded(!expanded),
64
- hasNestedChildren: !!nestedChildren
54
+ hasNestedChildren
65
55
  }
66
56
  ),
67
57
  /* @__PURE__ */ jsx(
@@ -100,17 +90,27 @@ const LayerItem = memo(function LayerItem2(props) {
100
90
  ]
101
91
  }
102
92
  ),
103
- nestedChildren && /* @__PURE__ */ jsx(
104
- Collapsible.Root,
105
- {
106
- open: expanded,
107
- id: layerGroupId,
108
- className: "toc-collapsible-item",
109
- children: /* @__PURE__ */ jsx(CollapsibleContent, { children: nestedChildren })
110
- }
111
- )
93
+ nestedChildren && /* @__PURE__ */ jsx(Collapsible.Root, { open: expanded, className: "toc-collapsible-item", children: /* @__PURE__ */ jsx(CollapsibleContent, { children: nestedChildren }) })
112
94
  ] });
113
95
  });
96
+ function useNestedChildren(layerGroupId, title, layer, intl) {
97
+ const childLayers = useChildLayers(layer);
98
+ const children = useMemo(() => {
99
+ if (childLayers?.length) {
100
+ return /* @__PURE__ */ jsx(
101
+ LayerList,
102
+ {
103
+ id: layerGroupId,
104
+ layers: childLayers,
105
+ ml: 4,
106
+ "aria-label": intl.formatMessage({ id: "childgroupLabel" }, { title })
107
+ }
108
+ );
109
+ }
110
+ return void 0;
111
+ }, [layerGroupId, intl, title, childLayers]);
112
+ return children;
113
+ }
114
114
  function CollapseButton(props) {
115
115
  const { layerTitle, layerGroupId, expanded, onClick, hasNestedChildren } = props;
116
116
  const icon = expanded ? /* @__PURE__ */ jsx(FiChevronDown, {}) : /* @__PURE__ */ jsx(FiChevronRight, {});
@@ -124,6 +124,7 @@ function CollapseButton(props) {
124
124
  className: "toc-layer-item-collapse-button",
125
125
  onClick,
126
126
  size: "sm",
127
+ focusRingOffset: "-2px",
127
128
  "aria-label": expanded ? intl.formatMessage({ id: "group.collapse" }, { title: layerTitle }) : intl.formatMessage({ id: "group.expand" }, { title: layerTitle }),
128
129
  "aria-expanded": expanded,
129
130
  "aria-controls": layerGroupId,
@@ -134,7 +135,7 @@ function CollapseButton(props) {
134
135
  background: "none"
135
136
  }
136
137
  },
137
- children: icon
138
+ children: /* @__PURE__ */ jsx(Icon, { children: icon })
138
139
  }
139
140
  );
140
141
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LayerItem.js","sources":["LayerItem.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { reactive } from \"@conterra/reactivity-core\";\nimport { Box, Collapsible, CollapsibleContent, Flex, IconButton, Spacer } from \"@chakra-ui/react\";\nimport { Tooltip } from \"@open-pioneer/chakra-snippets/tooltip\";\nimport { Checkbox } from \"@open-pioneer/chakra-snippets/checkbox\";\nimport { AnyLayer } from \"@open-pioneer/map\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport classNames from \"classnames\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { memo, ReactNode, useEffect, useId, useMemo } from \"react\";\nimport { FiAlertTriangle, FiChevronDown, FiChevronRight } from \"react-icons/fi\";\nimport { TocItem, useTocModel } from \"../../model/TocModel\";\nimport { slug } from \"../../utils/slug\";\nimport { useChildLayers, useLoadState } from \"./hooks\";\nimport { LayerItemMenu } from \"./LayerItemMenu\";\nimport { LayerList } from \"./LayerList\";\n\n/**\n * Renders a single layer as a list item.\n *\n * The item may have further nested list items if there are sublayers present.\n */\nexport const LayerItem = memo(function LayerItem(props: { layer: AnyLayer }): ReactNode {\n const { layer } = props;\n const intl = useIntl();\n const [tocItem, _tocModel, tocOptions] = useTocItem(layer);\n const expanded = useReactiveSnapshot(() => tocItem.isExpanded, [tocItem]);\n const isCollapsible = tocOptions ? tocOptions.collapsibleGroups : false;\n\n const layerGroupId = useId();\n const childLayers = useChildLayers(layer);\n const isAvailable = useLoadState(layer) !== \"error\";\n const notAvailableLabel = intl.formatMessage({ id: \"layerNotAvailable\" });\n const { title, description, isVisible } = useReactiveSnapshot(() => {\n return {\n title: layer.title,\n description: layer.description,\n isVisible: layer.visible\n };\n }, [layer]);\n\n let nestedChildren;\n if (childLayers?.length) {\n nestedChildren = (\n <LayerList\n layers={childLayers}\n ml={4}\n aria-label={intl.formatMessage({ id: \"childgroupLabel\" }, { title: title })}\n />\n );\n }\n return (\n <Box as=\"li\" className={classNames(\"toc-layer-item\", `layer-${slug(layer.id)}`)}>\n <Flex\n className=\"toc-layer-item-content\"\n width=\"100%\"\n flexDirection=\"row\"\n align=\"center\"\n justifyContent=\"space-between\"\n /** Gap to prevent bleeding of the buttons hover style into the layer title */\n gap={2}\n /** Aligned to the size of the (potential) menu button in LayerItemDescriptor */\n minHeight={10}\n >\n {isCollapsible && (\n <CollapseButton\n layerTitle={title}\n layerGroupId={layerGroupId}\n expanded={expanded}\n onClick={() => tocItem.setExpanded(!expanded)}\n hasNestedChildren={!!nestedChildren}\n />\n )}\n <Checkbox\n // Keyboard navigation jumps only to Checkboxes and uses the texts inside this DOM node.\n // The aria-labels of Tooltip and Icon is ignored by screenreader because they are no child element of the checkbox.\n // To consider the notAvailableLabel, an aria-label at the checkbox is necessary.\n aria-label={title + (!isAvailable ? \" \" + notAvailableLabel : \"\")}\n checked={isVisible}\n disabled={!isAvailable}\n onCheckedChange={(event) =>\n updateLayerVisibility(\n layer,\n event.checked === true,\n tocOptions.autoShowParents\n )\n }\n >\n {title}\n </Checkbox>\n {!isAvailable && (\n <Tooltip\n content={notAvailableLabel}\n positioning={{ placement: \"right\" }}\n openDelay={500}\n contentProps={{ className: \"toc-layer-item-content-tooltip\" }}\n >\n <span>\n <FiAlertTriangle\n className=\"toc-layer-item-content-icon\"\n color={\"red\"}\n aria-label={notAvailableLabel}\n />\n </span>\n </Tooltip>\n )}\n <Spacer />\n <LayerItemMenu layer={layer} title={title} description={description} intl={intl} />\n </Flex>\n {nestedChildren && (\n <Collapsible.Root\n open={expanded}\n id={layerGroupId}\n className=\"toc-collapsible-item\"\n >\n <CollapsibleContent>{nestedChildren}</CollapsibleContent>\n </Collapsible.Root>\n )}\n </Box>\n );\n});\n\nfunction CollapseButton(props: {\n layerTitle: string;\n layerGroupId: string;\n expanded: boolean;\n onClick: () => void;\n hasNestedChildren: boolean;\n}) {\n const { layerTitle, layerGroupId, expanded, onClick, hasNestedChildren } = props;\n const icon = expanded ? <FiChevronDown /> : <FiChevronRight />;\n const intl = useIntl();\n return (\n <IconButton\n variant=\"ghost\"\n borderRadius=\"full\"\n padding={0}\n className=\"toc-layer-item-collapse-button\"\n onClick={onClick}\n size=\"sm\"\n aria-label={\n expanded\n ? intl.formatMessage({ id: \"group.collapse\" }, { title: layerTitle })\n : intl.formatMessage({ id: \"group.expand\" }, { title: layerTitle })\n }\n aria-expanded={expanded}\n aria-controls={layerGroupId}\n //use visible:hidden for layers without children for correct indent\n visibility={hasNestedChildren ? \"visible\" : \"hidden\"}\n css={{\n // Chakra theme adds a background to components with \"aria-expanded\" by default.\n \"&:is([aria-expanded='true']):not(:hover)\": {\n background: \"none\"\n }\n }}\n >\n {icon}\n </IconButton>\n );\n}\n\n// Creates a toc item and registers it with the shared toc model.\nfunction useTocItem(layer: AnyLayer) {\n const tocModel = useTocModel();\n const options = useReactiveSnapshot(() => tocModel.options, [tocModel]);\n const tocItem = useMemo((): TocItem => {\n const expanded = reactive(!options.initiallyCollapsed);\n return {\n layerId: layer.id,\n get isExpanded(): boolean {\n return expanded.value;\n },\n setExpanded(expand: boolean) {\n expanded.value = expand;\n }\n };\n }, [layer, options.initiallyCollapsed]);\n\n // Register the item on the shared toc model\n useEffect(() => {\n tocModel.registerItem(tocItem);\n return () => tocModel.unregisterItem(tocItem);\n }, [tocModel, tocItem]);\n\n return [tocItem, tocModel, options] as const;\n}\n\nfunction updateLayerVisibility(layer: AnyLayer, visible: boolean, autoShowParents: boolean) {\n layer.setVisible(visible);\n if (visible && autoShowParents && layer.parent) {\n updateLayerVisibility(layer.parent, true, true);\n }\n}\n"],"names":["LayerItem"],"mappings":"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"}
1
+ {"version":3,"file":"LayerItem.js","sources":["LayerItem.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport {\n Box,\n Collapsible,\n CollapsibleContent,\n Flex,\n Icon,\n IconButton,\n Spacer\n} from \"@chakra-ui/react\";\nimport { reactive } from \"@conterra/reactivity-core\";\nimport { Checkbox } from \"@open-pioneer/chakra-snippets/checkbox\";\nimport { Tooltip } from \"@open-pioneer/chakra-snippets/tooltip\";\nimport { AnyLayer } from \"@open-pioneer/map\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport classNames from \"classnames\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { memo, ReactNode, useEffect, useId, useMemo } from \"react\";\nimport { FiAlertTriangle, FiChevronDown, FiChevronRight } from \"react-icons/fi\";\nimport { TocItem, useTocModel } from \"../../model/TocModel\";\nimport { slug } from \"../../utils/slug\";\nimport { useChildLayers, useLoadState } from \"./hooks\";\nimport { LayerItemMenu } from \"./LayerItemMenu\";\nimport { LayerList } from \"./LayerList\";\n\n/**\n * Renders a single layer as a list item.\n *\n * The item may have further nested list items if there are sublayers present.\n */\nexport const LayerItem = memo(function LayerItem(props: { layer: AnyLayer }): ReactNode {\n const { layer } = props;\n const intl = useIntl();\n const [tocItem, _tocModel, tocOptions] = useTocItem(layer);\n const expanded = useReactiveSnapshot(() => tocItem.isExpanded, [tocItem]);\n const isCollapsible = tocOptions ? tocOptions.collapsibleGroups : false;\n\n const layerGroupId = useId();\n const isAvailable = useLoadState(layer) !== \"error\";\n const notAvailableLabel = intl.formatMessage({ id: \"layerNotAvailable\" });\n const { title, description, isVisible } = useReactiveSnapshot(() => {\n return {\n title: layer.title,\n description: layer.description,\n isVisible: layer.visible\n };\n }, [layer]);\n\n const nestedChildren = useNestedChildren(layerGroupId, title, layer, intl);\n const hasNestedChildren = !!nestedChildren;\n return (\n <Box as=\"li\" className={classNames(\"toc-layer-item\", `layer-${slug(layer.id)}`)}>\n <Flex\n className=\"toc-layer-item-content\"\n width=\"100%\"\n flexDirection=\"row\"\n align=\"center\"\n justifyContent=\"space-between\"\n /** Gap to prevent bleeding of the buttons hover style into the layer title */\n gap={2}\n /** Aligned to the size of the (potential) menu button in LayerItemDescriptor */\n minHeight={10}\n >\n {isCollapsible && (\n <CollapseButton\n layerTitle={title}\n layerGroupId={layerGroupId}\n expanded={expanded}\n onClick={() => tocItem.setExpanded(!expanded)}\n hasNestedChildren={hasNestedChildren}\n />\n )}\n <Checkbox\n // Keyboard navigation jumps only to Checkboxes and uses the texts inside this DOM node.\n // The aria-labels of Tooltip and Icon is ignored by screen reader because they are no child element of the checkbox.\n // To consider the notAvailableLabel, an aria-label at the checkbox is necessary.\n aria-label={title + (!isAvailable ? \" \" + notAvailableLabel : \"\")}\n checked={isVisible}\n disabled={!isAvailable}\n onCheckedChange={(event) =>\n updateLayerVisibility(\n layer,\n event.checked === true,\n tocOptions.autoShowParents\n )\n }\n >\n {title}\n </Checkbox>\n {!isAvailable && (\n <Tooltip\n content={notAvailableLabel}\n positioning={{ placement: \"right\" }}\n openDelay={500}\n contentProps={{ className: \"toc-layer-item-content-tooltip\" }}\n >\n <span>\n <FiAlertTriangle\n className=\"toc-layer-item-content-icon\"\n color={\"red\"}\n aria-label={notAvailableLabel}\n />\n </span>\n </Tooltip>\n )}\n <Spacer />\n <LayerItemMenu layer={layer} title={title} description={description} intl={intl} />\n </Flex>\n {nestedChildren && (\n <Collapsible.Root open={expanded} className=\"toc-collapsible-item\">\n <CollapsibleContent>{nestedChildren}</CollapsibleContent>\n </Collapsible.Root>\n )}\n </Box>\n );\n});\n\nfunction useNestedChildren(\n layerGroupId: string,\n title: string,\n layer: AnyLayer,\n intl: PackageIntl\n) {\n const childLayers = useChildLayers(layer);\n const children = useMemo(() => {\n if (childLayers?.length) {\n return (\n <LayerList\n id={layerGroupId}\n layers={childLayers}\n ml={4}\n aria-label={intl.formatMessage({ id: \"childgroupLabel\" }, { title: title })}\n />\n );\n }\n return undefined;\n }, [layerGroupId, intl, title, childLayers]);\n return children;\n}\n\nfunction CollapseButton(props: {\n layerTitle: string;\n layerGroupId: string;\n expanded: boolean;\n onClick: () => void;\n hasNestedChildren: boolean;\n}) {\n const { layerTitle, layerGroupId, expanded, onClick, hasNestedChildren } = props;\n const icon = expanded ? <FiChevronDown /> : <FiChevronRight />;\n const intl = useIntl();\n return (\n <IconButton\n variant=\"ghost\"\n borderRadius=\"full\"\n padding={0}\n className=\"toc-layer-item-collapse-button\"\n onClick={onClick}\n size=\"sm\"\n focusRingOffset=\"-2px\"\n aria-label={\n expanded\n ? intl.formatMessage({ id: \"group.collapse\" }, { title: layerTitle })\n : intl.formatMessage({ id: \"group.expand\" }, { title: layerTitle })\n }\n aria-expanded={expanded}\n aria-controls={layerGroupId}\n //use visible:hidden for layers without children for correct indent\n visibility={hasNestedChildren ? \"visible\" : \"hidden\"}\n css={{\n // Chakra theme adds a background to components with \"aria-expanded\" by default.\n \"&:is([aria-expanded='true']):not(:hover)\": {\n background: \"none\"\n }\n }}\n >\n <Icon>{icon}</Icon>\n </IconButton>\n );\n}\n\n// Creates a toc item and registers it with the shared toc model.\nfunction useTocItem(layer: AnyLayer) {\n const tocModel = useTocModel();\n const options = useReactiveSnapshot(() => tocModel.options, [tocModel]);\n const tocItem = useMemo((): TocItem => {\n const expanded = reactive(!options.initiallyCollapsed);\n return {\n layerId: layer.id,\n get isExpanded(): boolean {\n return expanded.value;\n },\n setExpanded(expand: boolean) {\n expanded.value = expand;\n }\n };\n }, [layer, options.initiallyCollapsed]);\n\n // Register the item on the shared toc model\n useEffect(() => {\n tocModel.registerItem(tocItem);\n return () => tocModel.unregisterItem(tocItem);\n }, [tocModel, tocItem]);\n\n return [tocItem, tocModel, options] as const;\n}\n\nfunction updateLayerVisibility(layer: AnyLayer, visible: boolean, autoShowParents: boolean) {\n layer.setVisible(visible);\n if (visible && autoShowParents && layer.parent) {\n updateLayerVisibility(layer.parent, true, true);\n }\n}\n"],"names":["LayerItem"],"mappings":";;;;;;;;;;;;;;;;AAgCO,MAAM,SAAY,GAAA,IAAA,CAAK,SAASA,UAAAA,CAAU,KAAuC,EAAA;AACpF,EAAM,MAAA,EAAE,OAAU,GAAA,KAAA;AAClB,EAAA,MAAM,OAAO,OAAQ,EAAA;AACrB,EAAA,MAAM,CAAC,OAAS,EAAA,SAAA,EAAW,UAAU,CAAA,GAAI,WAAW,KAAK,CAAA;AACzD,EAAA,MAAM,WAAW,mBAAoB,CAAA,MAAM,QAAQ,UAAY,EAAA,CAAC,OAAO,CAAC,CAAA;AACxE,EAAM,MAAA,aAAA,GAAgB,UAAa,GAAA,UAAA,CAAW,iBAAoB,GAAA,KAAA;AAElE,EAAA,MAAM,eAAe,KAAM,EAAA;AAC3B,EAAM,MAAA,WAAA,GAAc,YAAa,CAAA,KAAK,CAAM,KAAA,OAAA;AAC5C,EAAA,MAAM,oBAAoB,IAAK,CAAA,aAAA,CAAc,EAAE,EAAA,EAAI,qBAAqB,CAAA;AACxE,EAAA,MAAM,EAAE,KAAO,EAAA,WAAA,EAAa,SAAU,EAAA,GAAI,oBAAoB,MAAM;AAChE,IAAO,OAAA;AAAA,MACH,OAAO,KAAM,CAAA,KAAA;AAAA,MACb,aAAa,KAAM,CAAA,WAAA;AAAA,MACnB,WAAW,KAAM,CAAA;AAAA,KACrB;AAAA,GACJ,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,MAAM,cAAiB,GAAA,iBAAA,CAAkB,YAAc,EAAA,KAAA,EAAO,OAAO,IAAI,CAAA;AACzE,EAAM,MAAA,iBAAA,GAAoB,CAAC,CAAC,cAAA;AAC5B,EAAA,uBACK,IAAA,CAAA,GAAA,EAAA,EAAI,EAAG,EAAA,IAAA,EAAK,SAAW,EAAA,UAAA,CAAW,gBAAkB,EAAA,CAAA,MAAA,EAAS,IAAK,CAAA,KAAA,CAAM,EAAE,CAAC,EAAE,CAC1E,EAAA,QAAA,EAAA;AAAA,oBAAA,IAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACG,SAAU,EAAA,wBAAA;AAAA,QACV,KAAM,EAAA,MAAA;AAAA,QACN,aAAc,EAAA,KAAA;AAAA,QACd,KAAM,EAAA,QAAA;AAAA,QACN,cAAe,EAAA,eAAA;AAAA,QAEf,GAAK,EAAA,CAAA;AAAA,QAEL,SAAW,EAAA,EAAA;AAAA,QAEV,QAAA,EAAA;AAAA,UACG,aAAA,oBAAA,GAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACG,UAAY,EAAA,KAAA;AAAA,cACZ,YAAA;AAAA,cACA,QAAA;AAAA,cACA,OAAS,EAAA,MAAM,OAAQ,CAAA,WAAA,CAAY,CAAC,QAAQ,CAAA;AAAA,cAC5C;AAAA;AAAA,WACJ;AAAA,0BAEJ,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAIG,YAAY,EAAA,KAAA,IAAS,CAAC,WAAA,GAAc,MAAM,iBAAoB,GAAA,EAAA,CAAA;AAAA,cAC9D,OAAS,EAAA,SAAA;AAAA,cACT,UAAU,CAAC,WAAA;AAAA,cACX,eAAA,EAAiB,CAAC,KACd,KAAA,qBAAA;AAAA,gBACI,KAAA;AAAA,gBACA,MAAM,OAAY,KAAA,IAAA;AAAA,gBAClB,UAAW,CAAA;AAAA,eACf;AAAA,cAGH,QAAA,EAAA;AAAA;AAAA,WACL;AAAA,UACC,CAAC,WACE,oBAAA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACG,OAAS,EAAA,iBAAA;AAAA,cACT,WAAA,EAAa,EAAE,SAAA,EAAW,OAAQ,EAAA;AAAA,cAClC,SAAW,EAAA,GAAA;AAAA,cACX,YAAA,EAAc,EAAE,SAAA,EAAW,gCAAiC,EAAA;AAAA,cAE5D,8BAAC,MACG,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,gBAAC,eAAA;AAAA,gBAAA;AAAA,kBACG,SAAU,EAAA,6BAAA;AAAA,kBACV,KAAO,EAAA,KAAA;AAAA,kBACP,YAAY,EAAA;AAAA;AAAA,eAEpB,EAAA;AAAA;AAAA,WACJ;AAAA,8BAEH,MAAO,EAAA,EAAA,CAAA;AAAA,0BACP,GAAA,CAAA,aAAA,EAAA,EAAc,KAAc,EAAA,KAAA,EAAc,aAA0B,IAAY,EAAA;AAAA;AAAA;AAAA,KACrF;AAAA,IACC,cACG,oBAAA,GAAA,CAAC,WAAY,CAAA,IAAA,EAAZ,EAAiB,IAAA,EAAM,QAAU,EAAA,SAAA,EAAU,sBACxC,EAAA,QAAA,kBAAA,GAAA,CAAC,kBAAoB,EAAA,EAAA,QAAA,EAAA,cAAA,EAAe,CACxC,EAAA;AAAA,GAER,EAAA,CAAA;AAER,CAAC;AAED,SAAS,iBACL,CAAA,YAAA,EACA,KACA,EAAA,KAAA,EACA,IACF,EAAA;AACE,EAAM,MAAA,WAAA,GAAc,eAAe,KAAK,CAAA;AACxC,EAAM,MAAA,QAAA,GAAW,QAAQ,MAAM;AAC3B,IAAA,IAAI,aAAa,MAAQ,EAAA;AACrB,MACI,uBAAA,GAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACG,EAAI,EAAA,YAAA;AAAA,UACJ,MAAQ,EAAA,WAAA;AAAA,UACR,EAAI,EAAA,CAAA;AAAA,UACJ,YAAA,EAAY,KAAK,aAAc,CAAA,EAAE,IAAI,iBAAkB,EAAA,EAAG,EAAE,KAAA,EAAc;AAAA;AAAA,OAC9E;AAAA;AAGR,IAAO,OAAA,MAAA;AAAA,KACR,CAAC,YAAA,EAAc,IAAM,EAAA,KAAA,EAAO,WAAW,CAAC,CAAA;AAC3C,EAAO,OAAA,QAAA;AACX;AAEA,SAAS,eAAe,KAMrB,EAAA;AACC,EAAA,MAAM,EAAE,UAAY,EAAA,YAAA,EAAc,QAAU,EAAA,OAAA,EAAS,mBAAsB,GAAA,KAAA;AAC3E,EAAA,MAAM,OAAO,QAAW,mBAAA,GAAA,CAAC,aAAc,EAAA,EAAA,CAAA,uBAAM,cAAe,EAAA,EAAA,CAAA;AAC5D,EAAA,MAAM,OAAO,OAAQ,EAAA;AACrB,EACI,uBAAA,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACG,OAAQ,EAAA,OAAA;AAAA,MACR,YAAa,EAAA,MAAA;AAAA,MACb,OAAS,EAAA,CAAA;AAAA,MACT,SAAU,EAAA,gCAAA;AAAA,MACV,OAAA;AAAA,MACA,IAAK,EAAA,IAAA;AAAA,MACL,eAAgB,EAAA,MAAA;AAAA,MAChB,YAAA,EACI,WACM,IAAK,CAAA,aAAA,CAAc,EAAE,EAAI,EAAA,gBAAA,EAAoB,EAAA,EAAE,KAAO,EAAA,UAAA,EAAY,CAClE,GAAA,IAAA,CAAK,cAAc,EAAE,EAAA,EAAI,gBAAkB,EAAA,EAAE,KAAO,EAAA,UAAA,EAAY,CAAA;AAAA,MAE1E,eAAe,EAAA,QAAA;AAAA,MACf,eAAe,EAAA,YAAA;AAAA,MAEf,UAAA,EAAY,oBAAoB,SAAY,GAAA,QAAA;AAAA,MAC5C,GAAK,EAAA;AAAA;AAAA,QAED,0CAA4C,EAAA;AAAA,UACxC,UAAY,EAAA;AAAA;AAChB,OACJ;AAAA,MAEA,QAAA,kBAAA,GAAA,CAAC,QAAM,QAAK,EAAA,IAAA,EAAA;AAAA;AAAA,GAChB;AAER;AAGA,SAAS,WAAW,KAAiB,EAAA;AACjC,EAAA,MAAM,WAAW,WAAY,EAAA;AAC7B,EAAA,MAAM,UAAU,mBAAoB,CAAA,MAAM,SAAS,OAAS,EAAA,CAAC,QAAQ,CAAC,CAAA;AACtE,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAe;AACnC,IAAA,MAAM,QAAW,GAAA,QAAA,CAAS,CAAC,OAAA,CAAQ,kBAAkB,CAAA;AACrD,IAAO,OAAA;AAAA,MACH,SAAS,KAAM,CAAA,EAAA;AAAA,MACf,IAAI,UAAsB,GAAA;AACtB,QAAA,OAAO,QAAS,CAAA,KAAA;AAAA,OACpB;AAAA,MACA,YAAY,MAAiB,EAAA;AACzB,QAAA,QAAA,CAAS,KAAQ,GAAA,MAAA;AAAA;AACrB,KACJ;AAAA,GACD,EAAA,CAAC,KAAO,EAAA,OAAA,CAAQ,kBAAkB,CAAC,CAAA;AAGtC,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,QAAA,CAAS,aAAa,OAAO,CAAA;AAC7B,IAAO,OAAA,MAAM,QAAS,CAAA,cAAA,CAAe,OAAO,CAAA;AAAA,GAC7C,EAAA,CAAC,QAAU,EAAA,OAAO,CAAC,CAAA;AAEtB,EAAO,OAAA,CAAC,OAAS,EAAA,QAAA,EAAU,OAAO,CAAA;AACtC;AAEA,SAAS,qBAAA,CAAsB,KAAiB,EAAA,OAAA,EAAkB,eAA0B,EAAA;AACxF,EAAA,KAAA,CAAM,WAAW,OAAO,CAAA;AACxB,EAAI,IAAA,OAAA,IAAW,eAAmB,IAAA,KAAA,CAAM,MAAQ,EAAA;AAC5C,IAAsB,qBAAA,CAAA,KAAA,CAAM,MAAQ,EAAA,IAAA,EAAM,IAAI,CAAA;AAAA;AAEtD;;;;"}
@@ -1,61 +1,69 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { Popover, IconButton, Portal, Text, CloseButton } from '@chakra-ui/react';
2
+ import { Popover, Portal, Text, CloseButton, IconButton, Icon } from '@chakra-ui/react';
3
+ import { Tooltip } from '@open-pioneer/chakra-snippets/tooltip';
4
+ import { useIntl } from '../../_virtual/_virtual-pioneer-module_react-hooks.js';
5
+ import { useId } from 'react';
3
6
  import { FiMoreVertical } from 'react-icons/fi';
4
7
  import { useLoadState } from './hooks.js';
5
8
 
6
9
  function LayerItemMenu(props) {
7
- const { layer, title, description, intl } = props;
10
+ const { layer, title, description } = props;
8
11
  const isPresent = !!description;
9
- const buttonLabel = intl.formatMessage({ id: "descriptionLabel" });
10
- const isAvailable = useLoadState(layer) !== "error";
11
- return isPresent && /* @__PURE__ */ jsxs(Popover.Root, { lazyMount: true, positioning: { placement: "bottom-start" }, children: [
12
- /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
13
- IconButton,
14
- {
15
- disabled: !isAvailable,
16
- className: "toc-layer-item-details-button",
17
- "aria-label": buttonLabel,
18
- borderRadius: "full",
19
- padding: 0,
20
- variant: "ghost",
21
- size: "sm",
22
- children: /* @__PURE__ */ jsx(FiMoreVertical, { spacing: 0 })
23
- }
24
- ) }),
25
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsxs(
26
- Popover.Content,
27
- {
28
- className: "toc-layer-item-details",
29
- overflowY: "auto",
30
- maxHeight: "400",
31
- children: [
32
- /* @__PURE__ */ jsx(Popover.Arrow, {}),
33
- /* @__PURE__ */ jsxs(Popover.Body, { children: [
34
- /* @__PURE__ */ jsx(Popover.Title, { className: "toc-layer-item-details-title", children: title }),
35
- /* @__PURE__ */ jsx(Text, { my: "2", className: "toc-layer-item-details-description", children: description })
36
- ] }),
37
- /* @__PURE__ */ jsx(
38
- Popover.CloseTrigger,
39
- {
40
- position: "absolute",
41
- top: "1",
42
- right: "1",
43
- mt: 3,
44
- asChild: true,
45
- children: /* @__PURE__ */ jsx(
12
+ const triggerId = useId();
13
+ return isPresent && /* @__PURE__ */ jsxs(
14
+ Popover.Root,
15
+ {
16
+ ids: { trigger: triggerId },
17
+ positioning: { placement: "bottom-start" },
18
+ lazyMount: true,
19
+ unmountOnExit: true,
20
+ children: [
21
+ /* @__PURE__ */ jsx(TriggerButton, { triggerId, layer }),
22
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsxs(
23
+ Popover.Content,
24
+ {
25
+ className: "toc-layer-item-details",
26
+ overflowY: "auto",
27
+ maxHeight: "400",
28
+ children: [
29
+ /* @__PURE__ */ jsx(Popover.Arrow, {}),
30
+ /* @__PURE__ */ jsxs(Popover.Body, { children: [
31
+ /* @__PURE__ */ jsx(Popover.Title, { className: "toc-layer-item-details-title", children: title }),
32
+ /* @__PURE__ */ jsx(Text, { my: "2", className: "toc-layer-item-details-description", children: description })
33
+ ] }),
34
+ /* @__PURE__ */ jsx(Popover.CloseTrigger, { position: "absolute", top: "1", right: "1", asChild: true, children: /* @__PURE__ */ jsx(
46
35
  CloseButton,
47
36
  {
48
37
  className: "toc-layer-item-details-button",
49
38
  variant: "ghost",
50
39
  size: "sm"
51
40
  }
52
- )
53
- }
54
- )
55
- ]
56
- }
57
- ) }) })
58
- ] });
41
+ ) })
42
+ ]
43
+ }
44
+ ) }) })
45
+ ]
46
+ }
47
+ );
48
+ }
49
+ function TriggerButton(props) {
50
+ const { layer, triggerId } = props;
51
+ const intl = useIntl();
52
+ const buttonLabel = intl.formatMessage({ id: "descriptionLabel" });
53
+ const isAvailable = useLoadState(layer) !== "error";
54
+ return /* @__PURE__ */ jsx(Tooltip, { ids: { trigger: triggerId }, content: buttonLabel, children: /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
55
+ IconButton,
56
+ {
57
+ disabled: !isAvailable,
58
+ className: "toc-layer-item-details-button",
59
+ "aria-label": buttonLabel,
60
+ borderRadius: "full",
61
+ focusRingOffset: "-2px",
62
+ variant: "ghost",
63
+ size: "sm",
64
+ children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(FiMoreVertical, { spacing: 0 }) })
65
+ }
66
+ ) }) });
59
67
  }
60
68
 
61
69
  export { LayerItemMenu };
@@ -1 +1 @@
1
- {"version":3,"file":"LayerItemMenu.js","sources":["LayerItemMenu.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { IconButton, CloseButton, Popover, Portal, Text } from \"@chakra-ui/react\";\nimport { AnyLayer } from \"@open-pioneer/map\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { FiMoreVertical } from \"react-icons/fi\";\nimport { useLoadState } from \"./hooks\";\n\nexport function LayerItemMenu(props: {\n layer: AnyLayer;\n title: string;\n description: string;\n intl: PackageIntl;\n}) {\n const { layer, title, description, intl } = props;\n const isPresent = !!description;\n const buttonLabel = intl.formatMessage({ id: \"descriptionLabel\" });\n const isAvailable = useLoadState(layer) !== \"error\";\n\n return (\n isPresent && (\n <Popover.Root lazyMount={true} positioning={{ placement: \"bottom-start\" }}>\n <Popover.Trigger asChild>\n <IconButton\n disabled={!isAvailable}\n className=\"toc-layer-item-details-button\"\n aria-label={buttonLabel}\n borderRadius=\"full\"\n padding={0}\n variant=\"ghost\"\n size=\"sm\"\n >\n <FiMoreVertical spacing={0} />\n </IconButton>\n </Popover.Trigger>\n <Portal>\n <Popover.Positioner>\n <Popover.Content\n className=\"toc-layer-item-details\"\n overflowY=\"auto\"\n maxHeight=\"400\"\n >\n <Popover.Arrow></Popover.Arrow>\n <Popover.Body>\n <Popover.Title className=\"toc-layer-item-details-title\">\n {title}\n </Popover.Title>\n <Text my=\"2\" className=\"toc-layer-item-details-description\">\n {description}\n </Text>\n </Popover.Body>\n <Popover.CloseTrigger\n position=\"absolute\"\n top=\"1\"\n right=\"1\"\n mt={3}\n asChild\n >\n <CloseButton\n className=\"toc-layer-item-details-button\"\n variant=\"ghost\"\n size=\"sm\"\n />\n </Popover.CloseTrigger>\n </Popover.Content>\n </Popover.Positioner>\n </Portal>\n </Popover.Root>\n )\n );\n}\n"],"names":[],"mappings":";;;;;AAQO,SAAS,cAAc,KAK3B,EAAA;AACC,EAAA,MAAM,EAAE,KAAA,EAAO,KAAO,EAAA,WAAA,EAAa,MAAS,GAAA,KAAA;AAC5C,EAAM,MAAA,SAAA,GAAY,CAAC,CAAC,WAAA;AACpB,EAAA,MAAM,cAAc,IAAK,CAAA,aAAA,CAAc,EAAE,EAAA,EAAI,oBAAoB,CAAA;AACjE,EAAM,MAAA,WAAA,GAAc,YAAa,CAAA,KAAK,CAAM,KAAA,OAAA;AAE5C,EACI,OAAA,SAAA,oBACK,IAAA,CAAA,OAAA,CAAQ,IAAR,EAAA,EAAa,SAAW,EAAA,IAAA,EAAM,WAAa,EAAA,EAAE,SAAW,EAAA,cAAA,EACrD,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,OAAQ,CAAA,OAAA,EAAR,EAAgB,OAAA,EAAO,IACpB,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACG,UAAU,CAAC,WAAA;AAAA,QACX,SAAU,EAAA,+BAAA;AAAA,QACV,YAAY,EAAA,WAAA;AAAA,QACZ,YAAa,EAAA,MAAA;AAAA,QACb,OAAS,EAAA,CAAA;AAAA,QACT,OAAQ,EAAA,OAAA;AAAA,QACR,IAAK,EAAA,IAAA;AAAA,QAEL,QAAA,kBAAA,GAAA,CAAC,cAAe,EAAA,EAAA,OAAA,EAAS,CAAG,EAAA;AAAA;AAAA,KAEpC,EAAA,CAAA;AAAA,oBACC,GAAA,CAAA,MAAA,EAAA,EACG,QAAC,kBAAA,GAAA,CAAA,OAAA,CAAQ,YAAR,EACG,QAAA,kBAAA,IAAA;AAAA,MAAC,OAAQ,CAAA,OAAA;AAAA,MAAR;AAAA,QACG,SAAU,EAAA,wBAAA;AAAA,QACV,SAAU,EAAA,MAAA;AAAA,QACV,SAAU,EAAA,KAAA;AAAA,QAEV,QAAA,EAAA;AAAA,0BAAC,GAAA,CAAA,OAAA,CAAQ,OAAR,EAAc,CAAA;AAAA,0BACf,IAAA,CAAC,OAAQ,CAAA,IAAA,EAAR,EACG,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,OAAQ,CAAA,KAAA,EAAR,EAAc,SAAA,EAAU,gCACpB,QACL,EAAA,KAAA,EAAA,CAAA;AAAA,gCACC,IAAK,EAAA,EAAA,EAAA,EAAG,GAAI,EAAA,SAAA,EAAU,sCAClB,QACL,EAAA,WAAA,EAAA;AAAA,WACJ,EAAA,CAAA;AAAA,0BACA,GAAA;AAAA,YAAC,OAAQ,CAAA,YAAA;AAAA,YAAR;AAAA,cACG,QAAS,EAAA,UAAA;AAAA,cACT,GAAI,EAAA,GAAA;AAAA,cACJ,KAAM,EAAA,GAAA;AAAA,cACN,EAAI,EAAA,CAAA;AAAA,cACJ,OAAO,EAAA,IAAA;AAAA,cAEP,QAAA,kBAAA,GAAA;AAAA,gBAAC,WAAA;AAAA,gBAAA;AAAA,kBACG,SAAU,EAAA,+BAAA;AAAA,kBACV,OAAQ,EAAA,OAAA;AAAA,kBACR,IAAK,EAAA;AAAA;AAAA;AACT;AAAA;AACJ;AAAA;AAAA,OAER,CACJ,EAAA;AAAA,GACJ,EAAA,CAAA;AAGZ;;;;"}
1
+ {"version":3,"file":"LayerItemMenu.js","sources":["LayerItemMenu.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { CloseButton, Icon, IconButton, Popover, Portal, Text } from \"@chakra-ui/react\";\nimport { Tooltip } from \"@open-pioneer/chakra-snippets/tooltip\";\nimport { AnyLayer } from \"@open-pioneer/map\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { useId } from \"react\";\nimport { FiMoreVertical } from \"react-icons/fi\";\nimport { useLoadState } from \"./hooks\";\n\nexport function LayerItemMenu(props: {\n layer: AnyLayer;\n title: string;\n description: string;\n intl: PackageIntl;\n}) {\n const { layer, title, description } = props;\n const isPresent = !!description;\n\n const triggerId = useId(); // see https://chakra-ui.com/docs/components/tooltip#with-menutrigger\n\n return (\n isPresent && (\n <Popover.Root\n ids={{ trigger: triggerId }}\n positioning={{ placement: \"bottom-start\" }}\n lazyMount={true}\n unmountOnExit={true}\n >\n <TriggerButton triggerId={triggerId} layer={layer} />\n <Portal>\n <Popover.Positioner>\n <Popover.Content\n className=\"toc-layer-item-details\"\n overflowY=\"auto\"\n maxHeight=\"400\"\n >\n <Popover.Arrow></Popover.Arrow>\n <Popover.Body>\n <Popover.Title className=\"toc-layer-item-details-title\">\n {title}\n </Popover.Title>\n <Text my=\"2\" className=\"toc-layer-item-details-description\">\n {description}\n </Text>\n </Popover.Body>\n <Popover.CloseTrigger position=\"absolute\" top=\"1\" right=\"1\" asChild>\n <CloseButton\n className=\"toc-layer-item-details-button\"\n variant=\"ghost\"\n size=\"sm\"\n />\n </Popover.CloseTrigger>\n </Popover.Content>\n </Popover.Positioner>\n </Portal>\n </Popover.Root>\n )\n );\n}\n\nfunction TriggerButton(props: { triggerId: string; layer: AnyLayer }) {\n const { layer, triggerId } = props;\n const intl = useIntl();\n const buttonLabel = intl.formatMessage({ id: \"descriptionLabel\" });\n const isAvailable = useLoadState(layer) !== \"error\";\n\n return (\n <Tooltip ids={{ trigger: triggerId }} content={buttonLabel}>\n <Popover.Trigger asChild>\n <IconButton\n disabled={!isAvailable}\n className=\"toc-layer-item-details-button\"\n aria-label={buttonLabel}\n borderRadius=\"full\"\n focusRingOffset=\"-2px\"\n variant=\"ghost\"\n size=\"sm\"\n >\n <Icon>\n <FiMoreVertical spacing={0} />\n </Icon>\n </IconButton>\n </Popover.Trigger>\n </Tooltip>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { Box, List, Text } from '@chakra-ui/react';
2
+ import { List, Text } from '@chakra-ui/react';
3
3
  import { useIntl } from '../../_virtual/_virtual-pioneer-module_react-hooks.js';
4
4
  import { memo, useMemo } from 'react';
5
5
  import { LayerItem } from './LayerItem.js';
@@ -20,17 +20,16 @@ const LayerList = memo(function LayerList2(props) {
20
20
  () => layers.map((layer) => /* @__PURE__ */ jsx(LayerItem, { layer }, layer.id)),
21
21
  [layers]
22
22
  );
23
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
23
+ return /* @__PURE__ */ jsx(
24
24
  List.Root,
25
25
  {
26
26
  as: "ul",
27
27
  className: "toc-layer-list",
28
28
  listStyleType: "none",
29
- role: "group",
30
29
  ...listProps,
31
30
  children: items
32
31
  }
33
- ) });
32
+ );
34
33
  });
35
34
 
36
35
  export { LayerList, TopLevelLayerList };
@@ -1 +1 @@
1
- {"version":3,"file":"LayerList.js","sources":["LayerList.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box, List, Text, ListRootProps } from \"@chakra-ui/react\";\nimport { AnyLayer, MapModel } from \"@open-pioneer/map\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { memo, useMemo } from \"react\";\nimport { LayerItem } from \"./LayerItem\";\nimport { useLayers } from \"./hooks\";\n\ninterface TopLevelLayerListProps {\n map: MapModel;\n\n /** The label of the list group (<ul>) */\n \"aria-label\"?: string;\n}\n\n/**\n * Lists the operational layers in the map.\n */\nexport const TopLevelLayerList = memo(function TopLevelLayerList(props: TopLevelLayerListProps) {\n const { map, \"aria-label\": ariaLabel } = props;\n const intl = useIntl();\n const layers = useLayers(map);\n\n if (!layers.length) {\n return (\n <Text className=\"toc-missing-layers\" aria-label={ariaLabel}>\n {intl.formatMessage({ id: \"missingLayers\" })}\n </Text>\n );\n }\n\n return <LayerList layers={layers} aria-label={ariaLabel} />;\n});\n\n/**\n * Renders the given layers as a list (<ul>).\n */\nexport const LayerList = memo(function LayerList(props: { layers: AnyLayer[] } & ListRootProps) {\n const { layers, ...listProps } = props;\n const items = useMemo(\n () => layers.map((layer) => <LayerItem key={layer.id} layer={layer} />),\n [layers]\n );\n\n return (\n <Box>\n <List.Root\n // Note: not using UnorderedList because it adds default margins\n as=\"ul\"\n className=\"toc-layer-list\"\n listStyleType=\"none\"\n role=\"group\"\n {...listProps}\n >\n {items}\n </List.Root>\n </Box>\n );\n});\n"],"names":["TopLevelLayerList","LayerList"],"mappings":";;;;;;;AAmBO,MAAM,iBAAoB,GAAA,IAAA,CAAK,SAASA,kBAAAA,CAAkB,KAA+B,EAAA;AAC5F,EAAA,MAAM,EAAE,GAAA,EAAK,YAAc,EAAA,SAAA,EAAc,GAAA,KAAA;AACzC,EAAA,MAAM,OAAO,OAAQ,EAAA;AACrB,EAAM,MAAA,MAAA,GAAS,UAAU,GAAG,CAAA;AAE5B,EAAI,IAAA,CAAC,OAAO,MAAQ,EAAA;AAChB,IAAA,uBACK,GAAA,CAAA,IAAA,EAAA,EAAK,SAAU,EAAA,oBAAA,EAAqB,YAAY,EAAA,SAAA,EAC5C,QAAK,EAAA,IAAA,CAAA,aAAA,CAAc,EAAE,EAAA,EAAI,eAAgB,EAAC,CAC/C,EAAA,CAAA;AAAA;AAIR,EAAA,uBAAQ,GAAA,CAAA,SAAA,EAAA,EAAU,MAAgB,EAAA,YAAA,EAAY,SAAW,EAAA,CAAA;AAC7D,CAAC;AAKM,MAAM,SAAY,GAAA,IAAA,CAAK,SAASC,UAAAA,CAAU,KAA+C,EAAA;AAC5F,EAAA,MAAM,EAAE,MAAA,EAAQ,GAAG,SAAA,EAAc,GAAA,KAAA;AACjC,EAAA,MAAM,KAAQ,GAAA,OAAA;AAAA,IACV,MAAM,MAAO,CAAA,GAAA,CAAI,CAAC,KAAA,yBAAW,SAAyB,EAAA,EAAA,KAAA,EAAA,EAAV,KAAM,CAAA,EAAkB,CAAE,CAAA;AAAA,IACtE,CAAC,MAAM;AAAA,GACX;AAEA,EAAA,2BACK,GACG,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,IAAK,CAAA,IAAA;AAAA,IAAL;AAAA,MAEG,EAAG,EAAA,IAAA;AAAA,MACH,SAAU,EAAA,gBAAA;AAAA,MACV,aAAc,EAAA,MAAA;AAAA,MACd,IAAK,EAAA,OAAA;AAAA,MACJ,GAAG,SAAA;AAAA,MAEH,QAAA,EAAA;AAAA;AAAA,GAET,EAAA,CAAA;AAER,CAAC;;;;"}
1
+ {"version":3,"file":"LayerList.js","sources":["LayerList.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { List, ListRootProps, Text } from \"@chakra-ui/react\";\nimport { AnyLayer, MapModel } from \"@open-pioneer/map\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { memo, useMemo } from \"react\";\nimport { LayerItem } from \"./LayerItem\";\nimport { useLayers } from \"./hooks\";\n\ninterface TopLevelLayerListProps {\n map: MapModel;\n\n /** The label of the list group (<ul>) */\n \"aria-label\"?: string;\n}\n\n/**\n * Lists the operational layers in the map.\n */\nexport const TopLevelLayerList = memo(function TopLevelLayerList(props: TopLevelLayerListProps) {\n const { map, \"aria-label\": ariaLabel } = props;\n const intl = useIntl();\n const layers = useLayers(map);\n\n if (!layers.length) {\n return (\n <Text className=\"toc-missing-layers\" aria-label={ariaLabel}>\n {intl.formatMessage({ id: \"missingLayers\" })}\n </Text>\n );\n }\n\n return <LayerList layers={layers} aria-label={ariaLabel} />;\n});\n\n/**\n * Renders the given layers as a list (<ul>).\n */\nexport const LayerList = memo(function LayerList(props: { layers: AnyLayer[] } & ListRootProps) {\n const { layers, ...listProps } = props;\n const items = useMemo(\n () => layers.map((layer) => <LayerItem key={layer.id} layer={layer} />),\n [layers]\n );\n\n return (\n <List.Root\n // Note: not using UnorderedList because it adds default margins\n as=\"ul\"\n className=\"toc-layer-list\"\n listStyleType=\"none\"\n {...listProps}\n >\n {items}\n </List.Root>\n );\n});\n"],"names":["TopLevelLayerList","LayerList"],"mappings":";;;;;;;AAmBO,MAAM,iBAAoB,GAAA,IAAA,CAAK,SAASA,kBAAAA,CAAkB,KAA+B,EAAA;AAC5F,EAAA,MAAM,EAAE,GAAA,EAAK,YAAc,EAAA,SAAA,EAAc,GAAA,KAAA;AACzC,EAAA,MAAM,OAAO,OAAQ,EAAA;AACrB,EAAM,MAAA,MAAA,GAAS,UAAU,GAAG,CAAA;AAE5B,EAAI,IAAA,CAAC,OAAO,MAAQ,EAAA;AAChB,IAAA,uBACK,GAAA,CAAA,IAAA,EAAA,EAAK,SAAU,EAAA,oBAAA,EAAqB,YAAY,EAAA,SAAA,EAC5C,QAAK,EAAA,IAAA,CAAA,aAAA,CAAc,EAAE,EAAA,EAAI,eAAgB,EAAC,CAC/C,EAAA,CAAA;AAAA;AAIR,EAAA,uBAAQ,GAAA,CAAA,SAAA,EAAA,EAAU,MAAgB,EAAA,YAAA,EAAY,SAAW,EAAA,CAAA;AAC7D,CAAC;AAKM,MAAM,SAAY,GAAA,IAAA,CAAK,SAASC,UAAAA,CAAU,KAA+C,EAAA;AAC5F,EAAA,MAAM,EAAE,MAAA,EAAQ,GAAG,SAAA,EAAc,GAAA,KAAA;AACjC,EAAA,MAAM,KAAQ,GAAA,OAAA;AAAA,IACV,MAAM,MAAO,CAAA,GAAA,CAAI,CAAC,KAAA,yBAAW,SAAyB,EAAA,EAAA,KAAA,EAAA,EAAV,KAAM,CAAA,EAAkB,CAAE,CAAA;AAAA,IACtE,CAAC,MAAM;AAAA,GACX;AAEA,EACI,uBAAA,GAAA;AAAA,IAAC,IAAK,CAAA,IAAA;AAAA,IAAL;AAAA,MAEG,EAAG,EAAA,IAAA;AAAA,MACH,SAAU,EAAA,gBAAA;AAAA,MACV,aAAc,EAAA,MAAA;AAAA,MACb,GAAG,SAAA;AAAA,MAEH,QAAA,EAAA;AAAA;AAAA,GACL;AAER,CAAC;;;;"}
package/ui/Toc.js CHANGED
@@ -42,7 +42,7 @@ function TocContent(props) {
42
42
  const intl = useIntl();
43
43
  const model = useTocModel(props);
44
44
  const basemapsHeadingId = useId();
45
- const basemapSwitcher = showBasemapSwitcher && /* @__PURE__ */ jsx(Box, { className: "toc-basemap-switcher", children: /* @__PURE__ */ jsx(
45
+ const basemapSwitcher = showBasemapSwitcher && /* @__PURE__ */ jsx(Box, { className: "toc-basemap-switcher", mb: PADDING, children: /* @__PURE__ */ jsx(
46
46
  TitledSection,
47
47
  {
48
48
  title: /* @__PURE__ */ jsx(SectionHeading, { id: basemapsHeadingId, size: "sm", mb: PADDING, children: intl.formatMessage({ id: "basemapsLabel" }) }),
@@ -59,8 +59,8 @@ function TocContent(props) {
59
59
  const layerList = /* @__PURE__ */ jsx(Box, { className: "toc-operational-layers", children: /* @__PURE__ */ jsx(
60
60
  TitledSection,
61
61
  {
62
- title: /* @__PURE__ */ jsx(SectionHeading, { size: "sm", mb: 2, children: /* @__PURE__ */ jsxs(Flex, { children: [
63
- /* @__PURE__ */ jsx(Text, { my: 3, children: intl.formatMessage({
62
+ title: /* @__PURE__ */ jsx(SectionHeading, { size: "sm", children: /* @__PURE__ */ jsxs(Flex, { children: [
63
+ /* @__PURE__ */ jsx(Text, { children: intl.formatMessage({
64
64
  id: "operationalLayerLabel"
65
65
  }) }),
66
66
  /* @__PURE__ */ jsx(Spacer, {}),
package/ui/Toc.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Toc.js","sources":["Toc.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { reactive, reactiveMap } from \"@conterra/reactivity-core\";\nimport { BasemapSwitcher, BasemapSwitcherProps } from \"@open-pioneer/basemap-switcher\";\nimport { Box, Flex, Spacer, Text } from \"@chakra-ui/react\";\nimport { MapModel, MapModelProps, useMapModel } from \"@open-pioneer/map\";\nimport {\n CommonComponentProps,\n SectionHeading,\n TitledSection,\n useCommonComponentProps\n} from \"@open-pioneer/react-utils\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, ReactNode, useEffect, useId, useMemo, useRef } from \"react\";\nimport { TocItem, TocModel, TocModelProvider, TocWidgetOptions } from \"../model/TocModel\";\nimport { TopLevelLayerList } from \"./LayerList/LayerList\";\nimport { Tools } from \"./Tools\";\n\n/**\n * Props supported by the {@link Toc} component.\n */\nexport interface TocProps extends CommonComponentProps, MapModelProps {\n /**\n * Defines whether the tool component is shown in the toc.\n *\n * Defaults to `false`.\n */\n showTools?: boolean;\n\n /**\n * Properties for the embedded tool component.\n */\n toolsConfig?: ToolsConfig;\n\n /**\n * Defines whether the basemap switcher is shown in the toc.\n *\n * Defaults to `true`.\n */\n showBasemapSwitcher?: boolean;\n\n /**\n * Properties for the embedded basemap switcher.\n *\n * Property `mapId` is not applied (the basemap switcher uses the same map as the toc).\n */\n basemapSwitcherProps?: Omit<BasemapSwitcherProps, \"mapId\">;\n\n /**\n * If `true`, groups in the toc can be collapsed and expanded.\n * This property should only be `true` if the map actually contains layer groups.\n *\n * Defaults to `false`.\n */\n collapsibleGroups?: boolean;\n\n /**\n * If `true` groups in the toc are collapsed initially.\n *\n * Defaults to `false`. If {@link collapsibleGroups} is `false` this property should also be `false`. Otherwise, only the top level layers will appear in the toc.\n */\n initiallyCollapsed?: boolean;\n\n /**\n * Show the parent layers when a child layer is made visible.\n *\n * Defaults to `true`.\n */\n autoShowParents?: boolean;\n}\n\n/**\n * Props supported by the {@link Tools} component.\n */\nexport interface ToolsConfig {\n /**\n * Optional property to show the `hide all layers` entry.\n *\n * Defaults to `true`.\n */\n showHideAllLayers?: boolean;\n\n /**\n * Optional property to show the `collapse all groups` entry.\n *\n * Defaults to `true`. Only applicable if {@link TocProps.collapsibleGroups} is `true`.\n */\n showCollapseAllGroups?: boolean;\n}\n\nconst PADDING = 2;\n\n/**\n * Displays the layers of the configured map.\n */\nexport const Toc: FC<TocProps> = (props: TocProps) => {\n const intl = useIntl();\n const { containerProps } = useCommonComponentProps(\"toc\", props);\n const state = useMapModel(props);\n\n let content: ReactNode | null;\n switch (state.kind) {\n case \"loading\":\n content = null;\n break;\n case \"rejected\":\n content = <Text className=\"toc-error\">{intl.formatMessage({ id: \"error\" })}</Text>;\n break;\n case \"resolved\": {\n const map = state.map;\n content = <TocContent {...props} map={map} />;\n break;\n }\n }\n\n return (\n <Flex {...containerProps} direction=\"column\" gap={PADDING}>\n {content}\n </Flex>\n );\n};\n\n/** This component is rendered once we have a reference to the loaded map model. */\nfunction TocContent(props: TocProps & { map: MapModel }) {\n const {\n map,\n showTools = false,\n toolsConfig,\n showBasemapSwitcher = true,\n basemapSwitcherProps\n } = props;\n const intl = useIntl();\n const model = useTocModel(props);\n const basemapsHeadingId = useId();\n const basemapSwitcher = showBasemapSwitcher && (\n <Box className=\"toc-basemap-switcher\">\n <TitledSection\n title={\n <SectionHeading id={basemapsHeadingId} size={\"sm\"} mb={PADDING}>\n {intl.formatMessage({ id: \"basemapsLabel\" })}\n </SectionHeading>\n }\n >\n <BasemapSwitcher\n map={map}\n aria-labelledby={basemapsHeadingId}\n {...basemapSwitcherProps}\n />\n </TitledSection>\n </Box>\n );\n\n const layerList = (\n <Box className=\"toc-operational-layers\">\n <TitledSection\n title={\n <SectionHeading size={\"sm\"} mb={2}>\n <Flex>\n <Text my={3}>\n {intl.formatMessage({\n id: \"operationalLayerLabel\"\n })}\n </Text>\n <Spacer />\n {showTools && <Tools map={map} {...toolsConfig} />}\n </Flex>\n </SectionHeading>\n }\n >\n <TopLevelLayerList\n map={map}\n aria-label={intl.formatMessage({ id: \"operationalLayerLabel\" })}\n />\n </TitledSection>\n </Box>\n );\n\n return (\n <TocModelProvider value={model}>\n {basemapSwitcher}\n {layerList}\n </TocModelProvider>\n );\n}\n\nfunction useTocModel(props: TocProps): TocModel {\n const initialProps = useRef(props);\n const { model, options } = useMemo(() => {\n const options = reactive<TocWidgetOptions>(\n createOptions(\n initialProps.current.autoShowParents,\n initialProps.current.collapsibleGroups,\n initialProps.current.initiallyCollapsed\n )\n );\n\n // Indexed by layerId\n const items = reactiveMap<string, TocItem>();\n const model: TocModel = {\n get options() {\n return options.value;\n },\n getItem(layerId: string): TocItem | undefined {\n return items.get(layerId);\n },\n getItems(): TocItem[] {\n return Array.from(items.values());\n },\n registerItem(item: TocItem): void {\n if (items.has(item.layerId)) {\n throw new Error(`Item with layerId '${item.layerId}' already registered.`);\n }\n items.set(item.layerId, item);\n },\n unregisterItem(item: TocItem): void {\n if (items.get(item.layerId) !== item) {\n throw new Error(`Item with layerId '${item.layerId}' not registered.`);\n }\n items.delete(item.layerId);\n }\n };\n return { model, options };\n }, []);\n\n // Sync props to model\n useEffect(() => {\n options.value = createOptions(\n props.autoShowParents,\n props.collapsibleGroups,\n props.initiallyCollapsed\n );\n }, [options, props.autoShowParents, props.collapsibleGroups, props.initiallyCollapsed]);\n\n return model;\n}\n\nfunction createOptions(\n autoShowParents?: boolean | undefined,\n collapsibleGroups?: boolean | undefined,\n isCollapsed?: boolean | undefined\n): TocWidgetOptions {\n return {\n autoShowParents: autoShowParents ?? true,\n collapsibleGroups: collapsibleGroups ?? false,\n initiallyCollapsed: isCollapsed ?? false\n };\n}\n"],"names":["options","model"],"mappings":"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"}
1
+ {"version":3,"file":"Toc.js","sources":["Toc.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { reactive, reactiveMap } from \"@conterra/reactivity-core\";\nimport { BasemapSwitcher, BasemapSwitcherProps } from \"@open-pioneer/basemap-switcher\";\nimport { Box, Flex, Spacer, Text } from \"@chakra-ui/react\";\nimport { MapModel, MapModelProps, useMapModel } from \"@open-pioneer/map\";\nimport {\n CommonComponentProps,\n SectionHeading,\n TitledSection,\n useCommonComponentProps\n} from \"@open-pioneer/react-utils\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, ReactNode, useEffect, useId, useMemo, useRef } from \"react\";\nimport { TocItem, TocModel, TocModelProvider, TocWidgetOptions } from \"../model/TocModel\";\nimport { TopLevelLayerList } from \"./LayerList/LayerList\";\nimport { Tools } from \"./Tools\";\n\n/**\n * Props supported by the {@link Toc} component.\n */\nexport interface TocProps extends CommonComponentProps, MapModelProps {\n /**\n * Defines whether the tool component is shown in the toc.\n *\n * Defaults to `false`.\n */\n showTools?: boolean;\n\n /**\n * Properties for the embedded tool component.\n */\n toolsConfig?: ToolsConfig;\n\n /**\n * Defines whether the basemap switcher is shown in the toc.\n *\n * Defaults to `true`.\n */\n showBasemapSwitcher?: boolean;\n\n /**\n * Properties for the embedded basemap switcher.\n *\n * Property `mapId` is not applied (the basemap switcher uses the same map as the toc).\n */\n basemapSwitcherProps?: Omit<BasemapSwitcherProps, \"mapId\">;\n\n /**\n * If `true`, groups in the toc can be collapsed and expanded.\n * This property should only be `true` if the map actually contains layer groups.\n *\n * Defaults to `false`.\n */\n collapsibleGroups?: boolean;\n\n /**\n * If `true` groups in the toc are collapsed initially.\n *\n * Defaults to `false`. If {@link collapsibleGroups} is `false` this property should also be `false`. Otherwise, only the top level layers will appear in the toc.\n */\n initiallyCollapsed?: boolean;\n\n /**\n * Show the parent layers when a child layer is made visible.\n *\n * Defaults to `true`.\n */\n autoShowParents?: boolean;\n}\n\n/**\n * Props supported by the {@link Tools} component.\n */\nexport interface ToolsConfig {\n /**\n * Optional property to show the `hide all layers` entry.\n *\n * Defaults to `true`.\n */\n showHideAllLayers?: boolean;\n\n /**\n * Optional property to show the `collapse all groups` entry.\n *\n * Defaults to `true`. Only applicable if {@link TocProps.collapsibleGroups} is `true`.\n */\n showCollapseAllGroups?: boolean;\n}\n\nconst PADDING = 2;\n\n/**\n * Displays the layers of the configured map.\n */\nexport const Toc: FC<TocProps> = (props: TocProps) => {\n const intl = useIntl();\n const { containerProps } = useCommonComponentProps(\"toc\", props);\n const state = useMapModel(props);\n\n let content: ReactNode | null;\n switch (state.kind) {\n case \"loading\":\n content = null;\n break;\n case \"rejected\":\n content = <Text className=\"toc-error\">{intl.formatMessage({ id: \"error\" })}</Text>;\n break;\n case \"resolved\": {\n const map = state.map;\n content = <TocContent {...props} map={map} />;\n break;\n }\n }\n\n return (\n <Flex {...containerProps} direction=\"column\" gap={PADDING}>\n {content}\n </Flex>\n );\n};\n\n/** This component is rendered once we have a reference to the loaded map model. */\nfunction TocContent(props: TocProps & { map: MapModel }) {\n const {\n map,\n showTools = false,\n toolsConfig,\n showBasemapSwitcher = true,\n basemapSwitcherProps\n } = props;\n const intl = useIntl();\n const model = useTocModel(props);\n const basemapsHeadingId = useId();\n const basemapSwitcher = showBasemapSwitcher && (\n <Box className=\"toc-basemap-switcher\" mb={PADDING}>\n <TitledSection\n title={\n <SectionHeading id={basemapsHeadingId} size={\"sm\"} mb={PADDING}>\n {intl.formatMessage({ id: \"basemapsLabel\" })}\n </SectionHeading>\n }\n >\n <BasemapSwitcher\n map={map}\n aria-labelledby={basemapsHeadingId}\n {...basemapSwitcherProps}\n />\n </TitledSection>\n </Box>\n );\n\n const layerList = (\n <Box className=\"toc-operational-layers\">\n <TitledSection\n title={\n <SectionHeading size=\"sm\">\n <Flex>\n <Text>\n {intl.formatMessage({\n id: \"operationalLayerLabel\"\n })}\n </Text>\n <Spacer />\n {showTools && <Tools map={map} {...toolsConfig} />}\n </Flex>\n </SectionHeading>\n }\n >\n <TopLevelLayerList\n map={map}\n aria-label={intl.formatMessage({ id: \"operationalLayerLabel\" })}\n />\n </TitledSection>\n </Box>\n );\n\n return (\n <TocModelProvider value={model}>\n {basemapSwitcher}\n {layerList}\n </TocModelProvider>\n );\n}\n\nfunction useTocModel(props: TocProps): TocModel {\n const initialProps = useRef(props);\n const { model, options } = useMemo(() => {\n const options = reactive<TocWidgetOptions>(\n createOptions(\n initialProps.current.autoShowParents,\n initialProps.current.collapsibleGroups,\n initialProps.current.initiallyCollapsed\n )\n );\n\n // Indexed by layerId\n const items = reactiveMap<string, TocItem>();\n const model: TocModel = {\n get options() {\n return options.value;\n },\n getItem(layerId: string): TocItem | undefined {\n return items.get(layerId);\n },\n getItems(): TocItem[] {\n return Array.from(items.values());\n },\n registerItem(item: TocItem): void {\n if (items.has(item.layerId)) {\n throw new Error(`Item with layerId '${item.layerId}' already registered.`);\n }\n items.set(item.layerId, item);\n },\n unregisterItem(item: TocItem): void {\n if (items.get(item.layerId) !== item) {\n throw new Error(`Item with layerId '${item.layerId}' not registered.`);\n }\n items.delete(item.layerId);\n }\n };\n return { model, options };\n }, []);\n\n // Sync props to model\n useEffect(() => {\n options.value = createOptions(\n props.autoShowParents,\n props.collapsibleGroups,\n props.initiallyCollapsed\n );\n }, [options, props.autoShowParents, props.collapsibleGroups, props.initiallyCollapsed]);\n\n return model;\n}\n\nfunction createOptions(\n autoShowParents?: boolean | undefined,\n collapsibleGroups?: boolean | undefined,\n isCollapsed?: boolean | undefined\n): TocWidgetOptions {\n return {\n autoShowParents: autoShowParents ?? true,\n collapsibleGroups: collapsibleGroups ?? false,\n initiallyCollapsed: isCollapsed ?? false\n };\n}\n"],"names":["options","model"],"mappings":"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"}
package/ui/Tools.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { Box, Menu, IconButton, Portal } from '@chakra-ui/react';
2
+ import { Box, Menu, Portal, IconButton, Icon } from '@chakra-ui/react';
3
3
  import { useIntl } from '../_virtual/_virtual-pioneer-module_react-hooks.js';
4
- import { memo } from 'react';
4
+ import { memo, useId } from 'react';
5
5
  import { FiMoreVertical } from 'react-icons/fi';
6
6
  import { useTocModel } from '../model/TocModel.js';
7
7
  import { useReactiveSnapshot } from '@open-pioneer/reactivity';
8
+ import { Tooltip } from '@open-pioneer/chakra-snippets/tooltip';
8
9
 
9
10
  const Tools = memo(function Tools2(props) {
10
11
  const intl = useIntl();
@@ -20,19 +21,9 @@ const Tools = memo(function Tools2(props) {
20
21
  } = props;
21
22
  const showCollapseAllGroups = collapsibleGroups && showCollapseAllGroupsProp;
22
23
  const hasContent = showHideAllLayers || showCollapseAllGroups;
23
- return hasContent && /* @__PURE__ */ jsx(Box, { className: "toc-tools", children: /* @__PURE__ */ jsxs(Menu.Root, { lazyMount: true, positioning: { placement: "bottom-start" }, children: [
24
- /* @__PURE__ */ jsx(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
25
- IconButton,
26
- {
27
- className: "toc-tools-button",
28
- "aria-label": intl.formatMessage({ id: "toolsLabel" }),
29
- borderRadius: "full",
30
- variant: "ghost",
31
- padding: 0,
32
- size: "sm",
33
- children: /* @__PURE__ */ jsx(FiMoreVertical, { spacing: 0 })
34
- }
35
- ) }),
24
+ const triggerId = useId();
25
+ return hasContent && /* @__PURE__ */ jsx(Box, { className: "toc-tools", children: /* @__PURE__ */ jsxs(Menu.Root, { ids: { trigger: triggerId }, positioning: { placement: "bottom-start" }, children: [
26
+ /* @__PURE__ */ jsx(TriggerButton, { triggerId }),
36
27
  /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsxs(Menu.Content, { className: "toc-tools-menu", children: [
37
28
  showHideAllLayers && /* @__PURE__ */ jsx(
38
29
  Menu.Item,
@@ -63,6 +54,24 @@ const Tools = memo(function Tools2(props) {
63
54
  ] }) }) })
64
55
  ] }) });
65
56
  });
57
+ function TriggerButton(props) {
58
+ const { triggerId } = props;
59
+ const intl = useIntl();
60
+ const label = intl.formatMessage({ id: "toolsLabel" });
61
+ return /* @__PURE__ */ jsx(Tooltip, { ids: { trigger: triggerId }, content: label, children: /* @__PURE__ */ jsx(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
62
+ IconButton,
63
+ {
64
+ className: "toc-tools-button",
65
+ "aria-label": label,
66
+ borderRadius: "full",
67
+ focusRingOffset: "-2px",
68
+ variant: "ghost",
69
+ padding: 0,
70
+ size: "sm",
71
+ children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(FiMoreVertical, { spacing: 0 }) })
72
+ }
73
+ ) }) });
74
+ }
66
75
  function hideAllLayers(map) {
67
76
  const hide = (layer) => {
68
77
  layer.setVisible(false);
package/ui/Tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Tools.js","sources":["Tools.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box, IconButton, Menu, Portal } from \"@chakra-ui/react\";\nimport { AnyLayer, MapModel } from \"@open-pioneer/map\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, memo } from \"react\";\nimport { FiMoreVertical } from \"react-icons/fi\";\nimport { TocModel, useTocModel } from \"../model/TocModel\";\nimport { ToolsConfig } from \"./Toc\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\n\nexport interface ToolsProps extends ToolsConfig {\n map: MapModel;\n}\n\nexport const Tools: FC<ToolsProps> = memo(function Tools(props: ToolsProps) {\n const intl = useIntl();\n const tocModel = useTocModel();\n const collapsibleGroups = useReactiveSnapshot(\n () => tocModel.options.collapsibleGroups,\n [tocModel]\n );\n const {\n map,\n showHideAllLayers = true,\n showCollapseAllGroups: showCollapseAllGroupsProp = collapsibleGroups\n } = props;\n\n // Only respected if groups are collapsible\n const showCollapseAllGroups = collapsibleGroups && showCollapseAllGroupsProp;\n const hasContent = showHideAllLayers || showCollapseAllGroups;\n return (\n hasContent && (\n <Box className=\"toc-tools\">\n <Menu.Root lazyMount={true} positioning={{ placement: \"bottom-start\" }}>\n <Menu.Trigger asChild>\n <IconButton\n className=\"toc-tools-button\"\n aria-label={intl.formatMessage({ id: \"toolsLabel\" })}\n borderRadius=\"full\"\n variant=\"ghost\"\n padding={0}\n size=\"sm\"\n >\n <FiMoreVertical spacing={0} />\n </IconButton>\n </Menu.Trigger>\n <Portal>\n <Menu.Positioner>\n <Menu.Content className=\"toc-tools-menu\">\n {showHideAllLayers && (\n <Menu.Item\n aria-label={intl.formatMessage({\n id: \"tools.hideAllLayers\"\n })}\n onClick={() => {\n hideAllLayers(map);\n }}\n value=\"hideAllLayers\"\n >\n {intl.formatMessage({ id: \"tools.hideAllLayers\" })}\n </Menu.Item>\n )}\n {showCollapseAllGroups && (\n <Menu.Item\n aria-label={intl.formatMessage({\n id: \"tools.collapseAllGroups\"\n })}\n onClick={() => {\n collapseAllGroups(tocModel);\n }}\n value=\"collapseAllGroups\"\n >\n {intl.formatMessage({ id: \"tools.collapseAllGroups\" })}\n </Menu.Item>\n )}\n </Menu.Content>\n </Menu.Positioner>\n </Portal>\n </Menu.Root>\n </Box>\n )\n );\n});\n\nfunction hideAllLayers(map: MapModel | undefined) {\n const hide = (layer: AnyLayer) => {\n layer.setVisible(false);\n\n const children = layer.children?.getItems();\n if (children) {\n for (const child of children) {\n hide(child);\n }\n }\n };\n\n map?.layers.getOperationalLayers().forEach((layer) => {\n hide(layer);\n });\n}\n\nfunction collapseAllGroups(tocModel: TocModel) {\n tocModel.getItems().forEach((item) => item.setExpanded(false));\n}\n"],"names":["Tools"],"mappings":"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"}
1
+ {"version":3,"file":"Tools.js","sources":["Tools.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box, IconButton, Menu, Portal, Icon } from \"@chakra-ui/react\";\nimport { AnyLayer, MapModel } from \"@open-pioneer/map\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, memo, useId } from \"react\";\nimport { FiMoreVertical } from \"react-icons/fi\";\nimport { TocModel, useTocModel } from \"../model/TocModel\";\nimport { ToolsConfig } from \"./Toc\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport { Tooltip } from \"@open-pioneer/chakra-snippets/tooltip\";\n\nexport interface ToolsProps extends ToolsConfig {\n map: MapModel;\n}\n\nexport const Tools: FC<ToolsProps> = memo(function Tools(props: ToolsProps) {\n const intl = useIntl();\n const tocModel = useTocModel();\n const collapsibleGroups = useReactiveSnapshot(\n () => tocModel.options.collapsibleGroups,\n [tocModel]\n );\n const {\n map,\n showHideAllLayers = true,\n showCollapseAllGroups: showCollapseAllGroupsProp = collapsibleGroups\n } = props;\n\n // Only respected if groups are collapsible\n const showCollapseAllGroups = collapsibleGroups && showCollapseAllGroupsProp;\n const hasContent = showHideAllLayers || showCollapseAllGroups;\n\n const triggerId = useId(); // see https://chakra-ui.com/docs/components/tooltip#with-menutrigger\n\n return (\n hasContent && (\n <Box className=\"toc-tools\">\n <Menu.Root ids={{ trigger: triggerId }} positioning={{ placement: \"bottom-start\" }}>\n <TriggerButton triggerId={triggerId} />\n <Portal>\n <Menu.Positioner>\n <Menu.Content className=\"toc-tools-menu\">\n {showHideAllLayers && (\n <Menu.Item\n aria-label={intl.formatMessage({\n id: \"tools.hideAllLayers\"\n })}\n onClick={() => {\n hideAllLayers(map);\n }}\n value=\"hideAllLayers\"\n >\n {intl.formatMessage({ id: \"tools.hideAllLayers\" })}\n </Menu.Item>\n )}\n {showCollapseAllGroups && (\n <Menu.Item\n aria-label={intl.formatMessage({\n id: \"tools.collapseAllGroups\"\n })}\n onClick={() => {\n collapseAllGroups(tocModel);\n }}\n value=\"collapseAllGroups\"\n >\n {intl.formatMessage({ id: \"tools.collapseAllGroups\" })}\n </Menu.Item>\n )}\n </Menu.Content>\n </Menu.Positioner>\n </Portal>\n </Menu.Root>\n </Box>\n )\n );\n});\n\nfunction TriggerButton(props: { triggerId: string }) {\n const { triggerId } = props;\n const intl = useIntl();\n const label = intl.formatMessage({ id: \"toolsLabel\" });\n return (\n <Tooltip ids={{ trigger: triggerId }} content={label}>\n <Menu.Trigger asChild>\n <IconButton\n className=\"toc-tools-button\"\n aria-label={label}\n borderRadius=\"full\"\n focusRingOffset=\"-2px\"\n variant=\"ghost\"\n padding={0}\n size=\"sm\"\n >\n <Icon>\n <FiMoreVertical spacing={0} />\n </Icon>\n </IconButton>\n </Menu.Trigger>\n </Tooltip>\n );\n}\n\nfunction hideAllLayers(map: MapModel | undefined) {\n const hide = (layer: AnyLayer) => {\n layer.setVisible(false);\n\n const children = layer.children?.getItems();\n if (children) {\n for (const child of children) {\n hide(child);\n }\n }\n };\n\n map?.layers.getOperationalLayers().forEach((layer) => {\n hide(layer);\n });\n}\n\nfunction collapseAllGroups(tocModel: TocModel) {\n tocModel.getItems().forEach((item) => item.setExpanded(false));\n}\n"],"names":["Tools"],"mappings":"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"}