@accelint/map-toolkit 1.0.0 → 1.2.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 +19 -0
- package/catalog-info.yaml +4 -4
- package/dist/camera/events.js.map +1 -1
- package/dist/camera/store.js.map +1 -1
- package/dist/cursor-coordinates/index.d.ts +4 -2
- package/dist/cursor-coordinates/index.js +3 -2
- package/dist/cursor-coordinates/store.d.ts +48 -0
- package/dist/cursor-coordinates/store.js +92 -0
- package/dist/cursor-coordinates/store.js.map +1 -0
- package/dist/cursor-coordinates/types.d.ts +87 -0
- package/dist/cursor-coordinates/types.js +12 -0
- package/dist/cursor-coordinates/use-cursor-coordinates.d.ts +41 -37
- package/dist/cursor-coordinates/use-cursor-coordinates.js +131 -202
- package/dist/cursor-coordinates/use-cursor-coordinates.js.map +1 -1
- package/dist/deckgl/base-map/controls.d.ts +1 -1
- package/dist/deckgl/base-map/controls.js.map +1 -1
- package/dist/deckgl/base-map/events.js.map +1 -1
- package/dist/deckgl/base-map/index.d.ts +2 -2
- package/dist/deckgl/base-map/index.js +3 -3
- package/dist/deckgl/base-map/provider.d.ts +2 -2
- package/dist/deckgl/base-map/provider.js.map +1 -1
- package/dist/deckgl/index.js +1 -1
- package/dist/deckgl/saved-viewports/index.js.map +1 -1
- package/dist/deckgl/saved-viewports/storage.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/fiber.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/use-select-shape.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/events.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/fiber.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/index.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/events.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js.map +1 -1
- package/dist/deckgl/shapes/index.d.ts +1 -1
- package/dist/deckgl/shapes/shared/constants.js.map +1 -1
- package/dist/deckgl/shapes/shared/events.js.map +1 -1
- package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js.map +1 -1
- package/dist/deckgl/shapes/shared/types.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/geometry-measurements.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/layer-config.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/mode-utils.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/pick-filtering.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/style-utils.js.map +1 -1
- package/dist/deckgl/symbol-layer/fiber.js.map +1 -1
- package/dist/deckgl/symbol-layer/index.js.map +1 -1
- package/dist/deckgl/text-layer/character-sets.js.map +1 -1
- package/dist/deckgl/text-layer/default-settings.js.map +1 -1
- package/dist/deckgl/text-layer/fiber.js.map +1 -1
- package/dist/deckgl/text-layer/index.js.map +1 -1
- package/dist/deckgl/text-settings.js.map +1 -1
- package/dist/map-cursor/events.js.map +1 -1
- package/dist/map-cursor/store.js.map +1 -1
- package/dist/map-cursor/use-map-cursor.js.map +1 -1
- package/dist/map-mode/events.js.map +1 -1
- package/dist/map-mode/store.js.map +1 -1
- package/dist/map-mode/use-map-mode.js.map +1 -1
- package/dist/maplibre/hooks/use-maplibre.js.map +1 -1
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/create-map-store.js.map +1 -1
- package/dist/shared/units.js.map +1 -1
- package/dist/viewport/store.js.map +1 -1
- package/dist/viewport/utils.js.map +1 -1
- package/dist/viewport/viewport-size.js.map +1 -1
- package/package.json +12 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @accelint/map-toolkit
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 878bfa6: Refactored the hotkey-manager package to decouple react.
|
|
8
|
+
|
|
9
|
+
## 1.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 0175dd1: Update useCursorCoordinates to accept a custom formatter and return more information about the raw coordinate.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [45275c4]
|
|
18
|
+
- Updated dependencies [d328b71]
|
|
19
|
+
- @accelint/geo@0.5.1
|
|
20
|
+
- @accelint/logger@0.1.5
|
|
21
|
+
|
|
3
22
|
## 1.0.0
|
|
4
23
|
|
|
5
24
|
### Major Changes
|
package/catalog-info.yaml
CHANGED
|
@@ -11,15 +11,15 @@ metadata:
|
|
|
11
11
|
|
|
12
12
|
Dependencies:
|
|
13
13
|
|
|
14
|
-
accelint_biome-config@1.0
|
|
15
|
-
accelint_design-foundation@2.
|
|
16
|
-
accelint_geo@0.5.
|
|
14
|
+
accelint_biome-config@1.1.0, accelint_bus@3.0.2, accelint_core@0.5.2,
|
|
15
|
+
accelint_design-foundation@2.1.0, accelint_design-toolkit@9.3.0,
|
|
16
|
+
accelint_geo@0.5.1, accelint_logger@0.1.5,
|
|
17
17
|
accelint_postcss-tailwind-css-modules@1.0.1, accelint_smeegl@0.3.4,
|
|
18
18
|
accelint_typescript-config@0.1.4, accelint_vitest-config@0.1.6
|
|
19
19
|
annotations:
|
|
20
20
|
backstage.io/edit-url: https://github.com/gohypergiant/standard-toolkit/blob/main/packages/map-toolkit/catalog-info.yaml
|
|
21
21
|
backstage.io/techdocs-ref: dir:.
|
|
22
|
-
package/version: 1.
|
|
22
|
+
package/version: 1.2.0
|
|
23
23
|
github.com/project-slug: gohypergiant/standard-toolkit
|
|
24
24
|
links:
|
|
25
25
|
- url: https://github.com/gohypergiant/standard-toolkit/tree/main/packages/map-toolkit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":[],"sources":["../../src/camera/events.ts"],"sourcesContent":["/*\n * Copyright
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../src/camera/events.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport const CameraEventNamespace = 'camera';\n\nexport const CameraEventTypes = {\n setView: `${CameraEventNamespace}:setView`,\n setProjection: `${CameraEventNamespace}:setProjection`,\n setZoom: `${CameraEventNamespace}:setZoom`,\n setRotation: `${CameraEventNamespace}:setRotation`,\n setPitch: `${CameraEventNamespace}:setPitch`,\n setCenter: `${CameraEventNamespace}:setCenter`,\n fitBounds: `${CameraEventNamespace}:fitBounds`,\n reset: `${CameraEventNamespace}:reset`,\n} as const;\n"],"mappings":";;;;;;;;;;;;;;AAYA,MAAa,uBAAuB;AAEpC,MAAa,mBAAmB;CAC9B,SAAS,GAAG,qBAAqB;CACjC,eAAe,GAAG,qBAAqB;CACvC,SAAS,GAAG,qBAAqB;CACjC,aAAa,GAAG,qBAAqB;CACrC,UAAU,GAAG,qBAAqB;CAClC,WAAW,GAAG,qBAAqB;CACnC,WAAW,GAAG,qBAAqB;CACnC,OAAO,GAAG,qBAAqB;CAChC"}
|
package/dist/camera/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","names":["DEFAULT_CAMERA_STATE: CameraState"],"sources":["../../src/camera/store.ts"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Camera Store\n *\n * Manages camera state (position, zoom, pitch, rotation, projection, view) per map instance.\n * State is updated via bus events or direct actions.\n *\n * @example\n * ```tsx\n * import { cameraStore } from '@accelint/map-toolkit/camera';\n *\n * function MapInfo({ mapId }) {\n * const { state } = cameraStore.use(mapId);\n * return (\n * <div>\n * Lat: {state.latitude.toFixed(2)}, Lon: {state.longitude.toFixed(2)}\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { fitBounds } from '@math.gl/web-mercator';\nimport { createMapStore } from '../shared/create-map-store';\nimport { CameraEventTypes } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { CameraEvent, ProjectionType, ViewType } from './types';\n\nconst cameraBus = Broadcast.getInstance<CameraEvent>();\n\n/**\n * Camera state for 2D view\n */\ntype CameraState2D = {\n latitude: number;\n longitude: number;\n zoom: number;\n pitch: 0;\n rotation: number;\n projection: 'mercator';\n view: '2D';\n};\n\n/**\n * Camera state for 3D view\n */\ntype CameraState3D = {\n latitude: number;\n longitude: number;\n zoom: number;\n pitch: 0;\n rotation: number;\n projection: 'globe';\n view: '3D';\n};\n\n/**\n * Camera state for 2.5D view\n */\ntype CameraState2Point5D = {\n latitude: number;\n longitude: number;\n zoom: number;\n pitch: number;\n rotation: number;\n projection: 'mercator';\n view: '2.5D';\n};\n\n/**\n * Union type for all camera states\n */\nexport type CameraState = CameraState2D | CameraState3D | CameraState2Point5D;\n\n/**\n * Actions for camera management\n */\ntype CameraActions = {\n /** Update camera state directly */\n setCameraState: (state: Partial<CameraState>) => void;\n};\n\n/**\n * Storage for initial camera state per instance.\n * Used for reset operations to restore to initial values.\n *\n * @internal These caches live outside the store factory because reset operations\n * need access to the original initial values. They are cleaned up via `onCleanup`\n * hook when the store instance is destroyed, and via `clearCameraState()` for\n * manual cleanup. Do NOT use `cameraStore.clear()` directly in tests - use\n * `clearCameraState()` instead to ensure proper cleanup.\n */\nconst initialStateCache = new Map<UniqueId, CameraStateInput>();\n\n/**\n * Track which instances have been initialized.\n * @internal See note on initialStateCache about cleanup.\n */\nconst initializedInstances = new Set<UniqueId>();\n\n/**\n * Input type for building camera state - simpler than union type\n */\ntype CameraStateInput = {\n latitude?: number;\n longitude?: number;\n zoom?: number;\n pitch?: number;\n rotation?: number;\n projection?: ProjectionType;\n view?: ViewType;\n};\n\n/**\n * Build a complete camera state from partial input.\n * Returns the appropriate discriminated union variant based on view/projection.\n */\nfunction buildCameraState(partial?: CameraStateInput): CameraState {\n const latitude = partial?.latitude ?? 0;\n const longitude = partial?.longitude ?? 0;\n const zoom = partial?.zoom ?? 0;\n const rotation = partial?.rotation ?? 0;\n\n // Determine which variant to build based on view/projection\n const is3D = partial?.view === '3D' || partial?.projection === 'globe';\n const is2Point5D = partial?.view === '2.5D';\n\n if (is3D) {\n // 3D view: globe projection, no pitch, no rotation\n return {\n latitude,\n longitude,\n zoom,\n pitch: 0,\n rotation: 0,\n projection: 'globe',\n view: '3D',\n } satisfies CameraState3D;\n }\n\n if (is2Point5D) {\n // 2.5D view: mercator projection, variable pitch\n return {\n latitude,\n longitude,\n zoom,\n pitch: partial?.pitch ?? 45,\n rotation,\n projection: 'mercator',\n view: '2.5D',\n } satisfies CameraState2Point5D;\n }\n\n // Default: 2D view, mercator projection, no pitch\n return {\n latitude,\n longitude,\n zoom,\n pitch: 0,\n rotation,\n projection: 'mercator',\n view: '2D',\n } satisfies CameraState2D;\n}\n\n/**\n * Default camera state\n */\nconst DEFAULT_CAMERA_STATE: CameraState = {\n latitude: 0,\n longitude: 0,\n zoom: 0,\n pitch: 0,\n rotation: 0,\n projection: 'mercator',\n view: '2D',\n};\n\n/**\n * Camera store instance\n */\nexport const cameraStore = createMapStore<CameraState, CameraActions>({\n defaultState: DEFAULT_CAMERA_STATE,\n\n actions: (_mapId, { get, replace }) => ({\n setCameraState: (updates: Partial<CameraState>) => {\n const currentState = get();\n // Use buildCameraState to ensure proper discriminated union type\n replace(buildCameraState({ ...currentState, ...updates }));\n },\n }),\n\n bus: (mapId, { get, replace }) => {\n const unsubReset = cameraBus.on(CameraEventTypes.reset, ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const initialState = initialStateCache.get(mapId);\n const newState = buildCameraState({\n latitude: state.latitude,\n longitude: state.longitude,\n projection: state.projection,\n view: state.view,\n zoom: payload.zoom === false ? state.zoom : (initialState?.zoom ?? 0),\n pitch:\n payload.pitch === false ? state.pitch : (initialState?.pitch ?? 0),\n rotation:\n payload.rotation === false\n ? state.rotation\n : (initialState?.rotation ?? 0),\n });\n\n replace(newState);\n });\n\n const unsubSetCenter = cameraBus.on(\n CameraEventTypes.setCenter,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n replace(\n buildCameraState({\n ...state,\n latitude: payload.latitude,\n longitude: payload.longitude,\n zoom: payload.zoom ?? state.zoom,\n rotation: payload.heading ?? state.rotation,\n pitch: payload.pitch ?? state.pitch,\n }),\n );\n },\n );\n\n const unsubFitBounds = cameraBus.on(\n CameraEventTypes.fitBounds,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const { longitude, latitude, zoom } = fitBounds({\n width: payload.width,\n height: payload.height,\n bounds: [\n [payload.bounds[0], payload.bounds[1]],\n [payload.bounds[2], payload.bounds[3]],\n ],\n padding: payload.padding,\n });\n\n replace(\n buildCameraState({\n ...state,\n latitude,\n longitude,\n zoom,\n rotation: payload.heading ?? state.rotation,\n pitch: payload.pitch ?? state.pitch,\n }),\n );\n },\n );\n\n const unsubSetProjection = cameraBus.on(\n CameraEventTypes.setProjection,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const newState = { ...state };\n newState.projection = payload.projection;\n if (payload.projection === 'globe') {\n newState.view = '3D';\n } else {\n newState.view = '2D';\n newState.pitch = 0;\n }\n replace(newState);\n },\n );\n\n const unsubSetView = cameraBus.on(\n CameraEventTypes.setView,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const newState = { ...state };\n newState.view = payload.view;\n if (payload.view === '3D') {\n newState.projection = 'globe';\n newState.pitch = 0;\n } else {\n newState.projection = 'mercator';\n }\n\n if (payload.view === '2.5D') {\n newState.pitch = 45;\n }\n replace(newState);\n },\n );\n\n const unsubSetZoom = cameraBus.on(\n CameraEventTypes.setZoom,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n replace({ ...state, zoom: payload.zoom });\n },\n );\n\n const unsubSetRotation = cameraBus.on(\n CameraEventTypes.setRotation,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n if (state.view !== '3D') {\n replace({ ...state, rotation: payload.rotation });\n }\n },\n );\n\n const unsubSetPitch = cameraBus.on(\n CameraEventTypes.setPitch,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n if (state.view === '2.5D') {\n replace({ ...state, pitch: payload.pitch });\n }\n },\n );\n\n return () => {\n unsubReset();\n unsubSetCenter();\n unsubFitBounds();\n unsubSetProjection();\n unsubSetView();\n unsubSetZoom();\n unsubSetRotation();\n unsubSetPitch();\n };\n },\n\n onCleanup: (mapId) => {\n initializedInstances.delete(mapId);\n initialStateCache.delete(mapId);\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Initialize camera state for a map instance with optional initial values.\n * Should be called before using the camera store for a given mapId.\n *\n * @param mapId - Unique identifier for the map instance\n * @param initialState - Optional initial camera state\n */\nexport function initializeCameraState(\n mapId: UniqueId,\n initialState?: CameraStateInput,\n): void {\n if (initializedInstances.has(mapId)) {\n return; // Already initialized\n }\n\n initializedInstances.add(mapId);\n if (initialState) {\n initialStateCache.set(mapId, initialState);\n }\n const builtState = buildCameraState(initialState);\n cameraStore.set(mapId, builtState);\n}\n\n/**\n * Hook to subscribe to camera state changes for a specific map.\n *\n * @param mapId - Unique identifier for the map instance\n * @param initialCameraState - Optional initial camera state (only used on first call)\n * @returns Camera state and setCameraState action\n *\n * @example\n * ```tsx\n * function MapInfo({ mapId }) {\n * const { cameraState, setCameraState } = useMapCamera(mapId);\n * return (\n * <div>\n * Lat: {cameraState.latitude.toFixed(2)}, Lon: {cameraState.longitude.toFixed(2)}\n * </div>\n * );\n * }\n * ```\n */\nexport function useMapCamera(\n mapId: UniqueId,\n initialCameraState?: CameraStateInput,\n): {\n cameraState: CameraState;\n setCameraState: (state: Partial<CameraState>) => void;\n} {\n // Initialize on first use if initial state provided\n if (initialCameraState && !initializedInstances.has(mapId)) {\n initializeCameraState(mapId, initialCameraState);\n }\n\n const { state, setCameraState } = cameraStore.use(mapId);\n\n return { cameraState: state, setCameraState };\n}\n\n/**\n * Manually clear camera state for a specific map instance.\n *\n * @param mapId - The unique identifier for the map instance to clear\n */\nexport function clearCameraState(mapId: UniqueId): void {\n initializedInstances.delete(mapId);\n initialStateCache.delete(mapId);\n cameraStore.clear(mapId);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","names":["DEFAULT_CAMERA_STATE: CameraState"],"sources":["../../src/camera/store.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Camera Store\n *\n * Manages camera state (position, zoom, pitch, rotation, projection, view) per map instance.\n * State is updated via bus events or direct actions.\n *\n * @example\n * ```tsx\n * import { cameraStore } from '@accelint/map-toolkit/camera';\n *\n * function MapInfo({ mapId }) {\n * const { state } = cameraStore.use(mapId);\n * return (\n * <div>\n * Lat: {state.latitude.toFixed(2)}, Lon: {state.longitude.toFixed(2)}\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { fitBounds } from '@math.gl/web-mercator';\nimport { createMapStore } from '../shared/create-map-store';\nimport { CameraEventTypes } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { CameraEvent, ProjectionType, ViewType } from './types';\n\nconst cameraBus = Broadcast.getInstance<CameraEvent>();\n\n/**\n * Camera state for 2D view\n */\ntype CameraState2D = {\n latitude: number;\n longitude: number;\n zoom: number;\n pitch: 0;\n rotation: number;\n projection: 'mercator';\n view: '2D';\n};\n\n/**\n * Camera state for 3D view\n */\ntype CameraState3D = {\n latitude: number;\n longitude: number;\n zoom: number;\n pitch: 0;\n rotation: number;\n projection: 'globe';\n view: '3D';\n};\n\n/**\n * Camera state for 2.5D view\n */\ntype CameraState2Point5D = {\n latitude: number;\n longitude: number;\n zoom: number;\n pitch: number;\n rotation: number;\n projection: 'mercator';\n view: '2.5D';\n};\n\n/**\n * Union type for all camera states\n */\nexport type CameraState = CameraState2D | CameraState3D | CameraState2Point5D;\n\n/**\n * Actions for camera management\n */\ntype CameraActions = {\n /** Update camera state directly */\n setCameraState: (state: Partial<CameraState>) => void;\n};\n\n/**\n * Storage for initial camera state per instance.\n * Used for reset operations to restore to initial values.\n *\n * @internal These caches live outside the store factory because reset operations\n * need access to the original initial values. They are cleaned up via `onCleanup`\n * hook when the store instance is destroyed, and via `clearCameraState()` for\n * manual cleanup. Do NOT use `cameraStore.clear()` directly in tests - use\n * `clearCameraState()` instead to ensure proper cleanup.\n */\nconst initialStateCache = new Map<UniqueId, CameraStateInput>();\n\n/**\n * Track which instances have been initialized.\n * @internal See note on initialStateCache about cleanup.\n */\nconst initializedInstances = new Set<UniqueId>();\n\n/**\n * Input type for building camera state - simpler than union type\n */\ntype CameraStateInput = {\n latitude?: number;\n longitude?: number;\n zoom?: number;\n pitch?: number;\n rotation?: number;\n projection?: ProjectionType;\n view?: ViewType;\n};\n\n/**\n * Build a complete camera state from partial input.\n * Returns the appropriate discriminated union variant based on view/projection.\n */\nfunction buildCameraState(partial?: CameraStateInput): CameraState {\n const latitude = partial?.latitude ?? 0;\n const longitude = partial?.longitude ?? 0;\n const zoom = partial?.zoom ?? 0;\n const rotation = partial?.rotation ?? 0;\n\n // Determine which variant to build based on view/projection\n const is3D = partial?.view === '3D' || partial?.projection === 'globe';\n const is2Point5D = partial?.view === '2.5D';\n\n if (is3D) {\n // 3D view: globe projection, no pitch, no rotation\n return {\n latitude,\n longitude,\n zoom,\n pitch: 0,\n rotation: 0,\n projection: 'globe',\n view: '3D',\n } satisfies CameraState3D;\n }\n\n if (is2Point5D) {\n // 2.5D view: mercator projection, variable pitch\n return {\n latitude,\n longitude,\n zoom,\n pitch: partial?.pitch ?? 45,\n rotation,\n projection: 'mercator',\n view: '2.5D',\n } satisfies CameraState2Point5D;\n }\n\n // Default: 2D view, mercator projection, no pitch\n return {\n latitude,\n longitude,\n zoom,\n pitch: 0,\n rotation,\n projection: 'mercator',\n view: '2D',\n } satisfies CameraState2D;\n}\n\n/**\n * Default camera state\n */\nconst DEFAULT_CAMERA_STATE: CameraState = {\n latitude: 0,\n longitude: 0,\n zoom: 0,\n pitch: 0,\n rotation: 0,\n projection: 'mercator',\n view: '2D',\n};\n\n/**\n * Camera store instance\n */\nexport const cameraStore = createMapStore<CameraState, CameraActions>({\n defaultState: DEFAULT_CAMERA_STATE,\n\n actions: (_mapId, { get, replace }) => ({\n setCameraState: (updates: Partial<CameraState>) => {\n const currentState = get();\n // Use buildCameraState to ensure proper discriminated union type\n replace(buildCameraState({ ...currentState, ...updates }));\n },\n }),\n\n bus: (mapId, { get, replace }) => {\n const unsubReset = cameraBus.on(CameraEventTypes.reset, ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const initialState = initialStateCache.get(mapId);\n const newState = buildCameraState({\n latitude: state.latitude,\n longitude: state.longitude,\n projection: state.projection,\n view: state.view,\n zoom: payload.zoom === false ? state.zoom : (initialState?.zoom ?? 0),\n pitch:\n payload.pitch === false ? state.pitch : (initialState?.pitch ?? 0),\n rotation:\n payload.rotation === false\n ? state.rotation\n : (initialState?.rotation ?? 0),\n });\n\n replace(newState);\n });\n\n const unsubSetCenter = cameraBus.on(\n CameraEventTypes.setCenter,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n replace(\n buildCameraState({\n ...state,\n latitude: payload.latitude,\n longitude: payload.longitude,\n zoom: payload.zoom ?? state.zoom,\n rotation: payload.heading ?? state.rotation,\n pitch: payload.pitch ?? state.pitch,\n }),\n );\n },\n );\n\n const unsubFitBounds = cameraBus.on(\n CameraEventTypes.fitBounds,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const { longitude, latitude, zoom } = fitBounds({\n width: payload.width,\n height: payload.height,\n bounds: [\n [payload.bounds[0], payload.bounds[1]],\n [payload.bounds[2], payload.bounds[3]],\n ],\n padding: payload.padding,\n });\n\n replace(\n buildCameraState({\n ...state,\n latitude,\n longitude,\n zoom,\n rotation: payload.heading ?? state.rotation,\n pitch: payload.pitch ?? state.pitch,\n }),\n );\n },\n );\n\n const unsubSetProjection = cameraBus.on(\n CameraEventTypes.setProjection,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const newState = { ...state };\n newState.projection = payload.projection;\n if (payload.projection === 'globe') {\n newState.view = '3D';\n } else {\n newState.view = '2D';\n newState.pitch = 0;\n }\n replace(newState);\n },\n );\n\n const unsubSetView = cameraBus.on(\n CameraEventTypes.setView,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const newState = { ...state };\n newState.view = payload.view;\n if (payload.view === '3D') {\n newState.projection = 'globe';\n newState.pitch = 0;\n } else {\n newState.projection = 'mercator';\n }\n\n if (payload.view === '2.5D') {\n newState.pitch = 45;\n }\n replace(newState);\n },\n );\n\n const unsubSetZoom = cameraBus.on(\n CameraEventTypes.setZoom,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n replace({ ...state, zoom: payload.zoom });\n },\n );\n\n const unsubSetRotation = cameraBus.on(\n CameraEventTypes.setRotation,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n if (state.view !== '3D') {\n replace({ ...state, rotation: payload.rotation });\n }\n },\n );\n\n const unsubSetPitch = cameraBus.on(\n CameraEventTypes.setPitch,\n ({ payload }) => {\n if (payload.id !== mapId) {\n return;\n }\n\n const state = get();\n if (state.view === '2.5D') {\n replace({ ...state, pitch: payload.pitch });\n }\n },\n );\n\n return () => {\n unsubReset();\n unsubSetCenter();\n unsubFitBounds();\n unsubSetProjection();\n unsubSetView();\n unsubSetZoom();\n unsubSetRotation();\n unsubSetPitch();\n };\n },\n\n onCleanup: (mapId) => {\n initializedInstances.delete(mapId);\n initialStateCache.delete(mapId);\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Initialize camera state for a map instance with optional initial values.\n * Should be called before using the camera store for a given mapId.\n *\n * @param mapId - Unique identifier for the map instance\n * @param initialState - Optional initial camera state\n */\nexport function initializeCameraState(\n mapId: UniqueId,\n initialState?: CameraStateInput,\n): void {\n if (initializedInstances.has(mapId)) {\n return; // Already initialized\n }\n\n initializedInstances.add(mapId);\n if (initialState) {\n initialStateCache.set(mapId, initialState);\n }\n const builtState = buildCameraState(initialState);\n cameraStore.set(mapId, builtState);\n}\n\n/**\n * Hook to subscribe to camera state changes for a specific map.\n *\n * @param mapId - Unique identifier for the map instance\n * @param initialCameraState - Optional initial camera state (only used on first call)\n * @returns Camera state and setCameraState action\n *\n * @example\n * ```tsx\n * function MapInfo({ mapId }) {\n * const { cameraState, setCameraState } = useMapCamera(mapId);\n * return (\n * <div>\n * Lat: {cameraState.latitude.toFixed(2)}, Lon: {cameraState.longitude.toFixed(2)}\n * </div>\n * );\n * }\n * ```\n */\nexport function useMapCamera(\n mapId: UniqueId,\n initialCameraState?: CameraStateInput,\n): {\n cameraState: CameraState;\n setCameraState: (state: Partial<CameraState>) => void;\n} {\n // Initialize on first use if initial state provided\n if (initialCameraState && !initializedInstances.has(mapId)) {\n initializeCameraState(mapId, initialCameraState);\n }\n\n const { state, setCameraState } = cameraStore.use(mapId);\n\n return { cameraState: state, setCameraState };\n}\n\n/**\n * Manually clear camera state for a specific map instance.\n *\n * @param mapId - The unique identifier for the map instance to clear\n */\nexport function clearCameraState(mapId: UniqueId): void {\n initializedInstances.delete(mapId);\n initialStateCache.delete(mapId);\n cameraStore.clear(mapId);\n}\n"],"mappings":"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"}
|
|
@@ -10,5 +10,7 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { CoordinateFormatTypes,
|
|
14
|
-
|
|
13
|
+
import { CoordinateFormatTypes, CoordinateFormatter, CursorCoordinateState, RawCoordinate, UseCursorCoordinatesOptions, UseCursorCoordinatesReturn } from "./types.js";
|
|
14
|
+
import { clearCursorCoordinateState, cursorCoordinateStore } from "./store.js";
|
|
15
|
+
import { useCursorCoordinates } from "./use-cursor-coordinates.js";
|
|
16
|
+
export { type CoordinateFormatTypes, type CoordinateFormatter, type CursorCoordinateState, type RawCoordinate, type UseCursorCoordinatesOptions, type UseCursorCoordinatesReturn, clearCursorCoordinateState, cursorCoordinateStore, useCursorCoordinates };
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
import { clearCursorCoordinateState,
|
|
14
|
+
import { clearCursorCoordinateState, cursorCoordinateStore } from "./store.js";
|
|
15
|
+
import { useCursorCoordinates } from "./use-cursor-coordinates.js";
|
|
15
16
|
|
|
16
|
-
export { clearCursorCoordinateState, useCursorCoordinates };
|
|
17
|
+
export { clearCursorCoordinateState, cursorCoordinateStore, useCursorCoordinates };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { MapStore } from "../shared/create-map-store.js";
|
|
14
|
+
import { CoordinateFormatTypes, CursorCoordinateState } from "./types.js";
|
|
15
|
+
import { UniqueId } from "@accelint/core";
|
|
16
|
+
|
|
17
|
+
//#region src/cursor-coordinates/store.d.ts
|
|
18
|
+
/**
|
|
19
|
+
* Actions for cursor coordinate management
|
|
20
|
+
*/
|
|
21
|
+
type CursorCoordinateActions = {
|
|
22
|
+
/** Set the coordinate display format */
|
|
23
|
+
setFormat: (format: CoordinateFormatTypes) => void;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Cursor coordinates store
|
|
27
|
+
*
|
|
28
|
+
* Stores the current cursor position and display format for each map instance.
|
|
29
|
+
* Automatically subscribes to hover events when first React subscriber mounts.
|
|
30
|
+
*/
|
|
31
|
+
declare const cursorCoordinateStore: MapStore<CursorCoordinateState, CursorCoordinateActions>;
|
|
32
|
+
/**
|
|
33
|
+
* Clear cursor coordinate state for a specific map instance.
|
|
34
|
+
* This is typically not needed as cleanup happens automatically when all subscribers unmount.
|
|
35
|
+
* Use this only in advanced scenarios where manual cleanup is required.
|
|
36
|
+
*
|
|
37
|
+
* @param instanceId - The unique identifier for the map to clear
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* // Manual cleanup (rarely needed)
|
|
42
|
+
* clearCursorCoordinateState('my-map-instance');
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function clearCursorCoordinateState(instanceId: UniqueId): void;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { clearCursorCoordinateState, cursorCoordinateStore };
|
|
48
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import { createMapStore } from "../shared/create-map-store.js";
|
|
15
|
+
import { MapEvents } from "../deckgl/base-map/events.js";
|
|
16
|
+
import { Broadcast } from "@accelint/bus";
|
|
17
|
+
|
|
18
|
+
//#region src/cursor-coordinates/store.ts
|
|
19
|
+
/**
|
|
20
|
+
* Cursor Coordinates Store
|
|
21
|
+
*
|
|
22
|
+
* Manages cursor coordinate state for map instances using the shared store factory.
|
|
23
|
+
* Subscribes to hover events from the map and stores the current cursor position.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* import { cursorCoordinateStore } from './store';
|
|
28
|
+
*
|
|
29
|
+
* // Use in a component
|
|
30
|
+
* function CoordinateDisplay({ mapId }) {
|
|
31
|
+
* const { state, setFormat } = cursorCoordinateStore.use(mapId);
|
|
32
|
+
* return <div>{state.coordinate ? `${state.coordinate[0]}, ${state.coordinate[1]}` : '--'}</div>;
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* // Or use the selector for specific values
|
|
36
|
+
* const coord = cursorCoordinateStore.useSelector(mapId, (s) => s.coordinate);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
const bus = Broadcast.getInstance();
|
|
40
|
+
/**
|
|
41
|
+
* Type guard to validate that a value is a proper coordinate tuple.
|
|
42
|
+
* Checks that the value is an array with exactly two finite numbers.
|
|
43
|
+
*
|
|
44
|
+
* @param value - Value to validate as a coordinate
|
|
45
|
+
* @returns True if value is a valid [longitude, latitude] tuple
|
|
46
|
+
*/
|
|
47
|
+
function isValidCoordinate(value) {
|
|
48
|
+
return Array.isArray(value) && value.length === 2 && value.every(Number.isFinite);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Cursor coordinates store
|
|
52
|
+
*
|
|
53
|
+
* Stores the current cursor position and display format for each map instance.
|
|
54
|
+
* Automatically subscribes to hover events when first React subscriber mounts.
|
|
55
|
+
*/
|
|
56
|
+
const cursorCoordinateStore = createMapStore({
|
|
57
|
+
defaultState: {
|
|
58
|
+
coordinate: null,
|
|
59
|
+
format: "dd"
|
|
60
|
+
},
|
|
61
|
+
actions: (_mapId, { set }) => ({ setFormat: (format) => {
|
|
62
|
+
set({ format });
|
|
63
|
+
} }),
|
|
64
|
+
bus: (mapId, { set }) => {
|
|
65
|
+
return bus.on(MapEvents.hover, (data) => {
|
|
66
|
+
if (mapId !== data.payload.id) return;
|
|
67
|
+
const coords = data.payload.info.coordinate;
|
|
68
|
+
if (isValidCoordinate(coords)) set({ coordinate: coords });
|
|
69
|
+
else set({ coordinate: null });
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Clear cursor coordinate state for a specific map instance.
|
|
75
|
+
* This is typically not needed as cleanup happens automatically when all subscribers unmount.
|
|
76
|
+
* Use this only in advanced scenarios where manual cleanup is required.
|
|
77
|
+
*
|
|
78
|
+
* @param instanceId - The unique identifier for the map to clear
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```tsx
|
|
82
|
+
* // Manual cleanup (rarely needed)
|
|
83
|
+
* clearCursorCoordinateState('my-map-instance');
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
function clearCursorCoordinateState(instanceId) {
|
|
87
|
+
cursorCoordinateStore.clear(instanceId);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { clearCursorCoordinateState, cursorCoordinateStore };
|
|
92
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","names":[],"sources":["../../src/cursor-coordinates/store.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Cursor Coordinates Store\n *\n * Manages cursor coordinate state for map instances using the shared store factory.\n * Subscribes to hover events from the map and stores the current cursor position.\n *\n * @example\n * ```tsx\n * import { cursorCoordinateStore } from './store';\n *\n * // Use in a component\n * function CoordinateDisplay({ mapId }) {\n * const { state, setFormat } = cursorCoordinateStore.use(mapId);\n * return <div>{state.coordinate ? `${state.coordinate[0]}, ${state.coordinate[1]}` : '--'}</div>;\n * }\n *\n * // Or use the selector for specific values\n * const coord = cursorCoordinateStore.useSelector(mapId, (s) => s.coordinate);\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { MapEvents } from '../deckgl/base-map/events';\nimport { createMapStore } from '../shared/create-map-store';\nimport type { UniqueId } from '@accelint/core';\nimport type { MapEventType, MapHoverEvent } from '../deckgl/base-map/types';\nimport type { CoordinateFormatTypes, CursorCoordinateState } from './types';\n\nconst bus = Broadcast.getInstance<MapEventType>();\n\n/**\n * Type guard to validate that a value is a proper coordinate tuple.\n * Checks that the value is an array with exactly two finite numbers.\n *\n * @param value - Value to validate as a coordinate\n * @returns True if value is a valid [longitude, latitude] tuple\n */\nfunction isValidCoordinate(value?: number[]): value is [number, number] {\n return (\n Array.isArray(value) && value.length === 2 && value.every(Number.isFinite)\n );\n}\n\n/**\n * Actions for cursor coordinate management\n */\ntype CursorCoordinateActions = {\n /** Set the coordinate display format */\n setFormat: (format: CoordinateFormatTypes) => void;\n};\n\n/**\n * Cursor coordinates store\n *\n * Stores the current cursor position and display format for each map instance.\n * Automatically subscribes to hover events when first React subscriber mounts.\n */\nexport const cursorCoordinateStore = createMapStore<\n CursorCoordinateState,\n CursorCoordinateActions\n>({\n defaultState: {\n coordinate: null,\n format: 'dd',\n },\n\n actions: (_mapId, { set }) => ({\n setFormat: (format: CoordinateFormatTypes) => {\n set({ format });\n },\n }),\n\n bus: (mapId, { set }) => {\n return bus.on(MapEvents.hover, (data: MapHoverEvent) => {\n const eventId = data.payload.id;\n\n // Ignore hover events from other map instances\n if (mapId !== eventId) {\n return;\n }\n\n const coords = data.payload.info.coordinate;\n\n // Update coordinate if valid, or clear if invalid\n if (isValidCoordinate(coords)) {\n set({ coordinate: coords as [number, number] });\n } else {\n set({ coordinate: null });\n }\n });\n },\n});\n\n/**\n * Clear cursor coordinate state for a specific map instance.\n * This is typically not needed as cleanup happens automatically when all subscribers unmount.\n * Use this only in advanced scenarios where manual cleanup is required.\n *\n * @param instanceId - The unique identifier for the map to clear\n *\n * @example\n * ```tsx\n * // Manual cleanup (rarely needed)\n * clearCursorCoordinateState('my-map-instance');\n * ```\n */\nexport function clearCursorCoordinateState(instanceId: UniqueId): void {\n cursorCoordinateStore.clear(instanceId);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAM,MAAM,UAAU,aAA2B;;;;;;;;AASjD,SAAS,kBAAkB,OAA6C;AACtE,QACE,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,KAAK,MAAM,MAAM,OAAO,SAAS;;;;;;;;AAkB9E,MAAa,wBAAwB,eAGnC;CACA,cAAc;EACZ,YAAY;EACZ,QAAQ;EACT;CAED,UAAU,QAAQ,EAAE,WAAW,EAC7B,YAAY,WAAkC;AAC5C,MAAI,EAAE,QAAQ,CAAC;IAElB;CAED,MAAM,OAAO,EAAE,UAAU;AACvB,SAAO,IAAI,GAAG,UAAU,QAAQ,SAAwB;AAItD,OAAI,UAHY,KAAK,QAAQ,GAI3B;GAGF,MAAM,SAAS,KAAK,QAAQ,KAAK;AAGjC,OAAI,kBAAkB,OAAO,CAC3B,KAAI,EAAE,YAAY,QAA4B,CAAC;OAE/C,KAAI,EAAE,YAAY,MAAM,CAAC;IAE3B;;CAEL,CAAC;;;;;;;;;;;;;;AAeF,SAAgB,2BAA2B,YAA4B;AACrE,uBAAsB,MAAM,WAAW"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { coordinateSystems } from "@accelint/geo";
|
|
14
|
+
|
|
15
|
+
//#region src/cursor-coordinates/types.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* Supported coordinate format types for displaying map coordinates.
|
|
18
|
+
*
|
|
19
|
+
* @typedef {'dd' | 'ddm' | 'dms' | 'mgrs' | 'utm'} CoordinateFormatTypes
|
|
20
|
+
* @property dd - Decimal Degrees (e.g., "45.500000° N, 30.250000° E")
|
|
21
|
+
* @property ddm - Degrees Decimal Minutes (e.g., "45° 30.0000' N, 30° 15.0000' E")
|
|
22
|
+
* @property dms - Degrees Minutes Seconds (e.g., "45° 30' 0.00" N, 30° 15' 0.00" E")
|
|
23
|
+
* @property mgrs - Military Grid Reference System (e.g., "31U DQ 48251 11932")
|
|
24
|
+
* @property utm - Universal Transverse Mercator (e.g., "31N 448251 5411932")
|
|
25
|
+
*/
|
|
26
|
+
type CoordinateFormatTypes = keyof typeof coordinateSystems;
|
|
27
|
+
/**
|
|
28
|
+
* Raw coordinate data returned by the hook.
|
|
29
|
+
* Always in longitude/latitude format, matching the order from map hover events.
|
|
30
|
+
*
|
|
31
|
+
* Returns `null` when cursor is not over the map or coordinates are invalid.
|
|
32
|
+
*/
|
|
33
|
+
type RawCoordinate = {
|
|
34
|
+
/** Longitude value in degrees (-180 to 180, normalized) */
|
|
35
|
+
longitude: number;
|
|
36
|
+
/** Latitude value in degrees (-90 to 90) */
|
|
37
|
+
latitude: number;
|
|
38
|
+
} | null;
|
|
39
|
+
/**
|
|
40
|
+
* Custom formatter function signature.
|
|
41
|
+
* Receives the raw coordinate data and returns a formatted string.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const customFormatter: CoordinateFormatter = (coord) =>
|
|
46
|
+
* `Lat: ${coord.latitude.toFixed(6)}° Lng: ${coord.longitude.toFixed(6)}°`;
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
type CoordinateFormatter = (coordinate: NonNullable<RawCoordinate>) => string;
|
|
50
|
+
/**
|
|
51
|
+
* Options for configuring cursor coordinate behavior.
|
|
52
|
+
*/
|
|
53
|
+
type UseCursorCoordinatesOptions = {
|
|
54
|
+
/**
|
|
55
|
+
* Custom formatter function. When provided, this takes precedence
|
|
56
|
+
* over the built-in format for the `formattedCoord` return value.
|
|
57
|
+
*
|
|
58
|
+
* The `setFormat` function still works and affects `currentFormat`,
|
|
59
|
+
* but won't affect `formattedCoord` when a custom formatter is active.
|
|
60
|
+
*/
|
|
61
|
+
formatter?: CoordinateFormatter;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Return type for useCursorCoordinates hook.
|
|
65
|
+
*/
|
|
66
|
+
type UseCursorCoordinatesReturn = {
|
|
67
|
+
/** Formatted coordinate string using current format or custom formatter */
|
|
68
|
+
formattedCoord: string;
|
|
69
|
+
/** Function to change the coordinate format system */
|
|
70
|
+
setFormat: (format: CoordinateFormatTypes) => void;
|
|
71
|
+
/** Raw coordinate data (always available when cursor is over map) */
|
|
72
|
+
rawCoord: RawCoordinate;
|
|
73
|
+
/** Current active format type */
|
|
74
|
+
currentFormat: CoordinateFormatTypes;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Internal state stored for each map instance's cursor coordinates.
|
|
78
|
+
*/
|
|
79
|
+
type CursorCoordinateState = {
|
|
80
|
+
/** Raw coordinate tuple [longitude, latitude] or null */
|
|
81
|
+
coordinate: [number, number] | null;
|
|
82
|
+
/** Current format type */
|
|
83
|
+
format: CoordinateFormatTypes;
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
export { CoordinateFormatTypes, CoordinateFormatter, CursorCoordinateState, RawCoordinate, UseCursorCoordinatesOptions, UseCursorCoordinatesReturn };
|
|
87
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
@@ -10,35 +10,11 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { UseCursorCoordinatesOptions, UseCursorCoordinatesReturn } from "./types.js";
|
|
14
14
|
import { UniqueId } from "@accelint/core";
|
|
15
15
|
|
|
16
16
|
//#region src/cursor-coordinates/use-cursor-coordinates.d.ts
|
|
17
|
-
|
|
18
|
-
* Supported coordinate format types for displaying map coordinates.
|
|
19
|
-
*
|
|
20
|
-
* @typedef {'dd' | 'ddm' | 'dms' | 'mgrs' | 'utm'} CoordinateFormatTypes
|
|
21
|
-
* @property dd - Decimal Degrees (e.g., "45.50000000 E / 30.25000000 N")
|
|
22
|
-
* @property ddm - Degrees Decimal Minutes (e.g., "45° 30' E / 30° 15' N")
|
|
23
|
-
* @property dms - Degrees Minutes Seconds (e.g., "45° 30' 0\" E / 30° 15' 0\" N")
|
|
24
|
-
* @property mgrs - Military Grid Reference System (e.g., "31U DQ 48251 11932")
|
|
25
|
-
* @property utm - Universal Transverse Mercator (e.g., "31N 448251 5411932")
|
|
26
|
-
*/
|
|
27
|
-
type CoordinateFormatTypes = keyof typeof coordinateSystems;
|
|
28
|
-
/**
|
|
29
|
-
* Manually clear cursor coordinate state for a specific instanceId.
|
|
30
|
-
* This is typically not needed as cleanup happens automatically when all subscribers unmount.
|
|
31
|
-
* Use this only in advanced scenarios where manual cleanup is required.
|
|
32
|
-
*
|
|
33
|
-
* @param instanceId - The unique identifier for the map to clear
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```tsx
|
|
37
|
-
* // Manual cleanup (rarely needed)
|
|
38
|
-
* clearCursorCoordinateState('my-map-instance');
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
declare function clearCursorCoordinateState(instanceId: UniqueId): void;
|
|
17
|
+
|
|
42
18
|
/**
|
|
43
19
|
* React hook that tracks and formats the cursor hover position coordinates on a map.
|
|
44
20
|
*
|
|
@@ -46,17 +22,15 @@ declare function clearCursorCoordinateState(instanceId: UniqueId): void;
|
|
|
46
22
|
* geographic formats (Decimal Degrees, DMS, MGRS, UTM, etc.). The hook automatically
|
|
47
23
|
* filters events to only process those from the specified map instance.
|
|
48
24
|
*
|
|
49
|
-
* Uses
|
|
50
|
-
* where multiple components can subscribe to the same map's coordinates with a single
|
|
51
|
-
* bus listener.
|
|
25
|
+
* Uses the shared store factory for efficient state management and automatic cleanup.
|
|
52
26
|
*
|
|
53
27
|
* @param id - Optional map instance ID. If not provided, attempts to use the ID from MapProvider context.
|
|
54
|
-
* @
|
|
55
|
-
* @
|
|
56
|
-
* @property setFormat - Function to change the coordinate format system
|
|
28
|
+
* @param options - Optional configuration options
|
|
29
|
+
* @returns Object containing the formatted coordinate string, raw coordinate, format setter, and current format
|
|
57
30
|
* @throws {Error} When no id is provided and hook is used outside MapProvider context
|
|
58
31
|
*
|
|
59
32
|
* @example
|
|
33
|
+
* Basic usage:
|
|
60
34
|
* ```tsx
|
|
61
35
|
* import { uuid } from '@accelint/core';
|
|
62
36
|
* import { useCursorCoordinates } from '@accelint/map-toolkit/cursor-coordinates';
|
|
@@ -80,11 +54,41 @@ declare function clearCursorCoordinateState(instanceId: UniqueId): void;
|
|
|
80
54
|
* );
|
|
81
55
|
* }
|
|
82
56
|
* ```
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* With custom formatter:
|
|
60
|
+
* ```tsx
|
|
61
|
+
* function CustomCoordinateDisplay() {
|
|
62
|
+
* const { formattedCoord, rawCoord } = useCursorCoordinates(MAP_ID, {
|
|
63
|
+
* formatter: (coord) =>
|
|
64
|
+
* `Lat: ${coord.latitude.toFixed(6)}° Lng: ${coord.longitude.toFixed(6)}°`,
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* return <div>{formattedCoord}</div>;
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* Accessing raw coordinates:
|
|
73
|
+
* ```tsx
|
|
74
|
+
* function RawCoordinateDisplay() {
|
|
75
|
+
* const { rawCoord, currentFormat } = useCursorCoordinates(MAP_ID);
|
|
76
|
+
*
|
|
77
|
+
* if (!rawCoord) {
|
|
78
|
+
* return <div>Move cursor over map</div>;
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* return (
|
|
82
|
+
* <div>
|
|
83
|
+
* <div>Longitude: {rawCoord.longitude}</div>
|
|
84
|
+
* <div>Latitude: {rawCoord.latitude}</div>
|
|
85
|
+
* <div>Format: {currentFormat}</div>
|
|
86
|
+
* </div>
|
|
87
|
+
* );
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
83
90
|
*/
|
|
84
|
-
declare function useCursorCoordinates(id?: UniqueId):
|
|
85
|
-
formattedCoord: string;
|
|
86
|
-
setFormat: (format: CoordinateFormatTypes) => void;
|
|
87
|
-
};
|
|
91
|
+
declare function useCursorCoordinates(id?: UniqueId, options?: UseCursorCoordinatesOptions): UseCursorCoordinatesReturn;
|
|
88
92
|
//#endregion
|
|
89
|
-
export {
|
|
93
|
+
export { useCursorCoordinates };
|
|
90
94
|
//# sourceMappingURL=use-cursor-coordinates.d.ts.map
|