@open-pioneer/spatial-bookmarks 0.4.3 → 0.7.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,5 +1,45 @@
1
1
  # @open-pioneer/spatial-bookmarks
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 310800c: Switch from `peerDependencies` to normal `dependencies`. Peer dependencies have some usability problems when used at scale.
8
+
9
+ ### Patch Changes
10
+
11
+ - 310800c: Update core packages version.
12
+ - 583f1d6: The `mapId` or `map` properties are now optional on individual components.
13
+ You can use the `DefaultMapProvider` to configure an implicit default value.
14
+
15
+ Note that configuring _neither_ a default _nor_ an explicit `map` or `mapId` will trigger a runtime error.
16
+
17
+ - 583f1d6: All UI components in this project now accept the `mapId` (a `string`) _or_ the `map` (a `MapModel`) directly.
18
+ - a8b3449: Switch to a new versioning strategy.
19
+ From now on, packages released by this repository share a common version number.
20
+ - 900eb11: Update dependencies.
21
+ - Updated dependencies [310800c]
22
+ - Updated dependencies [2502050]
23
+ - Updated dependencies [583f1d6]
24
+ - Updated dependencies [583f1d6]
25
+ - Updated dependencies [397d617]
26
+ - Updated dependencies [a8b3449]
27
+ - Updated dependencies [310800c]
28
+ - Updated dependencies [900eb11]
29
+ - Updated dependencies [583f1d6]
30
+ - Updated dependencies [397d617]
31
+ - @open-pioneer/map@0.7.0
32
+
33
+ ## 0.4.4
34
+
35
+ ### Patch Changes
36
+
37
+ - 3e7d978: Use reactivity API to manage internal state.
38
+ - b152428: Update trails dependencies
39
+ - Updated dependencies [b152428]
40
+ - Updated dependencies [291ccb6]
41
+ - @open-pioneer/map@0.6.1
42
+
3
43
  ## 0.4.3
4
44
 
5
45
  ### Patch Changes
@@ -1,10 +1,7 @@
1
+ import { MapModelProps } from "@open-pioneer/map";
1
2
  import { CommonComponentProps } from "@open-pioneer/react-utils";
2
3
  import { FC } from "react";
3
- export interface SpatialBookmarksProps extends CommonComponentProps {
4
- /**
5
- * The id of the map.
6
- */
7
- mapId: string;
4
+ export interface SpatialBookmarksProps extends CommonComponentProps, MapModelProps {
8
5
  }
9
6
  /**
10
7
  * A component that allows the user to manage a set of spatial bookmarks.
@@ -3,27 +3,26 @@ import { Flex, VStack, Alert, AlertIcon, Input, List, Box, Center, Text, Spacer,
3
3
  import { useMapModel } from '@open-pioneer/map';
4
4
  import { useCommonComponentProps } from '@open-pioneer/react-utils';
5
5
  import classNames from 'classnames';
6
- import { Provider, useAtomValue } from 'jotai';
7
6
  import { useService, useIntl } from './_virtual/_virtual-pioneer-module_react-hooks.js';
8
7
  import { useRef, useState, useEffect } from 'react';
9
8
  import { PiMapTrifold, PiTrashSimpleLight } from 'react-icons/pi';
10
9
  import { SpatialBookmarkViewModel } from './SpatialBookmarksViewModel.js';
10
+ import { useReactiveSnapshot } from '@open-pioneer/reactivity';
11
11
 
12
12
  const SpatialBookmarks = (props) => {
13
- const { map } = useMapModel(props.mapId);
13
+ const { map } = useMapModel(props);
14
14
  const localStorageService = useService(
15
15
  "local-storage.LocalStorageService"
16
16
  );
17
17
  const viewModel = useViewModel(map, localStorageService);
18
- return viewModel && // Makes the store accessible to useAtom() etc. in the UI
19
- /* @__PURE__ */ jsx(Provider, { store: viewModel.store, children: /* @__PURE__ */ jsx(SpatialBookmarkUI, { ...props, viewModel }) });
18
+ return viewModel && /* @__PURE__ */ jsx(SpatialBookmarkUI, { ...props, viewModel });
20
19
  };
21
20
  function SpatialBookmarkUI(props) {
22
21
  const { viewModel } = props;
23
22
  const intl = useIntl();
24
23
  const listItemNodes = useRef([]);
25
24
  const [scrollToLastItem, setScrollToLastItem] = useState(false);
26
- const bookmarks = useAtomValue(viewModel.bookmarks);
25
+ const bookmarks = useReactiveSnapshot(() => viewModel.bookmarks, [viewModel]);
27
26
  const [bookmarkName, setBookmarkName] = useState("");
28
27
  const isValidBookmarkName = bookmarkName.trim().length > 0;
29
28
  const { containerProps } = useCommonComponentProps("spatial-bookmarks", props);
@@ -1 +1 @@
1
- {"version":3,"file":"SpatialBookmarks.js","sources":["SpatialBookmarks.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport {\n Alert,\n AlertIcon,\n Box,\n Button,\n ButtonProps,\n Flex,\n Input,\n List,\n Spacer,\n Text,\n Tooltip,\n VStack,\n Center\n} from \"@open-pioneer/chakra-integration\";\nimport { LocalStorageService } from \"@open-pioneer/local-storage\";\nimport { MapModel, useMapModel } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport classNames from \"classnames\";\nimport { Provider as JotaiProvider, useAtomValue } from \"jotai\";\nimport { useIntl, useService } from \"open-pioneer:react-hooks\";\nimport { FC, KeyboardEvent, ReactNode, useEffect, useRef, useState } from \"react\";\nimport { PiMapTrifold, PiTrashSimpleLight } from \"react-icons/pi\";\nimport { Bookmark, SpatialBookmarkViewModel } from \"./SpatialBookmarksViewModel\";\n\ntype UIMode = \"list\" | \"create\" | \"delete\";\n\nexport interface SpatialBookmarksProps extends CommonComponentProps {\n /**\n * The id of the map.\n */\n mapId: string;\n}\n\n/**\n * A component that allows the user to manage a set of spatial bookmarks.\n */\nexport const SpatialBookmarks: FC<SpatialBookmarksProps> = (props) => {\n const { map } = useMapModel(props.mapId);\n const localStorageService = useService<LocalStorageService>(\n \"local-storage.LocalStorageService\"\n );\n const viewModel = useViewModel(map, localStorageService);\n return (\n viewModel && (\n // Makes the store accessible to useAtom() etc. in the UI\n <JotaiProvider store={viewModel.store}>\n <SpatialBookmarkUI {...props} viewModel={viewModel} />\n </JotaiProvider>\n )\n );\n};\n\nfunction SpatialBookmarkUI(props: SpatialBookmarksProps & { viewModel: SpatialBookmarkViewModel }) {\n const { viewModel } = props;\n const intl = useIntl();\n const listItemNodes = useRef<HTMLElement[]>([]);\n const [scrollToLastItem, setScrollToLastItem] = useState(false);\n\n const bookmarks = useAtomValue(viewModel.bookmarks);\n const [bookmarkName, setBookmarkName] = useState<string>(\"\");\n const isValidBookmarkName = bookmarkName.trim().length > 0; // use trim to avoid bookmarks with space character only\n const { containerProps } = useCommonComponentProps(\"spatial-bookmarks\", props);\n const [uiMode, setUiMode] = useState<UIMode>(\"list\");\n\n const clearBookmarks = () => {\n viewModel.deleteAllBookmarks();\n setUiMode(\"list\");\n };\n\n const addBookmark = () => {\n if (isValidBookmarkName) {\n viewModel.createBookmark(bookmarkName);\n setUiMode(\"list\");\n setBookmarkName(\"\");\n setScrollToLastItem(true);\n }\n };\n\n // Scroll to newly created bookmark after render\n useEffect(() => {\n if (scrollToLastItem) {\n const listItems = listItemNodes.current;\n if (listItems) {\n const lastItem = listItems[bookmarks.length - 1];\n lastItem?.scrollIntoView?.();\n }\n setScrollToLastItem(false);\n }\n }, [bookmarks, scrollToLastItem]);\n\n const deleteContent = () => (\n <VStack>\n <Alert rounded=\"md\" status=\"warning\">\n <AlertIcon />\n {intl.formatMessage({ id: \"bookmark.alert.delete\" })}\n </Alert>\n <RemoveControls\n intl={intl}\n onClear={clearBookmarks}\n onCancel={() => setUiMode(\"list\")}\n />\n </VStack>\n );\n\n const createContent = () => (\n <VStack>\n <Alert rounded=\"md\" status=\"info\">\n <AlertIcon />\n {intl.formatMessage({ id: \"bookmark.alert.create\" })}\n </Alert>\n <Input\n aria-label={intl.formatMessage({ id: \"bookmark.input.label\" })}\n placeholder={intl.formatMessage({ id: \"bookmark.input.placeholder\" })}\n value={bookmarkName}\n onChange={(event) => {\n setBookmarkName(event.target.value);\n }}\n onKeyDown={(e) => {\n // add bookmark only, if valid bookmark name exists\n if (e.key === \"Enter\") {\n addBookmark();\n }\n }}\n isRequired\n isInvalid={!isValidBookmarkName}\n autoFocus // eslint-disable-line jsx-a11y/no-autofocus\n />\n <CreateControls\n intl={intl}\n isInvalid={!isValidBookmarkName}\n onCancel={() => {\n setBookmarkName(\"\");\n setUiMode(\"list\");\n }}\n onSave={addBookmark}\n />\n </VStack>\n );\n\n const listContent = () => (\n <>\n {bookmarks.length ? (\n createList(bookmarks, viewModel, intl, listItemNodes)\n ) : (\n <Alert rounded=\"md\" status=\"info\">\n <AlertIcon />\n {intl.formatMessage({ id: \"bookmark.alert.noSaved\" })}\n </Alert>\n )}\n <ListControls\n intl={intl}\n bookmarks={bookmarks}\n showCreate={() => setUiMode(\"create\")}\n showDelete={() => setUiMode(\"delete\")}\n />\n </>\n );\n\n const content = (\n <>\n {uiMode === \"list\" && listContent()}\n {uiMode === \"create\" && createContent()}\n {uiMode === \"delete\" && deleteContent()}\n </>\n );\n\n return (\n <Flex flexDirection=\"column\" {...containerProps}>\n {content}\n </Flex>\n );\n}\n\nfunction createList(\n bookmarks: Bookmark[],\n viewModel: SpatialBookmarkViewModel,\n intl: PackageIntl,\n listRef: React.MutableRefObject<HTMLElement[]>\n) {\n const deleteBtnLabel = intl.formatMessage({\n id: \"bookmark.button.deleteOne\"\n });\n\n const bookmarkItems = bookmarks.map((bookmark, idx) => (\n <BookmarkItem\n key={bookmark.id}\n index={idx}\n listItemNodes={listRef}\n bookmark={bookmark}\n onActivate={() => viewModel.activateBookmark(bookmark)}\n onDelete={() => viewModel.deleteBookmark(bookmark.id)}\n deleteBtnLabel={deleteBtnLabel}\n />\n ));\n\n return (\n <List\n as=\"ul\"\n className=\"spatial-bookmark-list\"\n role=\"listbox\"\n aria-label={intl.formatMessage({\n id: \"bookmark.list.label\"\n })}\n flexShrink={1}\n flexGrow={1}\n p={1} // Some padding for children's box shadow\n spacing={1}\n overflowY=\"auto\"\n listStyleType=\"none\"\n >\n {bookmarkItems}\n </List>\n );\n}\n\n// key name -> index\nconst ARROW_INDEX_MAP: Record<string, number> = {\n ArrowDown: 1,\n ArrowUp: -1\n};\n\nfunction BookmarkItem(props: {\n index: number;\n listItemNodes: React.MutableRefObject<HTMLElement[]>;\n bookmark: Bookmark;\n onActivate: () => void;\n onDelete: () => void;\n deleteBtnLabel: string;\n}): JSX.Element {\n const { index, listItemNodes, bookmark, onDelete, onActivate, deleteBtnLabel } = props;\n const title = bookmark.title;\n const onKeyDown = (evt: KeyboardEvent) => {\n const key = evt.key;\n if (key === \"Enter\") {\n // Ignore enter from child components (buttons)\n if (evt.target === evt.currentTarget) {\n onActivate();\n }\n return;\n }\n\n if (ARROW_INDEX_MAP[key] != null) {\n const len = listItemNodes.current?.length;\n if (!len) {\n return;\n }\n\n let nextIndex = (index + ARROW_INDEX_MAP[key]!) % len;\n if (nextIndex < 0) {\n nextIndex = len - 1;\n }\n listItemNodes.current[nextIndex]?.focus();\n }\n };\n return (\n <Box\n as=\"li\"\n p={1}\n ref={(el: HTMLDivElement | null) => {\n if (!el) {\n listItemNodes.current.splice(index, 1);\n return;\n }\n listItemNodes.current[index] = el;\n }}\n className={classNames(\"spatial-bookmarks-item\")}\n tabIndex={0}\n rounded=\"md\"\n role=\"option\"\n cursor=\"pointer\"\n outline={0}\n _hover={{ background: \"trails.50\" }}\n _focusVisible={{ boxShadow: \"outline\" }}\n onKeyDown={onKeyDown}\n onClick={onActivate}\n >\n <Flex width=\"100%\" flexDirection=\"row\" align=\"center\" gap={1}>\n <Center>\n <PiMapTrifold />\n </Center>\n <Text ps={2} noOfLines={1}>\n {title}\n </Text>\n <Spacer />\n <Tooltip key={index} hasArrow label={deleteBtnLabel} placement=\"right\">\n <Button\n className=\"spatial-bookmarks-item-delete\"\n aria-label={deleteBtnLabel}\n borderRadius=\"full\"\n iconSpacing={0}\n padding={0}\n colorScheme=\"red\"\n variant=\"ghost\"\n leftIcon={<PiTrashSimpleLight />}\n onClick={(event) => {\n onDelete();\n event.stopPropagation();\n }}\n />\n </Tooltip>\n </Flex>\n </Box>\n );\n}\n\nfunction ListControls(props: {\n intl: PackageIntl;\n bookmarks: Bookmark[];\n showCreate: () => void;\n showDelete: () => void;\n}): JSX.Element {\n const { intl, bookmarks, showCreate, showDelete } = props;\n\n return (\n <ButtonContainer>\n <DialogButton\n isDisabled={bookmarks.length === 0}\n colorScheme=\"red\"\n width={undefined}\n iconSpacing={0}\n leftIcon={<PiTrashSimpleLight />}\n onClick={showDelete}\n aria-label={intl.formatMessage({ id: \"bookmark.button.deleteAll\" })}\n variant=\"outline\"\n />\n <DialogButton onClick={showCreate} width=\"100%\">\n {intl.formatMessage({ id: \"bookmark.button.create\" })}\n </DialogButton>\n </ButtonContainer>\n );\n}\n\nfunction RemoveControls(props: { intl: PackageIntl; onClear: () => void; onCancel: () => void }) {\n const { intl, onCancel, onClear } = props;\n return (\n <ButtonContainer>\n <DialogButton variant=\"outline\" onClick={onCancel}>\n {intl.formatMessage({ id: \"bookmark.button.cancelDelete\" })}\n </DialogButton>\n <DialogButton onClick={onClear}>\n {intl.formatMessage({ id: \"bookmark.button.confirmDelete\" })}\n </DialogButton>\n </ButtonContainer>\n );\n}\n\nfunction CreateControls(props: {\n intl: PackageIntl;\n isInvalid: boolean;\n onCancel: () => void;\n onSave: () => void;\n}) {\n const { intl, onCancel, onSave, isInvalid } = props;\n return (\n <ButtonContainer>\n <DialogButton variant=\"outline\" onClick={() => onCancel()}>\n {intl.formatMessage({ id: \"bookmark.button.cancel\" })}\n </DialogButton>\n <DialogButton isDisabled={isInvalid} onClick={() => onSave()}>\n {intl.formatMessage({ id: \"bookmark.button.save\" })}\n </DialogButton>\n </ButtonContainer>\n );\n}\n\nfunction ButtonContainer(props: { children: ReactNode }) {\n return (\n <Flex width=\"100%\" flexDirection=\"row\" mt={2} gap={1} flexGrow={0} flexShrink={0}>\n {props.children}\n </Flex>\n );\n}\n\nfunction DialogButton(props?: ButtonProps): JSX.Element {\n return <Button width=\"100%\" {...props} />;\n}\n\nfunction useViewModel(map: MapModel | undefined, localStorageService: LocalStorageService) {\n const [viewModel, setViewModel] = useState<SpatialBookmarkViewModel>();\n useEffect(() => {\n let viewModel: SpatialBookmarkViewModel | undefined;\n if (!map) {\n viewModel = undefined;\n } else {\n viewModel = new SpatialBookmarkViewModel(map, localStorageService);\n }\n\n setViewModel(viewModel);\n return () => viewModel?.destroy();\n }, [map, localStorageService]);\n\n return viewModel;\n}\n"],"names":["JotaiProvider","viewModel"],"mappings":"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"}
1
+ {"version":3,"file":"SpatialBookmarks.js","sources":["SpatialBookmarks.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport {\n Alert,\n AlertIcon,\n Box,\n Button,\n ButtonProps,\n Flex,\n Input,\n List,\n Spacer,\n Text,\n Tooltip,\n VStack,\n Center\n} from \"@open-pioneer/chakra-integration\";\nimport { LocalStorageService } from \"@open-pioneer/local-storage\";\nimport { MapModel, MapModelProps, useMapModel } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport classNames from \"classnames\";\nimport { useIntl, useService } from \"open-pioneer:react-hooks\";\nimport { FC, KeyboardEvent, ReactNode, useEffect, useRef, useState } from \"react\";\nimport { PiMapTrifold, PiTrashSimpleLight } from \"react-icons/pi\";\nimport { Bookmark, SpatialBookmarkViewModel } from \"./SpatialBookmarksViewModel\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\n\ntype UIMode = \"list\" | \"create\" | \"delete\";\n\nexport interface SpatialBookmarksProps extends CommonComponentProps, MapModelProps {}\n\n/**\n * A component that allows the user to manage a set of spatial bookmarks.\n */\nexport const SpatialBookmarks: FC<SpatialBookmarksProps> = (props) => {\n const { map } = useMapModel(props);\n const localStorageService = useService<LocalStorageService>(\n \"local-storage.LocalStorageService\"\n );\n const viewModel = useViewModel(map, localStorageService);\n return viewModel && <SpatialBookmarkUI {...props} viewModel={viewModel} />;\n};\n\nfunction SpatialBookmarkUI(props: SpatialBookmarksProps & { viewModel: SpatialBookmarkViewModel }) {\n const { viewModel } = props;\n const intl = useIntl();\n const listItemNodes = useRef<HTMLElement[]>([]);\n const [scrollToLastItem, setScrollToLastItem] = useState(false);\n const bookmarks = useReactiveSnapshot(() => viewModel.bookmarks, [viewModel]);\n const [bookmarkName, setBookmarkName] = useState<string>(\"\");\n const isValidBookmarkName = bookmarkName.trim().length > 0; // use trim to avoid bookmarks with space character only\n const { containerProps } = useCommonComponentProps(\"spatial-bookmarks\", props);\n const [uiMode, setUiMode] = useState<UIMode>(\"list\");\n\n const clearBookmarks = () => {\n viewModel.deleteAllBookmarks();\n setUiMode(\"list\");\n };\n\n const addBookmark = () => {\n if (isValidBookmarkName) {\n viewModel.createBookmark(bookmarkName);\n setUiMode(\"list\");\n setBookmarkName(\"\");\n setScrollToLastItem(true);\n }\n };\n\n // Scroll to newly created bookmark after render\n useEffect(() => {\n if (scrollToLastItem) {\n const listItems = listItemNodes.current;\n if (listItems) {\n const lastItem = listItems[bookmarks.length - 1];\n lastItem?.scrollIntoView?.();\n }\n setScrollToLastItem(false);\n }\n }, [bookmarks, scrollToLastItem]);\n\n const deleteContent = () => (\n <VStack>\n <Alert rounded=\"md\" status=\"warning\">\n <AlertIcon />\n {intl.formatMessage({ id: \"bookmark.alert.delete\" })}\n </Alert>\n <RemoveControls\n intl={intl}\n onClear={clearBookmarks}\n onCancel={() => setUiMode(\"list\")}\n />\n </VStack>\n );\n\n const createContent = () => (\n <VStack>\n <Alert rounded=\"md\" status=\"info\">\n <AlertIcon />\n {intl.formatMessage({ id: \"bookmark.alert.create\" })}\n </Alert>\n <Input\n aria-label={intl.formatMessage({ id: \"bookmark.input.label\" })}\n placeholder={intl.formatMessage({ id: \"bookmark.input.placeholder\" })}\n value={bookmarkName}\n onChange={(event) => {\n setBookmarkName(event.target.value);\n }}\n onKeyDown={(e) => {\n // add bookmark only, if valid bookmark name exists\n if (e.key === \"Enter\") {\n addBookmark();\n }\n }}\n isRequired\n isInvalid={!isValidBookmarkName}\n autoFocus // eslint-disable-line jsx-a11y/no-autofocus\n />\n <CreateControls\n intl={intl}\n isInvalid={!isValidBookmarkName}\n onCancel={() => {\n setBookmarkName(\"\");\n setUiMode(\"list\");\n }}\n onSave={addBookmark}\n />\n </VStack>\n );\n\n const listContent = () => (\n <>\n {bookmarks.length ? (\n createList(bookmarks, viewModel, intl, listItemNodes)\n ) : (\n <Alert rounded=\"md\" status=\"info\">\n <AlertIcon />\n {intl.formatMessage({ id: \"bookmark.alert.noSaved\" })}\n </Alert>\n )}\n <ListControls\n intl={intl}\n bookmarks={bookmarks}\n showCreate={() => setUiMode(\"create\")}\n showDelete={() => setUiMode(\"delete\")}\n />\n </>\n );\n\n const content = (\n <>\n {uiMode === \"list\" && listContent()}\n {uiMode === \"create\" && createContent()}\n {uiMode === \"delete\" && deleteContent()}\n </>\n );\n\n return (\n <Flex flexDirection=\"column\" {...containerProps}>\n {content}\n </Flex>\n );\n}\n\nfunction createList(\n bookmarks: Bookmark[],\n viewModel: SpatialBookmarkViewModel,\n intl: PackageIntl,\n listRef: React.MutableRefObject<HTMLElement[]>\n) {\n const deleteBtnLabel = intl.formatMessage({\n id: \"bookmark.button.deleteOne\"\n });\n\n const bookmarkItems = bookmarks.map((bookmark, idx) => (\n <BookmarkItem\n key={bookmark.id}\n index={idx}\n listItemNodes={listRef}\n bookmark={bookmark}\n onActivate={() => viewModel.activateBookmark(bookmark)}\n onDelete={() => viewModel.deleteBookmark(bookmark.id)}\n deleteBtnLabel={deleteBtnLabel}\n />\n ));\n\n return (\n <List\n as=\"ul\"\n className=\"spatial-bookmark-list\"\n role=\"listbox\"\n aria-label={intl.formatMessage({\n id: \"bookmark.list.label\"\n })}\n flexShrink={1}\n flexGrow={1}\n p={1} // Some padding for children's box shadow\n spacing={1}\n overflowY=\"auto\"\n listStyleType=\"none\"\n >\n {bookmarkItems}\n </List>\n );\n}\n\n// key name -> index\nconst ARROW_INDEX_MAP: Record<string, number> = {\n ArrowDown: 1,\n ArrowUp: -1\n};\n\nfunction BookmarkItem(props: {\n index: number;\n listItemNodes: React.MutableRefObject<HTMLElement[]>;\n bookmark: Bookmark;\n onActivate: () => void;\n onDelete: () => void;\n deleteBtnLabel: string;\n}): JSX.Element {\n const { index, listItemNodes, bookmark, onDelete, onActivate, deleteBtnLabel } = props;\n const title = bookmark.title;\n const onKeyDown = (evt: KeyboardEvent) => {\n const key = evt.key;\n if (key === \"Enter\") {\n // Ignore enter from child components (buttons)\n if (evt.target === evt.currentTarget) {\n onActivate();\n }\n return;\n }\n\n if (ARROW_INDEX_MAP[key] != null) {\n const len = listItemNodes.current?.length;\n if (!len) {\n return;\n }\n\n let nextIndex = (index + ARROW_INDEX_MAP[key]!) % len;\n if (nextIndex < 0) {\n nextIndex = len - 1;\n }\n listItemNodes.current[nextIndex]?.focus();\n }\n };\n return (\n <Box\n as=\"li\"\n p={1}\n ref={(el: HTMLDivElement | null) => {\n if (!el) {\n listItemNodes.current.splice(index, 1);\n return;\n }\n listItemNodes.current[index] = el;\n }}\n className={classNames(\"spatial-bookmarks-item\")}\n tabIndex={0}\n rounded=\"md\"\n role=\"option\"\n cursor=\"pointer\"\n outline={0}\n _hover={{ background: \"trails.50\" }}\n _focusVisible={{ boxShadow: \"outline\" }}\n onKeyDown={onKeyDown}\n onClick={onActivate}\n >\n <Flex width=\"100%\" flexDirection=\"row\" align=\"center\" gap={1}>\n <Center>\n <PiMapTrifold />\n </Center>\n <Text ps={2} noOfLines={1}>\n {title}\n </Text>\n <Spacer />\n <Tooltip key={index} hasArrow label={deleteBtnLabel} placement=\"right\">\n <Button\n className=\"spatial-bookmarks-item-delete\"\n aria-label={deleteBtnLabel}\n borderRadius=\"full\"\n iconSpacing={0}\n padding={0}\n colorScheme=\"red\"\n variant=\"ghost\"\n leftIcon={<PiTrashSimpleLight />}\n onClick={(event) => {\n onDelete();\n event.stopPropagation();\n }}\n />\n </Tooltip>\n </Flex>\n </Box>\n );\n}\n\nfunction ListControls(props: {\n intl: PackageIntl;\n bookmarks: Bookmark[];\n showCreate: () => void;\n showDelete: () => void;\n}): JSX.Element {\n const { intl, bookmarks, showCreate, showDelete } = props;\n\n return (\n <ButtonContainer>\n <DialogButton\n isDisabled={bookmarks.length === 0}\n colorScheme=\"red\"\n width={undefined}\n iconSpacing={0}\n leftIcon={<PiTrashSimpleLight />}\n onClick={showDelete}\n aria-label={intl.formatMessage({ id: \"bookmark.button.deleteAll\" })}\n variant=\"outline\"\n />\n <DialogButton onClick={showCreate} width=\"100%\">\n {intl.formatMessage({ id: \"bookmark.button.create\" })}\n </DialogButton>\n </ButtonContainer>\n );\n}\n\nfunction RemoveControls(props: { intl: PackageIntl; onClear: () => void; onCancel: () => void }) {\n const { intl, onCancel, onClear } = props;\n return (\n <ButtonContainer>\n <DialogButton variant=\"outline\" onClick={onCancel}>\n {intl.formatMessage({ id: \"bookmark.button.cancelDelete\" })}\n </DialogButton>\n <DialogButton onClick={onClear}>\n {intl.formatMessage({ id: \"bookmark.button.confirmDelete\" })}\n </DialogButton>\n </ButtonContainer>\n );\n}\n\nfunction CreateControls(props: {\n intl: PackageIntl;\n isInvalid: boolean;\n onCancel: () => void;\n onSave: () => void;\n}) {\n const { intl, onCancel, onSave, isInvalid } = props;\n return (\n <ButtonContainer>\n <DialogButton variant=\"outline\" onClick={() => onCancel()}>\n {intl.formatMessage({ id: \"bookmark.button.cancel\" })}\n </DialogButton>\n <DialogButton isDisabled={isInvalid} onClick={() => onSave()}>\n {intl.formatMessage({ id: \"bookmark.button.save\" })}\n </DialogButton>\n </ButtonContainer>\n );\n}\n\nfunction ButtonContainer(props: { children: ReactNode }) {\n return (\n <Flex width=\"100%\" flexDirection=\"row\" mt={2} gap={1} flexGrow={0} flexShrink={0}>\n {props.children}\n </Flex>\n );\n}\n\nfunction DialogButton(props?: ButtonProps): JSX.Element {\n return <Button width=\"100%\" {...props} />;\n}\n\nfunction useViewModel(map: MapModel | undefined, localStorageService: LocalStorageService) {\n const [viewModel, setViewModel] = useState<SpatialBookmarkViewModel>();\n useEffect(() => {\n let viewModel: SpatialBookmarkViewModel | undefined;\n if (!map) {\n viewModel = undefined;\n } else {\n viewModel = new SpatialBookmarkViewModel(map, localStorageService);\n }\n\n setViewModel(viewModel);\n return () => viewModel?.destroy();\n }, [map, localStorageService]);\n\n return viewModel;\n}\n"],"names":["viewModel"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { MapModel } from "@open-pioneer/map";
2
- import { Atom, createStore } from "jotai";
3
2
  import { LocalStorageService } from "@open-pioneer/local-storage";
4
3
  interface Extent {
5
4
  minX: number;
@@ -13,20 +12,17 @@ export interface Bookmark {
13
12
  extent: Extent;
14
13
  projection: string;
15
14
  }
16
- type Store = ReturnType<typeof createStore>;
17
15
  export declare class SpatialBookmarkViewModel {
18
16
  private map;
19
17
  private packageNamespace;
20
18
  private writableBookmarks;
21
- private stopBookmarksListener;
22
- /** Contains the jotai state (atoms + store === value). */
23
- readonly store: Store;
19
+ private watchBookmarksHandle;
24
20
  /**
25
21
  * Provides read-only access to the bookmarks array.
26
22
  * The UI simply renders the contents of the store and
27
23
  * uses the methods below to modify the state.
28
24
  */
29
- get bookmarks(): Atom<Bookmark[]>;
25
+ get bookmarks(): Bookmark[];
30
26
  constructor(map: MapModel, localStorageService: LocalStorageService);
31
27
  destroy(): void;
32
28
  /**
@@ -1,37 +1,35 @@
1
- import { atom, createStore } from 'jotai';
2
1
  import { v4 } from 'uuid';
3
2
  import { getCenter } from 'ol/extent.js';
4
3
  import { transformExtent } from 'ol/proj.js';
5
4
  import { createLogger } from '@open-pioneer/core';
5
+ import { reactiveArray, watch } from '@conterra/reactivity-core';
6
6
 
7
7
  const LOG = createLogger("spatial-bookmark:SpatialBookmarkViewModel");
8
8
  class SpatialBookmarkViewModel {
9
9
  map;
10
10
  packageNamespace;
11
- writableBookmarks = atom([]);
12
- stopBookmarksListener;
13
- /** Contains the jotai state (atoms + store === value). */
14
- store;
15
- // contains jotai state
11
+ writableBookmarks = reactiveArray([]);
12
+ watchBookmarksHandle;
16
13
  /**
17
14
  * Provides read-only access to the bookmarks array.
18
15
  * The UI simply renders the contents of the store and
19
16
  * uses the methods below to modify the state.
20
17
  */
21
18
  get bookmarks() {
22
- return this.writableBookmarks;
19
+ return this.writableBookmarks.getItems();
23
20
  }
24
21
  constructor(map, localStorageService) {
25
22
  this.map = map;
26
23
  this.packageNamespace = localStorageService.getNamespace("spatial-bookmarks");
27
- this.store = createStore();
28
24
  this.loadState();
29
- this.stopBookmarksListener = this.store.sub(this.bookmarks, () => {
30
- this.saveState();
31
- });
25
+ this.watchBookmarksHandle = watch(
26
+ () => [this.writableBookmarks.getItems()],
27
+ ([bookmarks]) => this.saveState(bookmarks),
28
+ { immediate: false }
29
+ );
32
30
  }
33
31
  destroy() {
34
- this.stopBookmarksListener();
32
+ this.watchBookmarksHandle.destroy();
35
33
  }
36
34
  /**
37
35
  * Creates a new bookmark with the `title` provided by the UI.
@@ -55,7 +53,7 @@ class SpatialBookmarkViewModel {
55
53
  };
56
54
  LOG.debug("Created a new bookmark", bookmark);
57
55
  const bookmarks = this.writableBookmarks;
58
- this.store.set(bookmarks, [...this.store.get(bookmarks), bookmark]);
56
+ bookmarks.push(bookmark);
59
57
  }
60
58
  /**
61
59
  * Activates the bookmark with the given id by zooming
@@ -72,15 +70,17 @@ class SpatialBookmarkViewModel {
72
70
  */
73
71
  deleteBookmark(id) {
74
72
  LOG.debug("Deleting bookmark", id);
75
- const bookmarks = this.writableBookmarks;
76
- this.store.set(bookmarks, [...this.store.get(bookmarks).filter((b) => b.id !== id)]);
73
+ const index = this.writableBookmarks.findIndex((bookmark) => bookmark.id === id);
74
+ if (index > -1) {
75
+ this.writableBookmarks.splice(index, 1);
76
+ }
77
77
  }
78
78
  /**
79
79
  * Deletes all bookmarks.
80
80
  */
81
81
  deleteAllBookmarks() {
82
82
  LOG.debug("Deleting all bookmarks");
83
- this.store.set(this.writableBookmarks, []);
83
+ this.writableBookmarks.splice(0);
84
84
  }
85
85
  /**
86
86
  * Loads the bookmarks from local storage.
@@ -91,19 +91,19 @@ class SpatialBookmarkViewModel {
91
91
  const rawBookmarks = this.packageNamespace.get("bookmarks") ?? [];
92
92
  try {
93
93
  validateBookmarks(rawBookmarks);
94
- this.store.set(this.writableBookmarks, rawBookmarks);
94
+ this.writableBookmarks.push(...rawBookmarks);
95
95
  } catch (e) {
96
96
  LOG.error("Bookmarks data in local storage is invalid, resetting to default value.", e);
97
- this.store.set(this.writableBookmarks, []);
98
- this.saveState();
97
+ this.writableBookmarks.splice(0);
98
+ this.saveState([]);
99
99
  }
100
100
  }
101
101
  /**
102
102
  * Saves the bookmarks to local storage.
103
103
  */
104
- saveState() {
104
+ saveState(bookmarks) {
105
105
  LOG.debug("Saving bookmarks to local storage");
106
- this.packageNamespace.set("bookmarks", this.store.get(this.bookmarks));
106
+ this.packageNamespace.set("bookmarks", bookmarks);
107
107
  }
108
108
  /** Computes an OpenLayers extent for the given bookmark. */
109
109
  getBookmarkExtent(bookmark) {
@@ -1 +1 @@
1
- {"version":3,"file":"SpatialBookmarksViewModel.js","sources":["SpatialBookmarksViewModel.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { MapModel } from \"@open-pioneer/map\";\nimport { Atom, atom, createStore } from \"jotai\";\nimport { LocalStorageNamespace, LocalStorageService } from \"@open-pioneer/local-storage\";\nimport { v4 as uuid4v } from \"uuid\";\nimport { Extent as OlExtent, getCenter } from \"ol/extent\";\nimport { transformExtent } from \"ol/proj\";\nimport { createLogger } from \"@open-pioneer/core\";\n\nconst LOG = createLogger(\"spatial-bookmark:SpatialBookmarkViewModel\");\n\ninterface Extent {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\nexport interface Bookmark {\n id: string;\n title: string;\n extent: Extent;\n projection: string;\n}\n\ntype Store = ReturnType<typeof createStore>;\n\nexport class SpatialBookmarkViewModel {\n private map: MapModel;\n private packageNamespace: LocalStorageNamespace;\n private writableBookmarks = atom<Bookmark[]>([]);\n private stopBookmarksListener: () => void;\n\n /** Contains the jotai state (atoms + store === value). */\n readonly store: Store; // contains jotai state\n\n /**\n * Provides read-only access to the bookmarks array.\n * The UI simply renders the contents of the store and\n * uses the methods below to modify the state.\n */\n get bookmarks(): Atom<Bookmark[]> {\n return this.writableBookmarks;\n }\n\n constructor(map: MapModel, localStorageService: LocalStorageService) {\n this.map = map;\n this.packageNamespace = localStorageService.getNamespace(\"spatial-bookmarks\");\n this.store = createStore();\n\n // Load from local storage on start; save changes whenever bookmarks change.\n this.loadState();\n this.stopBookmarksListener = this.store.sub(this.bookmarks, () => {\n this.saveState();\n });\n }\n\n destroy() {\n this.stopBookmarksListener();\n }\n\n /**\n * Creates a new bookmark with the `title` provided by the UI.\n * The current map extent is used for the new bookmark's extent.\n */\n createBookmark(title: string) {\n const olMap = this.map.olMap;\n // minx, miny, maxx, maxy\n const olExtent = olMap.getView().calculateExtent();\n const projection = olMap.getView().getProjection().getCode();\n const extent: Extent = {\n minX: olExtent[0]!,\n minY: olExtent[1]!,\n maxX: olExtent[2]!,\n maxY: olExtent[3]!\n };\n const bookmark: Bookmark = {\n id: uuid4v(),\n title,\n extent,\n projection\n };\n LOG.debug(\"Created a new bookmark\", bookmark);\n\n const bookmarks = this.writableBookmarks;\n this.store.set(bookmarks, [...this.store.get(bookmarks), bookmark]);\n }\n\n /**\n * Activates the bookmark with the given id by zooming\n * to the bookmark's extent.\n */\n activateBookmark(bookmark: Bookmark) {\n LOG.debug(\"Activating bookmark\", bookmark);\n const extent = this.getBookmarkExtent(bookmark);\n\n LOG.debug(\"Attempting to apply extent\", extent);\n this.applyExtent(extent);\n }\n\n /**\n * Deletes the bookmark with the given id.\n */\n deleteBookmark(id: string) {\n LOG.debug(\"Deleting bookmark\", id);\n const bookmarks = this.writableBookmarks;\n this.store.set(bookmarks, [...this.store.get(bookmarks).filter((b) => b.id !== id)]);\n }\n\n /**\n * Deletes all bookmarks.\n */\n deleteAllBookmarks() {\n LOG.debug(\"Deleting all bookmarks\");\n this.store.set(this.writableBookmarks, []);\n }\n\n /**\n * Loads the bookmarks from local storage.\n * If the bookmarks are not valid, the initial state (empty array) is restored.\n */\n private loadState() {\n LOG.debug(\"Restoring bookmarks from local storage\");\n\n const rawBookmarks = this.packageNamespace.get(\"bookmarks\") ?? [];\n try {\n validateBookmarks(rawBookmarks);\n this.store.set(this.writableBookmarks, rawBookmarks);\n } catch (e) {\n LOG.error(\"Bookmarks data in local storage is invalid, resetting to default value.\", e);\n this.store.set(this.writableBookmarks, []);\n this.saveState();\n }\n }\n\n /**\n * Saves the bookmarks to local storage.\n */\n private saveState() {\n LOG.debug(\"Saving bookmarks to local storage\");\n this.packageNamespace.set(\"bookmarks\", this.store.get(this.bookmarks));\n }\n\n /** Computes an OpenLayers extent for the given bookmark. */\n private getBookmarkExtent(bookmark: Bookmark) {\n const olMap = this.map.olMap;\n const olView = olMap.getView();\n const extent = bookmark.extent;\n const olExtent = [extent.minX, extent.minY, extent.maxX, extent.maxY];\n const viewProjection = olView.getProjection();\n const extentProjection = bookmark.projection;\n return transformExtent(olExtent, extentProjection, viewProjection);\n }\n\n /** Moves the map to the given extent. */\n private applyExtent(olExtent: OlExtent) {\n const olMap = this.map.olMap;\n const olView = olMap.getView();\n const center = getCenter(olExtent);\n const resolution = olView.getResolutionForExtent(olExtent);\n olView.setCenter(center);\n olView.setResolution(resolution);\n }\n}\n\nfunction validateBookmarks(rawBookmarks: unknown): asserts rawBookmarks is Bookmark[] {\n if (!Array.isArray(rawBookmarks)) {\n throw new Error(`Expected bookmarks from local storage to be an array.`);\n }\n for (const rawBookmark of rawBookmarks) {\n validateBookmark(rawBookmark);\n }\n}\n\nfunction validateBookmark(rawBookmark: unknown): asserts rawBookmark is Bookmark {\n if (!rawBookmark || typeof rawBookmark !== \"object\") {\n throw new Error(`Expected bookmark from local storage to be an object.`);\n }\n\n const bookmark = rawBookmark as Record<keyof Bookmark, unknown>;\n if (typeof bookmark.id !== \"string\") {\n throw new Error(\"Bookmark does not have a valid id.\");\n }\n if (typeof bookmark.title !== \"string\") {\n throw new Error(\"Bookmark does not have a valid title.\");\n }\n validateExtent(bookmark.extent);\n if (typeof bookmark.projection !== \"string\") {\n throw new Error(\"Bookmark does not have a valid projection value.\");\n }\n}\n\nfunction validateExtent(rawExtent: unknown): asserts rawExtent is Extent {\n if (!rawExtent || typeof rawExtent !== \"object\") {\n throw new Error(`Expected bookmark extent from local storage to be an object.`);\n }\n\n const extent = rawExtent as Record<keyof Extent, unknown>;\n if (\n typeof extent.minX !== \"number\" ||\n typeof extent.minY !== \"number\" ||\n typeof extent.maxX !== \"number\" ||\n typeof extent.maxY !== \"number\"\n ) {\n throw new Error(\"Expected bookmark extent from local storage to have valid coordinates.\");\n }\n}\n"],"names":["uuid4v"],"mappings":"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"}
1
+ {"version":3,"file":"SpatialBookmarksViewModel.js","sources":["SpatialBookmarksViewModel.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { MapModel } from \"@open-pioneer/map\";\nimport { LocalStorageNamespace, LocalStorageService } from \"@open-pioneer/local-storage\";\nimport { v4 as uuid4v } from \"uuid\";\nimport { Extent as OlExtent, getCenter } from \"ol/extent\";\nimport { transformExtent } from \"ol/proj\";\nimport { createLogger } from \"@open-pioneer/core\";\nimport { CleanupHandle, reactiveArray, watch } from \"@conterra/reactivity-core\";\n\nconst LOG = createLogger(\"spatial-bookmark:SpatialBookmarkViewModel\");\n\ninterface Extent {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\nexport interface Bookmark {\n id: string;\n title: string;\n extent: Extent;\n projection: string;\n}\n\nexport class SpatialBookmarkViewModel {\n private map: MapModel;\n private packageNamespace: LocalStorageNamespace;\n private writableBookmarks = reactiveArray<Bookmark>([]);\n private watchBookmarksHandle: CleanupHandle;\n\n /**\n * Provides read-only access to the bookmarks array.\n * The UI simply renders the contents of the store and\n * uses the methods below to modify the state.\n */\n get bookmarks(): Bookmark[] {\n return this.writableBookmarks.getItems();\n }\n\n constructor(map: MapModel, localStorageService: LocalStorageService) {\n this.map = map;\n this.packageNamespace = localStorageService.getNamespace(\"spatial-bookmarks\");\n\n // Load from local storage on start; save changes whenever bookmarks change.\n this.loadState();\n this.watchBookmarksHandle = watch(\n () => [this.writableBookmarks.getItems()],\n ([bookmarks]) => this.saveState(bookmarks),\n { immediate: false }\n );\n }\n\n destroy() {\n this.watchBookmarksHandle.destroy();\n }\n\n /**\n * Creates a new bookmark with the `title` provided by the UI.\n * The current map extent is used for the new bookmark's extent.\n */\n createBookmark(title: string) {\n const olMap = this.map.olMap;\n // minx, miny, maxx, maxy\n const olExtent = olMap.getView().calculateExtent();\n const projection = olMap.getView().getProjection().getCode();\n const extent: Extent = {\n minX: olExtent[0]!,\n minY: olExtent[1]!,\n maxX: olExtent[2]!,\n maxY: olExtent[3]!\n };\n const bookmark: Bookmark = {\n id: uuid4v(),\n title,\n extent,\n projection\n };\n LOG.debug(\"Created a new bookmark\", bookmark);\n\n const bookmarks = this.writableBookmarks;\n bookmarks.push(bookmark);\n }\n\n /**\n * Activates the bookmark with the given id by zooming\n * to the bookmark's extent.\n */\n activateBookmark(bookmark: Bookmark) {\n LOG.debug(\"Activating bookmark\", bookmark);\n const extent = this.getBookmarkExtent(bookmark);\n\n LOG.debug(\"Attempting to apply extent\", extent);\n this.applyExtent(extent);\n }\n\n /**\n * Deletes the bookmark with the given id.\n */\n deleteBookmark(id: string) {\n LOG.debug(\"Deleting bookmark\", id);\n const index = this.writableBookmarks.findIndex((bookmark) => bookmark.id === id);\n if (index > -1) {\n this.writableBookmarks.splice(index, 1);\n }\n }\n\n /**\n * Deletes all bookmarks.\n */\n deleteAllBookmarks() {\n LOG.debug(\"Deleting all bookmarks\");\n this.writableBookmarks.splice(0);\n }\n\n /**\n * Loads the bookmarks from local storage.\n * If the bookmarks are not valid, the initial state (empty array) is restored.\n */\n private loadState() {\n LOG.debug(\"Restoring bookmarks from local storage\");\n\n const rawBookmarks = this.packageNamespace.get(\"bookmarks\") ?? [];\n try {\n validateBookmarks(rawBookmarks);\n this.writableBookmarks.push(...rawBookmarks);\n } catch (e) {\n LOG.error(\"Bookmarks data in local storage is invalid, resetting to default value.\", e);\n this.writableBookmarks.splice(0);\n this.saveState([]);\n }\n }\n\n /**\n * Saves the bookmarks to local storage.\n */\n private saveState(bookmarks: Bookmark[]) {\n LOG.debug(\"Saving bookmarks to local storage\");\n this.packageNamespace.set(\"bookmarks\", bookmarks);\n }\n\n /** Computes an OpenLayers extent for the given bookmark. */\n private getBookmarkExtent(bookmark: Bookmark) {\n const olMap = this.map.olMap;\n const olView = olMap.getView();\n const extent = bookmark.extent;\n const olExtent = [extent.minX, extent.minY, extent.maxX, extent.maxY];\n const viewProjection = olView.getProjection();\n const extentProjection = bookmark.projection;\n return transformExtent(olExtent, extentProjection, viewProjection);\n }\n\n /** Moves the map to the given extent. */\n private applyExtent(olExtent: OlExtent) {\n const olMap = this.map.olMap;\n const olView = olMap.getView();\n const center = getCenter(olExtent);\n const resolution = olView.getResolutionForExtent(olExtent);\n olView.setCenter(center);\n olView.setResolution(resolution);\n }\n}\n\nfunction validateBookmarks(rawBookmarks: unknown): asserts rawBookmarks is Bookmark[] {\n if (!Array.isArray(rawBookmarks)) {\n throw new Error(`Expected bookmarks from local storage to be an array.`);\n }\n for (const rawBookmark of rawBookmarks) {\n validateBookmark(rawBookmark);\n }\n}\n\nfunction validateBookmark(rawBookmark: unknown): asserts rawBookmark is Bookmark {\n if (!rawBookmark || typeof rawBookmark !== \"object\") {\n throw new Error(`Expected bookmark from local storage to be an object.`);\n }\n\n const bookmark = rawBookmark as Record<keyof Bookmark, unknown>;\n if (typeof bookmark.id !== \"string\") {\n throw new Error(\"Bookmark does not have a valid id.\");\n }\n if (typeof bookmark.title !== \"string\") {\n throw new Error(\"Bookmark does not have a valid title.\");\n }\n validateExtent(bookmark.extent);\n if (typeof bookmark.projection !== \"string\") {\n throw new Error(\"Bookmark does not have a valid projection value.\");\n }\n}\n\nfunction validateExtent(rawExtent: unknown): asserts rawExtent is Extent {\n if (!rawExtent || typeof rawExtent !== \"object\") {\n throw new Error(`Expected bookmark extent from local storage to be an object.`);\n }\n\n const extent = rawExtent as Record<keyof Extent, unknown>;\n if (\n typeof extent.minX !== \"number\" ||\n typeof extent.minY !== \"number\" ||\n typeof extent.maxX !== \"number\" ||\n typeof extent.maxY !== \"number\"\n ) {\n throw new Error(\"Expected bookmark extent from local storage to have valid coordinates.\");\n }\n}\n"],"names":["uuid4v"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@open-pioneer/spatial-bookmarks",
4
- "version": "0.4.3",
4
+ "version": "0.7.0",
5
5
  "description": "This package provides a UI component that allows the user to store, manage, and easily navigate between different map extents by creating bookmarks.",
6
6
  "keywords": [
7
7
  "open-pioneer-trails"
@@ -14,21 +14,20 @@
14
14
  "directory": "src/packages/spatial-bookmarks"
15
15
  },
16
16
  "dependencies": {
17
- "jotai": "^2.9.0",
18
- "uuid": "^10.0.0"
19
- },
20
- "peerDependencies": {
21
- "@chakra-ui/icons": "^2.1.1",
22
- "@open-pioneer/chakra-integration": "^1.1.3",
23
- "@open-pioneer/core": "^1.2.3",
24
- "@open-pioneer/local-storage": "^0.3.1",
25
- "@open-pioneer/react-utils": "^1.0.0",
26
- "@open-pioneer/runtime": "^2.1.6",
17
+ "@chakra-ui/icons": "^2.2.4",
18
+ "@open-pioneer/chakra-integration": "^2.3.0",
19
+ "@open-pioneer/core": "^2.3.0",
20
+ "@open-pioneer/local-storage": "^2.3.0",
21
+ "@open-pioneer/react-utils": "^2.3.0",
22
+ "@open-pioneer/runtime": "^2.3.0",
27
23
  "classnames": "^2.3.2",
28
24
  "ol": "^9.2.4",
29
25
  "react": "^18.3.1",
30
- "react-icons": "^5.2.1",
31
- "@open-pioneer/map": "^0.6.0"
26
+ "react-icons": "^5.3.0",
27
+ "@conterra/reactivity-core": "^0.4.3",
28
+ "@open-pioneer/reactivity": "^2.3.0",
29
+ "uuid": "^10.0.0",
30
+ "@open-pioneer/map": "^0.7.0"
32
31
  },
33
32
  "exports": {
34
33
  "./package.json": "./package.json",