@open-pioneer/toc 0.8.0 → 0.9.0-dev.20250220091855

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.
@@ -8,6 +8,7 @@ import { FC } from "react";
8
8
  export interface TocProps extends CommonComponentProps, MapModelProps {
9
9
  /**
10
10
  * Defines whether the tool component is shown in the toc.
11
+ *
11
12
  * Defaults to `false`.
12
13
  */
13
14
  showTools?: boolean;
@@ -17,16 +18,32 @@ export interface TocProps extends CommonComponentProps, MapModelProps {
17
18
  toolsConfig?: ToolsConfig;
18
19
  /**
19
20
  * Defines whether the basemap switcher is shown in the toc.
21
+ *
20
22
  * Defaults to `true`.
21
23
  */
22
24
  showBasemapSwitcher?: boolean;
23
25
  /**
24
26
  * Properties for the embedded basemap switcher.
25
- * Property "mapId" is not applied.
27
+ *
28
+ * Property `mapId` is not applied (the basemap switcher uses the same map as the).
26
29
  */
27
30
  basemapSwitcherProps?: Omit<BasemapSwitcherProps, "mapId">;
31
+ /**
32
+ * If `true`, groups in the toc can be collapsed and expanded.
33
+ * This property should only be `true` if the map actually contains layer groups.
34
+ *
35
+ * Defaults to `false`.
36
+ */
37
+ collapsibleGroups?: boolean;
38
+ /**
39
+ * If `true` groups in the toc are collapsed initially.
40
+ *
41
+ * 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.
42
+ */
43
+ initiallyCollapsed?: boolean;
28
44
  /**
29
45
  * Show the parent layers when a child layer is made visible.
46
+ *
30
47
  * Defaults to `true`.
31
48
  */
32
49
  autoShowParents?: boolean;
@@ -37,9 +54,16 @@ export interface TocProps extends CommonComponentProps, MapModelProps {
37
54
  export interface ToolsConfig {
38
55
  /**
39
56
  * Optional property to show the `hide all layers` entry.
57
+ *
40
58
  * Defaults to `true`.
41
59
  */
42
60
  showHideAllLayers?: boolean;
61
+ /**
62
+ * Optional property to show the `collapse all groups` entry.
63
+ *
64
+ * Defaults to `true`. Only applicable if {@link TocProps.collapsibleGroups} is `true`.
65
+ */
66
+ showCollapseAllGroups?: boolean;
43
67
  }
44
68
  /**
45
69
  * Displays the layers of the configured map.
package/ui/Toc.js ADDED
@@ -0,0 +1,137 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { reactive, reactiveMap } from '@conterra/reactivity-core';
3
+ import { BasemapSwitcher } from '@open-pioneer/basemap-switcher';
4
+ import { Text, Flex, Box, Spacer } from '@open-pioneer/chakra-integration';
5
+ import { useMapModel } from '@open-pioneer/map';
6
+ import { useCommonComponentProps, TitledSection, SectionHeading } from '@open-pioneer/react-utils';
7
+ import { useIntl } from '../_virtual/_virtual-pioneer-module_react-hooks.js';
8
+ import { useId, useRef, useMemo, useEffect } from 'react';
9
+ import { TocModelProvider } from '../model/TocModel.js';
10
+ import { TopLevelLayerList } from './LayerList/LayerList.js';
11
+ import { Tools } from './Tools.js';
12
+
13
+ const PADDING = 2;
14
+ const Toc = (props) => {
15
+ const intl = useIntl();
16
+ const { containerProps } = useCommonComponentProps("toc", props);
17
+ const state = useMapModel(props);
18
+ let content;
19
+ switch (state.kind) {
20
+ case "loading":
21
+ content = null;
22
+ break;
23
+ case "rejected":
24
+ content = /* @__PURE__ */ jsx(Text, { className: "toc-error", children: intl.formatMessage({ id: "error" }) });
25
+ break;
26
+ case "resolved": {
27
+ const map = state.map;
28
+ content = /* @__PURE__ */ jsx(TocContent, { ...props, map });
29
+ break;
30
+ }
31
+ }
32
+ return /* @__PURE__ */ jsx(Flex, { ...containerProps, direction: "column", gap: PADDING, children: content });
33
+ };
34
+ function TocContent(props) {
35
+ const {
36
+ map,
37
+ showTools = false,
38
+ toolsConfig,
39
+ showBasemapSwitcher = true,
40
+ basemapSwitcherProps
41
+ } = props;
42
+ const intl = useIntl();
43
+ const model = useTocModel(props);
44
+ const basemapsHeadingId = useId();
45
+ const basemapSwitcher = showBasemapSwitcher && /* @__PURE__ */ jsx(Box, { className: "toc-basemap-switcher", children: /* @__PURE__ */ jsx(
46
+ TitledSection,
47
+ {
48
+ title: /* @__PURE__ */ jsx(SectionHeading, { id: basemapsHeadingId, size: "sm", mb: PADDING, children: intl.formatMessage({ id: "basemapsLabel" }) }),
49
+ children: /* @__PURE__ */ jsx(
50
+ BasemapSwitcher,
51
+ {
52
+ map,
53
+ "aria-labelledby": basemapsHeadingId,
54
+ ...basemapSwitcherProps
55
+ }
56
+ )
57
+ }
58
+ ) });
59
+ const layerList = /* @__PURE__ */ jsx(Box, { className: "toc-operational-layers", children: /* @__PURE__ */ jsx(
60
+ TitledSection,
61
+ {
62
+ title: /* @__PURE__ */ jsx(SectionHeading, { size: "sm", mb: 2, children: /* @__PURE__ */ jsxs(Flex, { children: [
63
+ /* @__PURE__ */ jsx(Text, { my: 3, children: intl.formatMessage({
64
+ id: "operationalLayerLabel"
65
+ }) }),
66
+ /* @__PURE__ */ jsx(Spacer, {}),
67
+ showTools && /* @__PURE__ */ jsx(Tools, { map, ...toolsConfig })
68
+ ] }) }),
69
+ children: /* @__PURE__ */ jsx(
70
+ TopLevelLayerList,
71
+ {
72
+ map,
73
+ "aria-label": intl.formatMessage({ id: "operationalLayerLabel" })
74
+ }
75
+ )
76
+ }
77
+ ) });
78
+ return /* @__PURE__ */ jsxs(TocModelProvider, { value: model, children: [
79
+ basemapSwitcher,
80
+ layerList
81
+ ] });
82
+ }
83
+ function useTocModel(props) {
84
+ const initialProps = useRef(props);
85
+ const { model, options } = useMemo(() => {
86
+ const options2 = reactive(
87
+ createOptions(
88
+ initialProps.current.autoShowParents,
89
+ initialProps.current.collapsibleGroups,
90
+ initialProps.current.initiallyCollapsed
91
+ )
92
+ );
93
+ const items = reactiveMap();
94
+ const model2 = {
95
+ get options() {
96
+ return options2.value;
97
+ },
98
+ getItem(layerId) {
99
+ return items.get(layerId);
100
+ },
101
+ getItems() {
102
+ return Array.from(items.values());
103
+ },
104
+ registerItem(item) {
105
+ if (items.has(item.layerId)) {
106
+ throw new Error(`Item with layerId '${item.layerId}' already registered.`);
107
+ }
108
+ items.set(item.layerId, item);
109
+ },
110
+ unregisterItem(item) {
111
+ if (items.get(item.layerId) !== item) {
112
+ throw new Error(`Item with layerId '${item.layerId}' not registered.`);
113
+ }
114
+ items.delete(item.layerId);
115
+ }
116
+ };
117
+ return { model: model2, options: options2 };
118
+ }, []);
119
+ useEffect(() => {
120
+ options.value = createOptions(
121
+ props.autoShowParents,
122
+ props.collapsibleGroups,
123
+ props.initiallyCollapsed
124
+ );
125
+ }, [options, props.autoShowParents, props.collapsibleGroups, props.initiallyCollapsed]);
126
+ return model;
127
+ }
128
+ function createOptions(autoShowParents, collapsibleGroups, isCollapsed) {
129
+ return {
130
+ autoShowParents: autoShowParents ?? true,
131
+ collapsibleGroups: collapsibleGroups ?? false,
132
+ initiallyCollapsed: isCollapsed ?? false
133
+ };
134
+ }
135
+
136
+ export { Toc };
137
+ //# sourceMappingURL=Toc.js.map
package/ui/Toc.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toc.js","sources":["Toc.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 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 \"@open-pioneer/chakra-integration\";\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, 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).\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: JSX.Element | 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,6 +1,7 @@
1
1
  import { MapModel } from "@open-pioneer/map";
2
2
  import { FC } from "react";
3
3
  import { ToolsConfig } from "./Toc";
4
- export declare const Tools: FC<{
4
+ export interface ToolsProps extends ToolsConfig {
5
5
  map: MapModel;
6
- } & ToolsConfig>;
6
+ }
7
+ export declare const Tools: FC<ToolsProps>;
package/ui/Tools.js ADDED
@@ -0,0 +1,82 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { Box, Menu, MenuButton, Button, Portal, MenuList, MenuItem } from '@open-pioneer/chakra-integration';
3
+ import { useIntl } from '../_virtual/_virtual-pioneer-module_react-hooks.js';
4
+ import { memo } from 'react';
5
+ import { FiMoreVertical } from 'react-icons/fi';
6
+ import { useTocModel } from '../model/TocModel.js';
7
+ import { useReactiveSnapshot } from '@open-pioneer/reactivity';
8
+
9
+ const Tools = memo(function Tools2(props) {
10
+ const intl = useIntl();
11
+ const tocModel = useTocModel();
12
+ const collapsibleGroups = useReactiveSnapshot(
13
+ () => tocModel.options.collapsibleGroups,
14
+ [tocModel]
15
+ );
16
+ const {
17
+ map,
18
+ showHideAllLayers = true,
19
+ showCollapseAllGroups: showCollapseAllGroupsProp = collapsibleGroups
20
+ } = props;
21
+ const showCollapseAllGroups = collapsibleGroups && showCollapseAllGroupsProp;
22
+ const hasContent = showHideAllLayers || showCollapseAllGroups;
23
+ return hasContent && /* @__PURE__ */ jsx(Box, { className: "toc-tools", children: /* @__PURE__ */ jsxs(Menu, { placement: "bottom-start", children: [
24
+ /* @__PURE__ */ jsx(
25
+ MenuButton,
26
+ {
27
+ as: Button,
28
+ className: "toc-tools-button",
29
+ "aria-label": intl.formatMessage({ id: "toolsLabel" }),
30
+ borderRadius: "full",
31
+ iconSpacing: 0,
32
+ padding: 3,
33
+ variant: "ghost",
34
+ leftIcon: /* @__PURE__ */ jsx(FiMoreVertical, {})
35
+ }
36
+ ),
37
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(MenuList, { className: "tools-menu", children: [
38
+ showHideAllLayers && /* @__PURE__ */ jsx(
39
+ MenuItem,
40
+ {
41
+ "aria-label": intl.formatMessage({ id: "tools.hideAllLayers" }),
42
+ onClick: () => {
43
+ hideAllLayers(map);
44
+ },
45
+ children: intl.formatMessage({ id: "tools.hideAllLayers" })
46
+ }
47
+ ),
48
+ showCollapseAllGroups && /* @__PURE__ */ jsx(
49
+ MenuItem,
50
+ {
51
+ "aria-label": intl.formatMessage({
52
+ id: "tools.collapseAllGroups"
53
+ }),
54
+ onClick: () => {
55
+ collapseAllGroups(tocModel);
56
+ },
57
+ children: intl.formatMessage({ id: "tools.collapseAllGroups" })
58
+ }
59
+ )
60
+ ] }) })
61
+ ] }) });
62
+ });
63
+ function hideAllLayers(map) {
64
+ const hide = (layer) => {
65
+ layer.setVisible(false);
66
+ const children = layer.children?.getItems();
67
+ if (children) {
68
+ for (const child of children) {
69
+ hide(child);
70
+ }
71
+ }
72
+ };
73
+ map?.layers.getOperationalLayers().forEach((layer) => {
74
+ hide(layer);
75
+ });
76
+ }
77
+ function collapseAllGroups(tocModel) {
78
+ tocModel.getItems().forEach((item) => item.setExpanded(false));
79
+ }
80
+
81
+ export { Tools };
82
+ //# sourceMappingURL=Tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tools.js","sources":["Tools.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport {\n Box,\n Button,\n Menu,\n MenuButton,\n MenuItem,\n MenuList,\n Portal\n} from \"@open-pioneer/chakra-integration\";\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 placement=\"bottom-start\">\n <MenuButton\n as={Button}\n className=\"toc-tools-button\"\n aria-label={intl.formatMessage({ id: \"toolsLabel\" })}\n borderRadius=\"full\"\n iconSpacing={0}\n padding={3}\n variant=\"ghost\"\n leftIcon={<FiMoreVertical />}\n />\n <Portal>\n <MenuList className=\"tools-menu\">\n {showHideAllLayers && (\n <MenuItem\n aria-label={intl.formatMessage({ id: \"tools.hideAllLayers\" })}\n onClick={() => {\n hideAllLayers(map);\n }}\n >\n {intl.formatMessage({ id: \"tools.hideAllLayers\" })}\n </MenuItem>\n )}\n {showCollapseAllGroups && (\n <MenuItem\n aria-label={intl.formatMessage({\n id: \"tools.collapseAllGroups\"\n })}\n onClick={() => {\n collapseAllGroups(tocModel);\n }}\n >\n {intl.formatMessage({ id: \"tools.collapseAllGroups\" })}\n </MenuItem>\n )}\n </MenuList>\n </Portal>\n </Menu>\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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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Strips special characters from the given string, making it suitable
3
+ * for use in CSS classes.
4
+ */
5
+ export declare function slug(id: string): string;
package/utils/slug.js ADDED
@@ -0,0 +1,6 @@
1
+ function slug(id) {
2
+ return id.toLowerCase().replace(/[^a-z0-9 -]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
3
+ }
4
+
5
+ export { slug };
6
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.js","sources":["slug.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Strips special characters from the given string, making it suitable\n * for use in CSS classes.\n */\nexport function slug(id: string): string {\n return id\n .toLowerCase()\n .replace(/[^a-z0-9 -]/g, \"\")\n .replace(/\\s+/g, \"-\")\n .replace(/-+/g, \"-\");\n}\n"],"names":[],"mappings":"AAOO,SAAS,KAAK,EAAoB,EAAA;AACrC,EAAA,OAAO,EACF,CAAA,WAAA,EACA,CAAA,OAAA,CAAQ,cAAgB,EAAA,EAAE,CAC1B,CAAA,OAAA,CAAQ,MAAQ,EAAA,GAAG,CACnB,CAAA,OAAA,CAAQ,OAAO,GAAG,CAAA,CAAA;AAC3B;;;;"}
package/Context.d.ts DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * Toc context to pass global widget options around (to avoid props drilling).
3
- *
4
- * @internal
5
- */
6
- export interface TocWidgetOptions {
7
- /** True: When showing a child, show all parents as well (`setVisible(true)`). */
8
- autoShowParents: boolean;
9
- }
10
- export declare const TocWidgetOptionsProvider: React.Provider<TocWidgetOptions>;
11
- export declare function useTocWidgetOptions(): TocWidgetOptions;
package/Context.js DELETED
@@ -1,14 +0,0 @@
1
- import { createContext, useContext } from 'react';
2
-
3
- const TocWidgetOptionsContext = createContext(void 0);
4
- const TocWidgetOptionsProvider = TocWidgetOptionsContext.Provider;
5
- function useTocWidgetOptions() {
6
- const context = useContext(TocWidgetOptionsContext);
7
- if (!context) {
8
- throw new Error("useTocWidgetOptions must be used within a TocWidgetOptionsProvider");
9
- }
10
- return context;
11
- }
12
-
13
- export { TocWidgetOptionsProvider, useTocWidgetOptions };
14
- //# sourceMappingURL=Context.js.map
package/Context.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"Context.js","sources":["Context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { createContext, useContext } from \"react\";\n\n/**\n * Toc context to pass global widget options around (to avoid props drilling).\n *\n * @internal\n */\nexport interface TocWidgetOptions {\n /** True: When showing a child, show all parents as well (`setVisible(true)`). */\n autoShowParents: boolean;\n}\n\nconst TocWidgetOptionsContext = createContext<TocWidgetOptions | undefined>(undefined);\n\nexport const TocWidgetOptionsProvider =\n TocWidgetOptionsContext.Provider as React.Provider<TocWidgetOptions>;\n\nexport function useTocWidgetOptions(): TocWidgetOptions {\n const context = useContext(TocWidgetOptionsContext);\n if (!context) {\n throw new Error(\"useTocWidgetOptions must be used within a TocWidgetOptionsProvider\");\n }\n return context;\n}\n"],"names":[],"mappings":";;AAcA,MAAM,uBAAA,GAA0B,cAA4C,KAAS,CAAA,CAAA,CAAA;AAE9E,MAAM,2BACT,uBAAwB,CAAA,SAAA;AAErB,SAAS,mBAAwC,GAAA;AACpD,EAAM,MAAA,OAAA,GAAU,WAAW,uBAAuB,CAAA,CAAA;AAClD,EAAA,IAAI,CAAC,OAAS,EAAA;AACV,IAAM,MAAA,IAAI,MAAM,oEAAoE,CAAA,CAAA;AAAA,GACxF;AACA,EAAO,OAAA,OAAA,CAAA;AACX;;;;"}
package/LayerList.d.ts DELETED
@@ -1,10 +0,0 @@
1
- import { MapModel } from "@open-pioneer/map";
2
- /**
3
- * Lists the (top level) operational layers in the map.
4
- *
5
- * Layer Groups are skipped in the current implementation.
6
- */
7
- export declare function LayerList(props: {
8
- map: MapModel;
9
- "aria-label"?: string;
10
- }): JSX.Element;
package/LayerList.js DELETED
@@ -1,168 +0,0 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { Text, List, Box, Flex, Checkbox, Tooltip, Spacer, Popover, PopoverTrigger, Button, Portal, PopoverContent, PopoverArrow, PopoverCloseButton, PopoverHeader, PopoverBody } from '@open-pioneer/chakra-integration';
3
- import { isSublayer } from '@open-pioneer/map';
4
- import { useReactiveSnapshot } from '@open-pioneer/reactivity';
5
- import classNames from 'classnames';
6
- import { useIntl } from './_virtual/_virtual-pioneer-module_react-hooks.js';
7
- import { FiAlertTriangle, FiMoreVertical } from 'react-icons/fi';
8
- import { useTocWidgetOptions } from './Context.js';
9
-
10
- function LayerList(props) {
11
- const { map, "aria-label": ariaLabel } = props;
12
- const intl = useIntl();
13
- const layers = useLayers(map);
14
- if (!layers.length) {
15
- return /* @__PURE__ */ jsx(Text, { className: "toc-missing-layers", "aria-label": ariaLabel, children: intl.formatMessage({ id: "missingLayers" }) });
16
- }
17
- return createList(layers, {
18
- "aria-label": ariaLabel
19
- });
20
- }
21
- function createList(layers, listProps) {
22
- const items = layers.map((layer) => /* @__PURE__ */ jsx(LayerItem, { layer }, layer.id));
23
- return /* @__PURE__ */ jsx(
24
- List,
25
- {
26
- as: "ul",
27
- className: "toc-layer-list",
28
- listStyleType: "none",
29
- role: "group",
30
- ...listProps,
31
- children: items
32
- }
33
- );
34
- }
35
- function LayerItem(props) {
36
- const { layer } = props;
37
- const intl = useIntl();
38
- const options = useTocWidgetOptions();
39
- const { title, description, isVisible } = useReactiveSnapshot(() => {
40
- return {
41
- title: layer.title,
42
- description: layer.description,
43
- isVisible: layer.visible
44
- };
45
- }, [layer]);
46
- const childLayers = useChildLayers(layer);
47
- const isAvailable = useLoadState(layer) !== "error";
48
- const notAvailableLabel = intl.formatMessage({ id: "layerNotAvailable" });
49
- let nestedChildren;
50
- if (childLayers?.length) {
51
- nestedChildren = createList(childLayers, {
52
- ml: 4,
53
- "aria-label": intl.formatMessage({ id: "childgroupLabel" }, { title })
54
- });
55
- }
56
- return /* @__PURE__ */ jsxs(Box, { as: "li", className: classNames("toc-layer-item", `layer-${slug(layer.id)}`), children: [
57
- /* @__PURE__ */ jsxs(
58
- Flex,
59
- {
60
- className: "toc-layer-item-content",
61
- width: "100%",
62
- flexDirection: "row",
63
- align: "center",
64
- justifyContent: "space-between",
65
- gap: 2,
66
- minHeight: 10,
67
- children: [
68
- /* @__PURE__ */ jsx(
69
- Checkbox,
70
- {
71
- "aria-label": title + (!isAvailable ? " " + notAvailableLabel : ""),
72
- isChecked: isVisible,
73
- isDisabled: !isAvailable,
74
- onChange: (event) => updateLayerVisibility(layer, event.target.checked, options.autoShowParents),
75
- children: title
76
- }
77
- ),
78
- !isAvailable && /* @__PURE__ */ jsx(
79
- Tooltip,
80
- {
81
- className: "toc-layer-item-content-tooltip",
82
- label: notAvailableLabel,
83
- placement: "right",
84
- openDelay: 500,
85
- children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
86
- FiAlertTriangle,
87
- {
88
- className: "toc-layer-item-content-icon",
89
- color: "red",
90
- "aria-label": notAvailableLabel
91
- }
92
- ) })
93
- }
94
- ),
95
- /* @__PURE__ */ jsx(Spacer, {}),
96
- description && /* @__PURE__ */ jsx(
97
- LayerItemDescriptor,
98
- {
99
- layer,
100
- title,
101
- description,
102
- intl
103
- }
104
- )
105
- ]
106
- }
107
- ),
108
- nestedChildren
109
- ] });
110
- }
111
- function updateLayerVisibility(layer, visible, autoShowParents) {
112
- layer.setVisible(visible);
113
- if (visible && autoShowParents && layer.parent) {
114
- updateLayerVisibility(layer.parent, true, true);
115
- }
116
- }
117
- function LayerItemDescriptor(props) {
118
- const { layer, title, description, intl } = props;
119
- const buttonLabel = intl.formatMessage({ id: "descriptionLabel" });
120
- const isAvailable = useLoadState(layer) !== "error";
121
- return /* @__PURE__ */ jsxs(Popover, { placement: "bottom-start", children: [
122
- /* @__PURE__ */ jsx(PopoverTrigger, { children: /* @__PURE__ */ jsx(
123
- Button,
124
- {
125
- isDisabled: !isAvailable,
126
- className: "toc-layer-item-details-button",
127
- "aria-label": buttonLabel,
128
- borderRadius: "full",
129
- iconSpacing: 0,
130
- padding: 0,
131
- variant: "ghost",
132
- leftIcon: /* @__PURE__ */ jsx(FiMoreVertical, {})
133
- }
134
- ) }),
135
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(PopoverContent, { className: "toc-layer-item-details", overflowY: "auto", maxHeight: "400", children: [
136
- /* @__PURE__ */ jsx(PopoverArrow, {}),
137
- /* @__PURE__ */ jsx(PopoverCloseButton, { mt: 1 }),
138
- /* @__PURE__ */ jsx(PopoverHeader, { children: title }),
139
- /* @__PURE__ */ jsx(PopoverBody, { children: description })
140
- ] }) })
141
- ] });
142
- }
143
- function useLayers(map) {
144
- return useReactiveSnapshot(() => {
145
- const layers = map.layers.getOperationalLayers({ sortByDisplayOrder: true }) ?? [];
146
- layers.reverse();
147
- return layers;
148
- }, [map]);
149
- }
150
- function useChildLayers(layer) {
151
- return useReactiveSnapshot(() => {
152
- const children = layer.children?.getItems({ sortByDisplayOrder: true });
153
- children?.reverse();
154
- return children;
155
- }, [layer]);
156
- }
157
- function useLoadState(layer) {
158
- return useReactiveSnapshot(() => {
159
- const target = isSublayer(layer) ? layer.parentLayer : layer;
160
- return target.loadState;
161
- }, [layer]);
162
- }
163
- function slug(id) {
164
- return id.toLowerCase().replace(/[^a-z0-9 -]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
165
- }
166
-
167
- export { LayerList };
168
- //# sourceMappingURL=LayerList.js.map
package/LayerList.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"LayerList.js","sources":["LayerList.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport {\n Box,\n Button,\n Checkbox,\n Flex,\n List,\n ListProps,\n Popover,\n PopoverArrow,\n PopoverBody,\n PopoverCloseButton,\n PopoverContent,\n PopoverHeader,\n PopoverTrigger,\n Portal,\n Spacer,\n Text,\n Tooltip\n} from \"@open-pioneer/chakra-integration\";\nimport { AnyLayer, isSublayer, Layer, MapModel } 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 { FiAlertTriangle, FiMoreVertical } from \"react-icons/fi\";\nimport { useTocWidgetOptions } from \"./Context\";\n\n/**\n * Lists the (top level) operational layers in the map.\n *\n * Layer Groups are skipped in the current implementation.\n */\nexport function LayerList(props: { map: MapModel; \"aria-label\"?: string }): JSX.Element {\n const { map, \"aria-label\": ariaLabel } = props;\n const intl = useIntl();\n const layers = useLayers(map);\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 createList(layers, {\n \"aria-label\": ariaLabel\n });\n}\n\nfunction createList(layers: AnyLayer[], listProps: ListProps) {\n const items = layers.map((layer) => <LayerItem key={layer.id} layer={layer} />);\n return (\n <List\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>\n );\n}\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 */\nfunction LayerItem(props: { layer: AnyLayer }): JSX.Element {\n const { layer } = props;\n const intl = useIntl();\n const options = useTocWidgetOptions();\n const { title, description, isVisible } = useReactiveSnapshot(() => {\n return {\n title: layer.title,\n description: layer.description,\n isVisible: layer.visible\n };\n }, [layer]);\n const childLayers = useChildLayers(layer);\n const isAvailable = useLoadState(layer) !== \"error\";\n const notAvailableLabel = intl.formatMessage({ id: \"layerNotAvailable\" });\n\n let nestedChildren;\n if (childLayers?.length) {\n nestedChildren = createList(childLayers, {\n ml: 4,\n \"aria-label\": intl.formatMessage({ id: \"childgroupLabel\" }, { title: title })\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 <Checkbox\n // Keyboard navigation jumps only to Checkboxes and uses the texts inside this DOM node. The aria-labels of Tooltip and Icon is ignored by screenreader because they are no child element of the checkbox. To consider the notAvailableLabel, an aria-label at the checkbox is necessary.\n aria-label={title + (!isAvailable ? \" \" + notAvailableLabel : \"\")}\n isChecked={isVisible}\n isDisabled={!isAvailable}\n onChange={(event) =>\n updateLayerVisibility(layer, event.target.checked, options.autoShowParents)\n }\n >\n {title}\n </Checkbox>\n {!isAvailable && (\n <Tooltip\n className=\"toc-layer-item-content-tooltip\"\n label={notAvailableLabel}\n placement=\"right\"\n openDelay={500}\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></Spacer>\n {description && (\n <LayerItemDescriptor\n layer={layer}\n title={title}\n description={description}\n intl={intl}\n />\n )}\n </Flex>\n {nestedChildren}\n </Box>\n );\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\nfunction LayerItemDescriptor(props: {\n layer: AnyLayer;\n title: string;\n description: string;\n intl: PackageIntl;\n}): JSX.Element {\n const { layer, title, description, intl } = props;\n const buttonLabel = intl.formatMessage({ id: \"descriptionLabel\" });\n const isAvailable = useLoadState(layer) !== \"error\";\n\n return (\n <Popover placement=\"bottom-start\">\n <PopoverTrigger>\n <Button\n isDisabled={!isAvailable}\n className=\"toc-layer-item-details-button\"\n aria-label={buttonLabel}\n borderRadius=\"full\"\n iconSpacing={0}\n padding={0}\n variant=\"ghost\"\n leftIcon={<FiMoreVertical />}\n />\n </PopoverTrigger>\n <Portal>\n <PopoverContent className=\"toc-layer-item-details\" overflowY=\"auto\" maxHeight=\"400\">\n <PopoverArrow />\n <PopoverCloseButton mt={1} />\n <PopoverHeader>{title}</PopoverHeader>\n <PopoverBody>{description}</PopoverBody>\n </PopoverContent>\n </Portal>\n </Popover>\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.getOperationalLayers({ 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 contained in a group layer) of a layer.\n * Layers are returned in render order (topmost sublayer first).\n */\nfunction useChildLayers(layer: AnyLayer): AnyLayer[] | undefined {\n return useReactiveSnapshot(() => {\n const children = layer.children?.getItems({ sortByDisplayOrder: true });\n children?.reverse(); // render topmost layer first\n return children;\n }, [layer]);\n}\n\n/** Returns the layers current state. */\nfunction useLoadState(layer: AnyLayer): string {\n return useReactiveSnapshot(() => {\n // for sublayers, use the state of the parent\n const target = isSublayer(layer) ? layer.parentLayer : layer;\n return target.loadState;\n }, [layer]);\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":";;;;;;;;;AAkCO,SAAS,UAAU,KAA8D,EAAA;AACpF,EAAA,MAAM,EAAE,GAAA,EAAK,YAAc,EAAA,SAAA,EAAc,GAAA,KAAA,CAAA;AACzC,EAAA,MAAM,OAAO,OAAQ,EAAA,CAAA;AACrB,EAAM,MAAA,MAAA,GAAS,UAAU,GAAG,CAAA,CAAA;AAC5B,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,CAAA;AAAA,GAER;AAEA,EAAA,OAAO,WAAW,MAAQ,EAAA;AAAA,IACtB,YAAc,EAAA,SAAA;AAAA,GACjB,CAAA,CAAA;AACL,CAAA;AAEA,SAAS,UAAA,CAAW,QAAoB,SAAsB,EAAA;AAC1D,EAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,GAAA,CAAI,CAAC,KAAA,yBAAW,SAAyB,EAAA,EAAA,KAAA,EAAA,EAAV,KAAM,CAAA,EAAkB,CAAE,CAAA,CAAA;AAC9E,EACI,uBAAA,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;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,KAAA;AAAA,KAAA;AAAA,GACL,CAAA;AAER,CAAA;AAOA,SAAS,UAAU,KAAyC,EAAA;AACxD,EAAM,MAAA,EAAE,OAAU,GAAA,KAAA,CAAA;AAClB,EAAA,MAAM,OAAO,OAAQ,EAAA,CAAA;AACrB,EAAA,MAAM,UAAU,mBAAoB,EAAA,CAAA;AACpC,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,OAAA;AAAA,KACrB,CAAA;AAAA,GACJ,EAAG,CAAC,KAAK,CAAC,CAAA,CAAA;AACV,EAAM,MAAA,WAAA,GAAc,eAAe,KAAK,CAAA,CAAA;AACxC,EAAM,MAAA,WAAA,GAAc,YAAa,CAAA,KAAK,CAAM,KAAA,OAAA,CAAA;AAC5C,EAAA,MAAM,oBAAoB,IAAK,CAAA,aAAA,CAAc,EAAE,EAAA,EAAI,qBAAqB,CAAA,CAAA;AAExE,EAAI,IAAA,cAAA,CAAA;AACJ,EAAA,IAAI,aAAa,MAAQ,EAAA;AACrB,IAAA,cAAA,GAAiB,WAAW,WAAa,EAAA;AAAA,MACrC,EAAI,EAAA,CAAA;AAAA,MACJ,YAAA,EAAc,KAAK,aAAc,CAAA,EAAE,IAAI,iBAAkB,EAAA,EAAG,EAAE,KAAA,EAAc,CAAA;AAAA,KAC/E,CAAA,CAAA;AAAA,GACL;AACA,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,QAEX,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAEG,YAAY,EAAA,KAAA,IAAS,CAAC,WAAA,GAAc,MAAM,iBAAoB,GAAA,EAAA,CAAA;AAAA,cAC9D,SAAW,EAAA,SAAA;AAAA,cACX,YAAY,CAAC,WAAA;AAAA,cACb,QAAA,EAAU,CAAC,KACP,KAAA,qBAAA,CAAsB,OAAO,KAAM,CAAA,MAAA,CAAO,OAAS,EAAA,OAAA,CAAQ,eAAe,CAAA;AAAA,cAG7E,QAAA,EAAA,KAAA;AAAA,aAAA;AAAA,WACL;AAAA,UACC,CAAC,WACE,oBAAA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACG,SAAU,EAAA,gCAAA;AAAA,cACV,KAAO,EAAA,iBAAA;AAAA,cACP,SAAU,EAAA,OAAA;AAAA,cACV,SAAW,EAAA,GAAA;AAAA,cAEX,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,iBAAA;AAAA,iBAAA;AAAA,eAEpB,EAAA,CAAA;AAAA,aAAA;AAAA,WACJ;AAAA,8BAEH,MAAO,EAAA,EAAA,CAAA;AAAA,UACP,WACG,oBAAA,GAAA;AAAA,YAAC,mBAAA;AAAA,YAAA;AAAA,cACG,KAAA;AAAA,cACA,KAAA;AAAA,cACA,WAAA;AAAA,cACA,IAAA;AAAA,aAAA;AAAA,WACJ;AAAA,SAAA;AAAA,OAAA;AAAA,KAER;AAAA,IACC,cAAA;AAAA,GACL,EAAA,CAAA,CAAA;AAER,CAAA;AAEA,SAAS,qBAAA,CAAsB,KAAiB,EAAA,OAAA,EAAkB,eAA0B,EAAA;AACxF,EAAA,KAAA,CAAM,WAAW,OAAO,CAAA,CAAA;AACxB,EAAI,IAAA,OAAA,IAAW,eAAmB,IAAA,KAAA,CAAM,MAAQ,EAAA;AAC5C,IAAsB,qBAAA,CAAA,KAAA,CAAM,MAAQ,EAAA,IAAA,EAAM,IAAI,CAAA,CAAA;AAAA,GAClD;AACJ,CAAA;AAEA,SAAS,oBAAoB,KAKb,EAAA;AACZ,EAAA,MAAM,EAAE,KAAA,EAAO,KAAO,EAAA,WAAA,EAAa,MAAS,GAAA,KAAA,CAAA;AAC5C,EAAA,MAAM,cAAc,IAAK,CAAA,aAAA,CAAc,EAAE,EAAA,EAAI,oBAAoB,CAAA,CAAA;AACjE,EAAM,MAAA,WAAA,GAAc,YAAa,CAAA,KAAK,CAAM,KAAA,OAAA,CAAA;AAE5C,EACI,uBAAA,IAAA,CAAC,OAAQ,EAAA,EAAA,SAAA,EAAU,cACf,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cACG,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACG,YAAY,CAAC,WAAA;AAAA,QACb,SAAU,EAAA,+BAAA;AAAA,QACV,YAAY,EAAA,WAAA;AAAA,QACZ,YAAa,EAAA,MAAA;AAAA,QACb,WAAa,EAAA,CAAA;AAAA,QACb,OAAS,EAAA,CAAA;AAAA,QACT,OAAQ,EAAA,OAAA;AAAA,QACR,QAAA,sBAAW,cAAe,EAAA,EAAA,CAAA;AAAA,OAAA;AAAA,KAElC,EAAA,CAAA;AAAA,oBACA,GAAA,CAAC,UACG,QAAC,kBAAA,IAAA,CAAA,cAAA,EAAA,EAAe,WAAU,wBAAyB,EAAA,SAAA,EAAU,MAAO,EAAA,SAAA,EAAU,KAC1E,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,YAAa,EAAA,EAAA,CAAA;AAAA,sBACd,GAAA,CAAC,kBAAmB,EAAA,EAAA,EAAA,EAAI,CAAG,EAAA,CAAA;AAAA,sBAC3B,GAAA,CAAC,iBAAe,QAAM,EAAA,KAAA,EAAA,CAAA;AAAA,sBACtB,GAAA,CAAC,eAAa,QAAY,EAAA,WAAA,EAAA,CAAA;AAAA,KAAA,EAC9B,CACJ,EAAA,CAAA;AAAA,GACJ,EAAA,CAAA,CAAA;AAER,CAAA;AAGA,SAAS,UAAU,GAAwB,EAAA;AACvC,EAAA,OAAO,oBAAoB,MAAM;AAC7B,IAAM,MAAA,MAAA,GAAS,IAAI,MAAO,CAAA,oBAAA,CAAqB,EAAE,kBAAoB,EAAA,IAAA,EAAM,CAAA,IAAK,EAAC,CAAA;AACjF,IAAA,MAAA,CAAO,OAAQ,EAAA,CAAA;AACf,IAAO,OAAA,MAAA,CAAA;AAAA,GACX,EAAG,CAAC,GAAG,CAAC,CAAA,CAAA;AACZ,CAAA;AAMA,SAAS,eAAe,KAAyC,EAAA;AAC7D,EAAA,OAAO,oBAAoB,MAAM;AAC7B,IAAA,MAAM,WAAW,KAAM,CAAA,QAAA,EAAU,SAAS,EAAE,kBAAA,EAAoB,MAAM,CAAA,CAAA;AACtE,IAAA,QAAA,EAAU,OAAQ,EAAA,CAAA;AAClB,IAAO,OAAA,QAAA,CAAA;AAAA,GACX,EAAG,CAAC,KAAK,CAAC,CAAA,CAAA;AACd,CAAA;AAGA,SAAS,aAAa,KAAyB,EAAA;AAC3C,EAAA,OAAO,oBAAoB,MAAM;AAE7B,IAAA,MAAM,MAAS,GAAA,UAAA,CAAW,KAAK,CAAA,GAAI,MAAM,WAAc,GAAA,KAAA,CAAA;AACvD,IAAA,OAAO,MAAO,CAAA,SAAA,CAAA;AAAA,GAClB,EAAG,CAAC,KAAK,CAAC,CAAA,CAAA;AACd,CAAA;AAEA,SAAS,KAAK,EAAY,EAAA;AACtB,EAAA,OAAO,EACF,CAAA,WAAA,EACA,CAAA,OAAA,CAAQ,cAAgB,EAAA,EAAE,CAC1B,CAAA,OAAA,CAAQ,MAAQ,EAAA,GAAG,CACnB,CAAA,OAAA,CAAQ,OAAO,GAAG,CAAA,CAAA;AAC3B;;;;"}