@accelint/map-toolkit 1.3.0 → 1.5.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/catalog-info.yaml +3 -3
  3. package/dist/camera/store.js +1 -1
  4. package/dist/camera/store.js.map +1 -1
  5. package/dist/cursor-coordinates/use-cursor-coordinates.js.map +1 -1
  6. package/dist/deckgl/base-map/index.d.ts +2 -2
  7. package/dist/deckgl/base-map/index.js +24 -7
  8. package/dist/deckgl/base-map/index.js.map +1 -1
  9. package/dist/deckgl/base-map/provider.d.ts +2 -2
  10. package/dist/deckgl/base-map/provider.js +2 -4
  11. package/dist/deckgl/base-map/provider.js.map +1 -1
  12. package/dist/deckgl/index.js +3 -3
  13. package/dist/deckgl/shapes/display-shape-layer/index.js +1 -1
  14. package/dist/deckgl/shapes/display-shape-layer/store.js +7 -1
  15. package/dist/deckgl/shapes/display-shape-layer/store.js.map +1 -1
  16. package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +2 -2
  17. package/dist/deckgl/shapes/draw-shape-layer/index.js +3 -3
  18. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +7 -7
  19. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -1
  20. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +2 -2
  21. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +2 -2
  22. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +2 -2
  23. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +2 -2
  24. package/dist/deckgl/shapes/draw-shape-layer/store.js +37 -3
  25. package/dist/deckgl/shapes/draw-shape-layer/store.js.map +1 -1
  26. package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.js +1 -1
  27. package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js +1 -1
  28. package/dist/deckgl/shapes/edit-shape-layer/constants.js +2 -1
  29. package/dist/deckgl/shapes/edit-shape-layer/constants.js.map +1 -1
  30. package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +2 -2
  31. package/dist/deckgl/shapes/edit-shape-layer/index.js +30 -12
  32. package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
  33. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +1 -1
  34. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +6 -6
  35. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
  36. package/dist/deckgl/shapes/edit-shape-layer/modes/index.js +10 -4
  37. package/dist/deckgl/shapes/edit-shape-layer/modes/index.js.map +1 -1
  38. package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js +129 -0
  39. package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js.map +1 -0
  40. package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js +1 -1
  41. package/dist/deckgl/shapes/edit-shape-layer/store.js +19 -4
  42. package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
  43. package/dist/deckgl/shapes/edit-shape-layer/types.d.ts +4 -3
  44. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js +1 -1
  45. package/dist/deckgl/shapes/index.js +4 -4
  46. package/dist/deckgl/shapes/shared/constants.js +5 -5
  47. package/dist/deckgl/shapes/shared/constants.js.map +1 -1
  48. package/dist/deckgl/shapes/shared/utils/layer-config.js +1 -1
  49. package/dist/hotkey-manager/dist/react/use-hotkey.js +39 -0
  50. package/dist/hotkey-manager/dist/react/use-hotkey.js.map +1 -0
  51. package/dist/shared/cleanup.d.ts +58 -0
  52. package/dist/shared/cleanup.js +93 -0
  53. package/dist/shared/cleanup.js.map +1 -0
  54. package/dist/shared/create-map-store.d.ts +12 -0
  55. package/dist/shared/create-map-store.js +8 -3
  56. package/dist/shared/create-map-store.js.map +1 -1
  57. package/dist/viewport/viewport-size.d.ts +2 -2
  58. package/package.json +10 -8
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/deckgl/shapes/edit-shape-layer/modes/index.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\nimport { TranslateMode, ViewMode } from '@deck.gl-community/editable-layers';\nimport { BoundingTransformMode } from './bounding-transform-mode';\nimport { CircleTransformMode } from './circle-transform-mode';\nimport { VertexTransformMode } from './vertex-transform-mode';\nimport type { EditMode } from '../types';\n\n/**\n * Cached edit mode instances.\n *\n * CRITICAL: Mode instances must be cached at module level to prevent\n * deck.gl assertion failures. Creating new mode instances on each render\n * causes the EditableGeoJsonLayer to fail with assertion errors.\n *\n * BoundingTransformMode combines ScaleModeWithFreeTransform, RotateMode, and\n * TranslateMode for shapes without vertex editing (ellipses, rectangles),\n * allowing non-uniform scaling plus rotate/translate via bounding box handles.\n * Shows live dimension tooltips during scaling.\n *\n * VertexTransformMode combines ModifyMode with ScaleModeWithFreeTransform,\n * RotateMode, and TranslateMode for shapes that support vertex editing\n * (polygons, lines), allowing vertex manipulation plus scale/rotate/translate.\n *\n * CircleTransformMode combines ResizeCircleMode with TranslateMode\n * for circles, allowing resize from edge plus drag to translate.\n * Shows live diameter/area tooltips during resize.\n *\n * TranslateMode allows dragging to move the shape (used for points).\n */\nconst EDIT_MODE_INSTANCES = {\n view: new ViewMode(),\n 'bounding-transform': new BoundingTransformMode(),\n 'vertex-transform': new VertexTransformMode(),\n 'circle-transform': new CircleTransformMode(),\n translate: new TranslateMode(),\n} as const;\n\n/**\n * Get the cached mode instance for an edit mode.\n *\n * Returns the pre-instantiated edit mode for the specified mode type.\n * Modes are cached at module level to prevent deck.gl assertion failures\n * that occur when creating new mode instances on each render.\n *\n * ## Available Edit Modes\n * - `'bounding-transform'`: For shapes without vertex editing (rectangles, ellipses)\n * - `'vertex-transform'`: For shapes with vertex editing (polygons, lines)\n * - `'circle-transform'`: For circles (resize from edge + translate)\n * - `'translate'`: For points (drag to move)\n *\n * @param mode - The edit mode to get the instance for\n * @returns The cached mode instance\n *\n * @example\n * ```typescript\n * import { getEditModeInstance } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes';\n *\n * // Get the bounding transform mode for editing rectangles/ellipses\n * const boundingMode = getEditModeInstance('bounding-transform');\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: boundingMode,\n * // ... other props\n * });\n * ```\n */\nexport function getEditModeInstance(\n mode: EditMode,\n): (typeof EDIT_MODE_INSTANCES)[EditMode] {\n return EDIT_MODE_INSTANCES[mode];\n}\n\n/**\n * Get the ViewMode instance (for when not editing).\n *\n * Returns the pre-instantiated ViewMode which is the default mode when\n * no editing operation is active. This mode allows viewing and interacting\n * with the map without editing shapes.\n *\n * @returns The cached ViewMode instance\n *\n * @example\n * ```typescript\n * import { getViewModeInstance } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes';\n *\n * // Get the view mode (default when not editing)\n * const viewMode = getViewModeInstance();\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: viewMode,\n * // ... other props\n * });\n * ```\n */\nexport function getViewModeInstance(): ViewMode {\n return EDIT_MODE_INSTANCES.view;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAM,sBAAsB;CAC1B,MAAM,IAAI,UAAU;CACpB,sBAAsB,IAAI,uBAAuB;CACjD,oBAAoB,IAAI,qBAAqB;CAC7C,oBAAoB,IAAI,qBAAqB;CAC7C,WAAW,IAAI,eAAe;CAC/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCD,SAAgB,oBACd,MACwC;AACxC,QAAO,oBAAoB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/deckgl/shapes/edit-shape-layer/modes/index.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\nimport { TranslateMode, ViewMode } from '@deck.gl-community/editable-layers';\nimport { BoundingTransformMode } from './bounding-transform-mode';\nimport { CircleTransformMode } from './circle-transform-mode';\nimport { PointTranslateMode } from './point-translate-mode';\nimport { VertexTransformMode } from './vertex-transform-mode';\nimport type { EditMode } from '../types';\n\n/**\n * Cached edit mode instances.\n *\n * CRITICAL: Mode instances must be cached at module level to prevent\n * deck.gl assertion failures. Creating new mode instances on each render\n * causes the EditableGeoJsonLayer to fail with assertion errors.\n *\n * BoundingTransformMode combines ScaleModeWithFreeTransform, RotateMode, and\n * TranslateMode for shapes without vertex editing (ellipses, rectangles),\n * allowing non-uniform scaling plus rotate/translate via bounding box handles.\n * Shows live dimension tooltips during scaling.\n *\n * VertexTransformMode combines ModifyMode with ScaleModeWithFreeTransform,\n * RotateMode, and TranslateMode for shapes that support vertex editing\n * (polygons, lines), allowing vertex manipulation plus scale/rotate/translate.\n *\n * CircleTransformMode combines ResizeCircleMode with TranslateMode\n * for circles, allowing resize from edge plus drag to translate.\n * Shows live radius/area tooltips during resize.\n *\n * PointTranslateMode allows clicking anywhere on the map to reposition\n * a point, or dragging the point for traditional translation behavior.\n *\n * TranslateMode allows dragging to move the shape (generic translation).\n */\nconst EDIT_MODE_INSTANCES = {\n view: new ViewMode(),\n 'bounding-transform': new BoundingTransformMode(),\n 'vertex-transform': new VertexTransformMode(),\n 'circle-transform': new CircleTransformMode(),\n translate: new TranslateMode(),\n 'point-translate': new PointTranslateMode(),\n} as const;\n\n/**\n * Get the cached mode instance for an edit mode.\n *\n * Returns the pre-instantiated edit mode for the specified mode type.\n * Modes are cached at module level to prevent deck.gl assertion failures\n * that occur when creating new mode instances on each render.\n *\n * ## Available Edit Modes\n * - `'bounding-transform'`: For shapes without vertex editing (rectangles, ellipses)\n * - `'vertex-transform'`: For shapes with vertex editing (polygons, lines)\n * - `'circle-transform'`: For circles (resize from edge + translate)\n * - `'point-translate'`: For points (click to place + drag to move)\n * - `'translate'`: Generic translation (drag to move)\n *\n * @param mode - The edit mode to get the instance for\n * @returns The cached mode instance\n *\n * @example\n * ```typescript\n * import { getEditModeInstance } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes';\n *\n * // Get the bounding transform mode for editing rectangles/ellipses\n * const boundingMode = getEditModeInstance('bounding-transform');\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: boundingMode,\n * // ... other props\n * });\n * ```\n */\nexport function getEditModeInstance(\n mode: EditMode,\n): (typeof EDIT_MODE_INSTANCES)[EditMode] {\n return EDIT_MODE_INSTANCES[mode];\n}\n\n/**\n * Get the ViewMode instance (for when not editing).\n *\n * Returns the pre-instantiated ViewMode which is the default mode when\n * no editing operation is active. This mode allows viewing and interacting\n * with the map without editing shapes.\n *\n * @returns The cached ViewMode instance\n *\n * @example\n * ```typescript\n * import { getViewModeInstance } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes';\n *\n * // Get the view mode (default when not editing)\n * const viewMode = getViewModeInstance();\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: viewMode,\n * // ... other props\n * });\n * ```\n */\nexport function getViewModeInstance(): ViewMode {\n return EDIT_MODE_INSTANCES.view;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,MAAM,sBAAsB;CAC1B,MAAM,IAAI,UAAU;CACpB,sBAAsB,IAAI,uBAAuB;CACjD,oBAAoB,IAAI,qBAAqB;CAC7C,oBAAoB,IAAI,qBAAqB;CAC7C,WAAW,IAAI,eAAe;CAC9B,mBAAmB,IAAI,oBAAoB;CAC5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCD,SAAgB,oBACd,MACwC;AACxC,QAAO,oBAAoB"}
@@ -0,0 +1,129 @@
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 { GeoJsonEditMode, TranslateMode } from "@deck.gl-community/editable-layers";
15
+
16
+ //#region src/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.ts
17
+ /**
18
+ * Edit mode for Point shapes that supports both click-to-place and drag behaviors.
19
+ *
20
+ * ## Capabilities
21
+ * This mode provides two ways to reposition a point:
22
+ * - **Click on empty space**: Instantly moves the point to the clicked location
23
+ * - **Drag the point**: Traditional click-and-drag behavior (via TranslateMode)
24
+ *
25
+ * ## Behavior Details
26
+ * - Clicking anywhere on the map (that isn't the point itself) repositions the point
27
+ * - Clicking directly on the point and dragging works as traditional translation
28
+ * - Both behaviors emit the 'translated' edit type for consistency with existing event handling
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * import { PointTranslateMode } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes/point-translate-mode';
33
+ * import { EditableGeoJsonLayer } from '@deck.gl-community/editable-layers';
34
+ *
35
+ * // Used internally by EditShapeLayer for points
36
+ * const mode = new PointTranslateMode();
37
+ *
38
+ * const layer = new EditableGeoJsonLayer({
39
+ * mode,
40
+ * data: pointFeatureCollection,
41
+ * selectedFeatureIndexes: [0],
42
+ * onEdit: handleEdit,
43
+ * });
44
+ * ```
45
+ */
46
+ var PointTranslateMode = class extends GeoJsonEditMode {
47
+ translateMode = new TranslateMode();
48
+ /**
49
+ * Handle click events to reposition the point.
50
+ *
51
+ * If the click is on empty map space (not on the point itself),
52
+ * moves the point to the clicked location immediately.
53
+ *
54
+ * @param event - Click event containing map coordinates and pick information
55
+ * @param props - Mode props containing data, selected indexes, and edit callback
56
+ */
57
+ handleClick(event, props) {
58
+ if (event.picks?.some((pick) => pick.isGuide || pick.featureIndex !== void 0)) return;
59
+ const { mapCoords } = event;
60
+ const selectedIndex = props.selectedIndexes?.[0];
61
+ if (selectedIndex === void 0) return;
62
+ const feature = props.data.features[selectedIndex];
63
+ if (!feature) return;
64
+ const updatedFeature = {
65
+ ...feature,
66
+ geometry: {
67
+ type: "Point",
68
+ coordinates: mapCoords
69
+ }
70
+ };
71
+ props.onEdit({
72
+ updatedData: {
73
+ ...props.data,
74
+ features: [updatedFeature]
75
+ },
76
+ editType: "translated",
77
+ editContext: { featureIndexes: [selectedIndex] }
78
+ });
79
+ }
80
+ /**
81
+ * Delegate pointer move events to TranslateMode for cursor updates.
82
+ *
83
+ * @param event - Pointer move event with current cursor position
84
+ * @param props - Mode props containing state and configuration
85
+ */
86
+ handlePointerMove(event, props) {
87
+ this.translateMode.handlePointerMove(event, props);
88
+ }
89
+ /**
90
+ * Delegate start dragging to TranslateMode for traditional drag behavior.
91
+ *
92
+ * @param event - Drag start event with pointer down coordinates
93
+ * @param props - Mode props containing data and edit callback
94
+ */
95
+ handleStartDragging(event, props) {
96
+ this.translateMode.handleStartDragging(event, props);
97
+ }
98
+ /**
99
+ * Delegate dragging to TranslateMode for traditional drag behavior.
100
+ *
101
+ * @param event - Dragging event with current and previous pointer positions
102
+ * @param props - Mode props containing data and edit callback
103
+ */
104
+ handleDragging(event, props) {
105
+ this.translateMode.handleDragging(event, props);
106
+ }
107
+ /**
108
+ * Delegate stop dragging to TranslateMode for traditional drag behavior.
109
+ *
110
+ * @param event - Drag stop event with final pointer position
111
+ * @param props - Mode props containing data and edit callback
112
+ */
113
+ handleStopDragging(event, props) {
114
+ this.translateMode.handleStopDragging(event, props);
115
+ }
116
+ /**
117
+ * Delegate guide rendering to TranslateMode.
118
+ *
119
+ * @param props - Mode props containing data and selected indexes
120
+ * @returns Guide feature collection for rendering edit handles
121
+ */
122
+ getGuides(props) {
123
+ return this.translateMode.getGuides(props);
124
+ }
125
+ };
126
+
127
+ //#endregion
128
+ export { PointTranslateMode };
129
+ //# sourceMappingURL=point-translate-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"point-translate-mode.js","names":[],"sources":["../../../../../src/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.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\nimport {\n type ClickEvent,\n type DraggingEvent,\n type FeatureCollection,\n GeoJsonEditMode,\n type GuideFeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type StartDraggingEvent,\n type StopDraggingEvent,\n TranslateMode,\n} from '@deck.gl-community/editable-layers';\n\n/**\n * Edit mode for Point shapes that supports both click-to-place and drag behaviors.\n *\n * ## Capabilities\n * This mode provides two ways to reposition a point:\n * - **Click on empty space**: Instantly moves the point to the clicked location\n * - **Drag the point**: Traditional click-and-drag behavior (via TranslateMode)\n *\n * ## Behavior Details\n * - Clicking anywhere on the map (that isn't the point itself) repositions the point\n * - Clicking directly on the point and dragging works as traditional translation\n * - Both behaviors emit the 'translated' edit type for consistency with existing event handling\n *\n * @example\n * ```typescript\n * import { PointTranslateMode } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes/point-translate-mode';\n * import { EditableGeoJsonLayer } from '@deck.gl-community/editable-layers';\n *\n * // Used internally by EditShapeLayer for points\n * const mode = new PointTranslateMode();\n *\n * const layer = new EditableGeoJsonLayer({\n * mode,\n * data: pointFeatureCollection,\n * selectedFeatureIndexes: [0],\n * onEdit: handleEdit,\n * });\n * ```\n */\nexport class PointTranslateMode extends GeoJsonEditMode {\n private translateMode = new TranslateMode();\n\n /**\n * Handle click events to reposition the point.\n *\n * If the click is on empty map space (not on the point itself),\n * moves the point to the clicked location immediately.\n *\n * @param event - Click event containing map coordinates and pick information\n * @param props - Mode props containing data, selected indexes, and edit callback\n */\n override handleClick(\n event: ClickEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n // If clicked on the point itself or a guide, let drag handle it\n const clickedOnFeature = event.picks?.some(\n (pick) => pick.isGuide || pick.featureIndex !== undefined,\n );\n\n if (clickedOnFeature) {\n return;\n }\n\n const { mapCoords } = event;\n const selectedIndex = props.selectedIndexes?.[0];\n\n if (selectedIndex === undefined) {\n return;\n }\n\n const feature = props.data.features[selectedIndex];\n\n if (!feature) {\n return;\n }\n\n // Create updated feature with new coordinates\n const updatedFeature = {\n ...feature,\n geometry: {\n type: 'Point' as const,\n coordinates: mapCoords,\n },\n };\n\n // Emit edit action with 'translated' type to work with existing completion handlers\n props.onEdit({\n updatedData: {\n ...props.data,\n features: [updatedFeature],\n },\n editType: 'translated',\n editContext: {\n featureIndexes: [selectedIndex],\n },\n });\n }\n\n /**\n * Delegate pointer move events to TranslateMode for cursor updates.\n *\n * @param event - Pointer move event with current cursor position\n * @param props - Mode props containing state and configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handlePointerMove(event, props);\n }\n\n /**\n * Delegate start dragging to TranslateMode for traditional drag behavior.\n *\n * @param event - Drag start event with pointer down coordinates\n * @param props - Mode props containing data and edit callback\n */\n override handleStartDragging(\n event: StartDraggingEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handleStartDragging(event, props);\n }\n\n /**\n * Delegate dragging to TranslateMode for traditional drag behavior.\n *\n * @param event - Dragging event with current and previous pointer positions\n * @param props - Mode props containing data and edit callback\n */\n override handleDragging(\n event: DraggingEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handleDragging(event, props);\n }\n\n /**\n * Delegate stop dragging to TranslateMode for traditional drag behavior.\n *\n * @param event - Drag stop event with final pointer position\n * @param props - Mode props containing data and edit callback\n */\n override handleStopDragging(\n event: StopDraggingEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handleStopDragging(event, props);\n }\n\n /**\n * Delegate guide rendering to TranslateMode.\n *\n * @param props - Mode props containing data and selected indexes\n * @returns Guide feature collection for rendering edit handles\n */\n override getGuides(\n props: ModeProps<FeatureCollection>,\n ): GuideFeatureCollection {\n return this.translateMode.getGuides(props);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,IAAa,qBAAb,cAAwC,gBAAgB;CACtD,AAAQ,gBAAgB,IAAI,eAAe;;;;;;;;;;CAW3C,AAAS,YACP,OACA,OACM;AAMN,MAJyB,MAAM,OAAO,MACnC,SAAS,KAAK,WAAW,KAAK,iBAAiB,OACjD,CAGC;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBAAgB,MAAM,kBAAkB;AAE9C,MAAI,kBAAkB,OACpB;EAGF,MAAM,UAAU,MAAM,KAAK,SAAS;AAEpC,MAAI,CAAC,QACH;EAIF,MAAM,iBAAiB;GACrB,GAAG;GACH,UAAU;IACR,MAAM;IACN,aAAa;IACd;GACF;AAGD,QAAM,OAAO;GACX,aAAa;IACX,GAAG,MAAM;IACT,UAAU,CAAC,eAAe;IAC3B;GACD,UAAU;GACV,aAAa,EACX,gBAAgB,CAAC,cAAc,EAChC;GACF,CAAC;;;;;;;;CASJ,AAAS,kBACP,OACA,OACM;AACN,OAAK,cAAc,kBAAkB,OAAO,MAAM;;;;;;;;CASpD,AAAS,oBACP,OACA,OACM;AACN,OAAK,cAAc,oBAAoB,OAAO,MAAM;;;;;;;;CAStD,AAAS,eACP,OACA,OACM;AACN,OAAK,cAAc,eAAe,OAAO,MAAM;;;;;;;;CASjD,AAAS,mBACP,OACA,OACM;AACN,OAAK,cAAc,mBAAmB,OAAO,MAAM;;;;;;;;CASrD,AAAS,UACP,OACwB;AACxB,SAAO,KAAK,cAAc,UAAU,MAAM"}
@@ -11,8 +11,8 @@
11
11
  */
12
12
 
13
13
 
14
- import { ImmutableFeatureCollection, RotateMode } from "@deck.gl-community/editable-layers";
15
14
  import { bearing, centroid, transformRotate } from "@turf/turf";
15
+ import { ImmutableFeatureCollection, RotateMode } from "@deck.gl-community/editable-layers";
16
16
 
17
17
  //#region src/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.ts
18
18
  /** Snap interval in degrees (45° = 8 positions around the circle) */
@@ -15,10 +15,10 @@
15
15
 
16
16
  import { createMapStore } from "../../../shared/create-map-store.js";
17
17
  import { MapEvents } from "../../base-map/events.js";
18
- import { isCircleShape, isEllipseShape, isPointShape, isRectangleShape } from "../shared/types.js";
19
18
  import { releaseModeAndCursor, requestCursorChange, requestModeChange } from "../shared/utils/mode-utils.js";
20
- import { EditShapeEvents } from "./events.js";
19
+ import { isCircleShape, isEllipseShape, isPointShape, isRectangleShape } from "../shared/types.js";
21
20
  import { EDIT_CURSOR_MAP, EDIT_SHAPE_LAYER_ID, EDIT_SHAPE_MODE } from "./constants.js";
21
+ import { EditShapeEvents } from "./events.js";
22
22
  import { Broadcast } from "@accelint/bus";
23
23
  import { getLogger } from "@accelint/logger";
24
24
 
@@ -66,9 +66,12 @@ const DEFAULT_EDITING_STATE = {
66
66
  };
67
67
  /**
68
68
  * Determine the appropriate edit mode for a shape type
69
+ *
70
+ * @param shape - The shape to determine the edit mode for
71
+ * @returns The edit mode to use for this shape type
69
72
  */
70
73
  function getEditModeForShape(shape) {
71
- if (isPointShape(shape)) return "translate";
74
+ if (isPointShape(shape)) return "point-translate";
72
75
  if (isCircleShape(shape)) return "circle-transform";
73
76
  if (isEllipseShape(shape) || isRectangleShape(shape)) return "bounding-transform";
74
77
  return "vertex-transform";
@@ -177,6 +180,12 @@ const editStore = createMapStore({
177
180
  }
178
181
  });
179
182
  /**
183
+ * Manually clear editing state for a specific mapId.
184
+ */
185
+ function clearEditingState(mapId) {
186
+ editStore.clear(mapId);
187
+ }
188
+ /**
180
189
  * Update feature from the layer component (called during drag operations)
181
190
  */
182
191
  function updateFeatureFromLayer(mapId, feature) {
@@ -188,7 +197,13 @@ function updateFeatureFromLayer(mapId, feature) {
188
197
  function cancelEditingFromLayer(mapId) {
189
198
  editStore.actions(mapId).cancel();
190
199
  }
200
+ /**
201
+ * Save editing (called by the layer component on Enter)
202
+ */
203
+ function saveEditingFromLayer(mapId) {
204
+ editStore.actions(mapId).save();
205
+ }
191
206
 
192
207
  //#endregion
193
- export { cancelEditingFromLayer, editStore, updateFeatureFromLayer };
208
+ export { cancelEditingFromLayer, clearEditingState, editStore, saveEditingFromLayer, updateFeatureFromLayer };
194
209
  //# sourceMappingURL=store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","names":["DEFAULT_EDITING_STATE: EditingState"],"sources":["../../../../src/deckgl/shapes/edit-shape-layer/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'use client';\n\n/**\n * Edit Shape Store\n *\n * Manages editing state for shape modification.\n *\n * @example\n * ```typescript\n * import { editStore } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * function EditControls({ mapId }) {\n * const { state, edit, save, cancel } = editStore.use(mapId);\n *\n * return (\n * <div>\n * <p>Editing: {state.editingShape?.name ?? 'none'}</p>\n * <button onClick={save}>Save</button>\n * <button onClick={cancel}>Cancel</button>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { getLogger } from '@accelint/logger';\nimport { createMapStore } from '@/shared/create-map-store';\nimport { MapEvents } from '../../base-map/events';\nimport {\n isCircleShape,\n isEllipseShape,\n isPointShape,\n isRectangleShape,\n} from '../shared/types';\nimport {\n releaseModeAndCursor,\n requestCursorChange,\n requestModeChange,\n} from '../shared/utils/mode-utils';\nimport {\n EDIT_CURSOR_MAP,\n EDIT_SHAPE_LAYER_ID,\n EDIT_SHAPE_MODE,\n} from './constants';\nimport { EditShapeEvents } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { Feature } from 'geojson';\nimport type { MapEventType } from '../../base-map/types';\nimport type { Shape } from '../shared/types';\nimport type {\n EditShapeEvent,\n ShapeEditCanceledEvent,\n ShapeEditingEvent,\n ShapeUpdatedEvent,\n} from './events';\nimport type {\n EditFunction,\n EditingState,\n EditMode,\n EditShapeOptions,\n} from './types';\n\nconst logger = getLogger({\n enabled:\n process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test',\n level: 'warn',\n prefix: '[EditShapeLayer]',\n pretty: true,\n});\n\n/**\n * Typed event bus instances\n */\nconst editShapeBus = Broadcast.getInstance<EditShapeEvent>();\nconst mapEventBus = Broadcast.getInstance<MapEventType>();\n\n/**\n * Default editing state\n */\nconst DEFAULT_EDITING_STATE: EditingState = {\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n};\n\n/**\n * Actions for edit shape store\n */\ntype EditShapeActions = {\n /** Start editing a shape */\n edit: EditFunction;\n /** Save the current edits */\n save: () => void;\n /** Cancel editing */\n cancel: () => void;\n};\n\n/**\n * Determine the appropriate edit mode for a shape type\n */\nfunction getEditModeForShape(shape: Shape): EditMode {\n if (isPointShape(shape)) {\n return 'translate';\n }\n if (isCircleShape(shape)) {\n return 'circle-transform';\n }\n if (isEllipseShape(shape) || isRectangleShape(shape)) {\n return 'bounding-transform';\n }\n return 'vertex-transform';\n}\n\n/**\n * Start editing a shape\n */\nfunction startEditing(\n mapId: UniqueId,\n state: EditingState,\n shape: Shape,\n options: EditShapeOptions | undefined,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n // Prevent editing locked shapes\n if (shape.locked) {\n logger.warn(`Cannot edit locked shape: \"${shape.name}\"`);\n return;\n }\n\n // Already editing - cancel first\n if (state.editingShape) {\n cancelEditingInternal(mapId, state, notify, setState);\n }\n\n // Determine edit mode (can be overridden via options)\n const editMode = options?.mode ?? getEditModeForShape(shape);\n\n // Update state with new object reference\n setState({\n editingShape: shape,\n editMode,\n featureBeingEdited: shape.feature,\n });\n\n // Request map mode and cursor\n requestModeChange(mapId, EDIT_SHAPE_MODE, EDIT_SHAPE_LAYER_ID);\n const cursor = EDIT_CURSOR_MAP[editMode];\n requestCursorChange(mapId, cursor, EDIT_SHAPE_LAYER_ID);\n\n // Disable map panning during editing\n mapEventBus.emit(MapEvents.disablePan, { id: mapId });\n\n // Emit editing started event\n editShapeBus.emit(EditShapeEvents.editing, {\n shape,\n mapId,\n } as unknown as ShapeEditingEvent['payload']);\n\n notify();\n}\n\n/**\n * Save editing and create updated shape\n */\nfunction saveEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): Shape | null {\n if (!(state.editingShape && state.featureBeingEdited)) {\n return null;\n }\n\n const originalShape = state.editingShape;\n const updatedFeature = state.featureBeingEdited;\n\n // Create updated shape with new geometry\n const updatedShape = {\n ...originalShape,\n feature: {\n ...updatedFeature,\n properties: {\n ...originalShape.feature.properties,\n ...updatedFeature.properties,\n },\n },\n lastUpdated: Date.now(),\n } as Shape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit shape updated event\n editShapeBus.emit(EditShapeEvents.updated, {\n shape: updatedShape,\n mapId,\n } as unknown as ShapeUpdatedEvent['payload']);\n\n notify();\n\n return updatedShape;\n}\n\n/**\n * Cancel the current editing operation\n */\nfunction cancelEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n if (!state.editingShape) {\n return; // Nothing to cancel\n }\n\n const originalShape = state.editingShape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: originalShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n\n notify();\n}\n\n/**\n * Edit shape store\n */\nexport const editStore = createMapStore<EditingState, EditShapeActions>({\n defaultState: { ...DEFAULT_EDITING_STATE },\n\n actions: (mapId, { get, set, notify }) => ({\n edit: (shape: Shape, options?: EditShapeOptions) => {\n startEditing(mapId, get(), shape, options, notify, set);\n },\n\n save: () => {\n saveEditingInternal(mapId, get(), notify, set);\n },\n\n cancel: () => {\n cancelEditingInternal(mapId, get(), notify, set);\n },\n }),\n\n // Note: EditShapeLayer is \"neutral\" regarding mode change authorization.\n // It doesn't auto-cancel or reject mode changes - those decisions are\n // left to UI components that can prompt the user.\n\n onCleanup: (mapId, state) => {\n // Cancel any active editing before cleanup\n if (state.editingShape) {\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: state.editingShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n }\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get the current editing state for a mapId\n * Returns null if no store instance exists\n */\nexport function getEditingState(mapId: UniqueId): EditingState | null {\n if (!editStore.exists(mapId)) {\n return null;\n }\n return editStore.get(mapId);\n}\n\n/**\n * Hook for editing state\n */\nexport function useEditingState(\n mapId: UniqueId,\n): { state: EditingState } & EditShapeActions {\n return editStore.use(mapId);\n}\n\n/**\n * Manually clear editing state for a specific mapId.\n */\nexport function clearEditingState(mapId: UniqueId): void {\n editStore.clear(mapId);\n}\n\n/**\n * Update feature from the layer component (called during drag operations)\n */\nexport function updateFeatureFromLayer(\n mapId: UniqueId,\n feature: Feature,\n): void {\n editStore.set(mapId, { featureBeingEdited: feature });\n}\n\n/**\n * Cancel editing (called by the layer component on ESC)\n */\nexport function cancelEditingFromLayer(mapId: UniqueId): void {\n editStore.actions(mapId).cancel();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"store.js","names":["DEFAULT_EDITING_STATE: EditingState"],"sources":["../../../../src/deckgl/shapes/edit-shape-layer/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'use client';\n\n/**\n * Edit Shape Store\n *\n * Manages editing state for shape modification.\n *\n * @example\n * ```typescript\n * import { editStore } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * function EditControls({ mapId }) {\n * const { state, edit, save, cancel } = editStore.use(mapId);\n *\n * return (\n * <div>\n * <p>Editing: {state.editingShape?.name ?? 'none'}</p>\n * <button onClick={save}>Save</button>\n * <button onClick={cancel}>Cancel</button>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { getLogger } from '@accelint/logger';\nimport { createMapStore } from '@/shared/create-map-store';\nimport { MapEvents } from '../../base-map/events';\nimport {\n isCircleShape,\n isEllipseShape,\n isPointShape,\n isRectangleShape,\n} from '../shared/types';\nimport {\n releaseModeAndCursor,\n requestCursorChange,\n requestModeChange,\n} from '../shared/utils/mode-utils';\nimport {\n EDIT_CURSOR_MAP,\n EDIT_SHAPE_LAYER_ID,\n EDIT_SHAPE_MODE,\n} from './constants';\nimport { EditShapeEvents } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { Feature } from 'geojson';\nimport type { MapEventType } from '../../base-map/types';\nimport type { Shape } from '../shared/types';\nimport type {\n EditShapeEvent,\n ShapeEditCanceledEvent,\n ShapeEditingEvent,\n ShapeUpdatedEvent,\n} from './events';\nimport type {\n EditFunction,\n EditingState,\n EditMode,\n EditShapeOptions,\n} from './types';\n\nconst logger = getLogger({\n enabled:\n process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test',\n level: 'warn',\n prefix: '[EditShapeLayer]',\n pretty: true,\n});\n\n/**\n * Typed event bus instances\n */\nconst editShapeBus = Broadcast.getInstance<EditShapeEvent>();\nconst mapEventBus = Broadcast.getInstance<MapEventType>();\n\n/**\n * Default editing state\n */\nconst DEFAULT_EDITING_STATE: EditingState = {\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n};\n\n/**\n * Actions for edit shape store\n */\ntype EditShapeActions = {\n /** Start editing a shape */\n edit: EditFunction;\n /** Save the current edits */\n save: () => void;\n /** Cancel editing */\n cancel: () => void;\n};\n\n/**\n * Determine the appropriate edit mode for a shape type\n *\n * @param shape - The shape to determine the edit mode for\n * @returns The edit mode to use for this shape type\n */\nfunction getEditModeForShape(shape: Shape): EditMode {\n if (isPointShape(shape)) {\n return 'point-translate';\n }\n if (isCircleShape(shape)) {\n return 'circle-transform';\n }\n if (isEllipseShape(shape) || isRectangleShape(shape)) {\n return 'bounding-transform';\n }\n return 'vertex-transform';\n}\n\n/**\n * Start editing a shape\n */\nfunction startEditing(\n mapId: UniqueId,\n state: EditingState,\n shape: Shape,\n options: EditShapeOptions | undefined,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n // Prevent editing locked shapes\n if (shape.locked) {\n logger.warn(`Cannot edit locked shape: \"${shape.name}\"`);\n return;\n }\n\n // Already editing - cancel first\n if (state.editingShape) {\n cancelEditingInternal(mapId, state, notify, setState);\n }\n\n // Determine edit mode (can be overridden via options)\n const editMode = options?.mode ?? getEditModeForShape(shape);\n\n // Update state with new object reference\n setState({\n editingShape: shape,\n editMode,\n featureBeingEdited: shape.feature,\n });\n\n // Request map mode and cursor\n requestModeChange(mapId, EDIT_SHAPE_MODE, EDIT_SHAPE_LAYER_ID);\n const cursor = EDIT_CURSOR_MAP[editMode];\n requestCursorChange(mapId, cursor, EDIT_SHAPE_LAYER_ID);\n\n // Disable map panning during editing\n mapEventBus.emit(MapEvents.disablePan, { id: mapId });\n\n // Emit editing started event\n editShapeBus.emit(EditShapeEvents.editing, {\n shape,\n mapId,\n } as unknown as ShapeEditingEvent['payload']);\n\n notify();\n}\n\n/**\n * Save editing and create updated shape\n */\nfunction saveEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): Shape | null {\n if (!(state.editingShape && state.featureBeingEdited)) {\n return null;\n }\n\n const originalShape = state.editingShape;\n const updatedFeature = state.featureBeingEdited;\n\n // Create updated shape with new geometry\n const updatedShape = {\n ...originalShape,\n feature: {\n ...updatedFeature,\n properties: {\n ...originalShape.feature.properties,\n ...updatedFeature.properties,\n },\n },\n lastUpdated: Date.now(),\n } as Shape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit shape updated event\n editShapeBus.emit(EditShapeEvents.updated, {\n shape: updatedShape,\n mapId,\n } as unknown as ShapeUpdatedEvent['payload']);\n\n notify();\n\n return updatedShape;\n}\n\n/**\n * Cancel the current editing operation\n */\nfunction cancelEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n if (!state.editingShape) {\n return; // Nothing to cancel\n }\n\n const originalShape = state.editingShape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: originalShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n\n notify();\n}\n\n/**\n * Edit shape store\n */\nexport const editStore = createMapStore<EditingState, EditShapeActions>({\n defaultState: { ...DEFAULT_EDITING_STATE },\n\n actions: (mapId, { get, set, notify }) => ({\n edit: (shape: Shape, options?: EditShapeOptions) => {\n startEditing(mapId, get(), shape, options, notify, set);\n },\n\n save: () => {\n saveEditingInternal(mapId, get(), notify, set);\n },\n\n cancel: () => {\n cancelEditingInternal(mapId, get(), notify, set);\n },\n }),\n\n // Note: EditShapeLayer is \"neutral\" regarding mode change authorization.\n // It doesn't auto-cancel or reject mode changes - those decisions are\n // left to UI components that can prompt the user.\n\n onCleanup: (mapId, state) => {\n // Cancel any active editing before cleanup\n if (state.editingShape) {\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: state.editingShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n }\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get the current editing state for a mapId\n * Returns null if no store instance exists\n */\nexport function getEditingState(mapId: UniqueId): EditingState | null {\n if (!editStore.exists(mapId)) {\n return null;\n }\n return editStore.get(mapId);\n}\n\n/**\n * Hook for editing state\n */\nexport function useEditingState(\n mapId: UniqueId,\n): { state: EditingState } & EditShapeActions {\n return editStore.use(mapId);\n}\n\n/**\n * Manually clear editing state for a specific mapId.\n */\nexport function clearEditingState(mapId: UniqueId): void {\n editStore.clear(mapId);\n}\n\n/**\n * Update feature from the layer component (called during drag operations)\n */\nexport function updateFeatureFromLayer(\n mapId: UniqueId,\n feature: Feature,\n): void {\n editStore.set(mapId, { featureBeingEdited: feature });\n}\n\n/**\n * Cancel editing (called by the layer component on ESC)\n */\nexport function cancelEditingFromLayer(mapId: UniqueId): void {\n editStore.actions(mapId).cancel();\n}\n\n/**\n * Save editing (called by the layer component on Enter)\n */\nexport function saveEditingFromLayer(mapId: UniqueId): void {\n editStore.actions(mapId).save();\n}\n"],"mappings":"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"}
@@ -22,9 +22,10 @@ import { Feature } from "geojson";
22
22
  * - 'bounding-transform': Scale/rotate/translate via bounding box handles (ellipses, rectangles)
23
23
  * - 'vertex-transform': Drag vertices OR scale/rotate/translate (polygons, lines)
24
24
  * - 'circle-transform': Drag edge to resize, drag body to translate (circles)
25
- * - 'translate': Drag to move the shape (points)
25
+ * - 'translate': Drag to move the shape (generic translation)
26
+ * - 'point-translate': Click to place OR drag to move (points)
26
27
  */
27
- type EditMode = 'view' | 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate';
28
+ type EditMode = 'view' | 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate' | 'point-translate';
28
29
  /**
29
30
  * State for the editing store
30
31
  */
@@ -41,7 +42,7 @@ type EditingState = {
41
42
  */
42
43
  type EditShapeOptions = {
43
44
  /** Override the default edit mode (auto-detected from shape type by default) */
44
- mode?: 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate';
45
+ mode?: 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate' | 'point-translate';
45
46
  };
46
47
  /**
47
48
  * Options for the useEditShape hook
@@ -13,9 +13,9 @@
13
13
 
14
14
  'use client';
15
15
 
16
- import { MapContext } from "../../base-map/provider.js";
17
16
  import { EditShapeEvents } from "./events.js";
18
17
  import { editStore } from "./store.js";
18
+ import { MapContext } from "../../base-map/provider.js";
19
19
  import { useContext, useMemo } from "react";
20
20
  import { useBus } from "@accelint/bus/react";
21
21
 
@@ -11,16 +11,16 @@
11
11
  */
12
12
 
13
13
 
14
- import { BASE_FILL_OPACITY, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_EDIT_HANDLE_COLOR, DEFAULT_EDIT_HANDLE_OUTLINE_COLOR, DEFAULT_STYLE_PROPERTIES, LINE_PATTERNS, LINE_WIDTHS, SHAPE_LAYER_IDS } from "./shared/constants.js";
15
14
  import { ShapeEvents } from "./shared/events.js";
16
- import { getDashArray, getFillColor, getLineColor, getLineWidth, normalizeColor } from "./shared/utils/style-utils.js";
17
15
  import { ShapeFeatureType, isCircleShape, isEllipseShape, isLineStringShape, isPointShape, isPolygonShape, isRectangleShape } from "./shared/types.js";
16
+ import { DrawShapeEvents } from "./draw-shape-layer/events.js";
17
+ import { BASE_FILL_OPACITY, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_EDIT_HANDLE_COLOR, DEFAULT_EDIT_HANDLE_OUTLINE_COLOR, DEFAULT_STYLE_PROPERTIES, LINE_PATTERNS, LINE_WIDTHS, SHAPE_LAYER_IDS } from "./shared/constants.js";
18
+ import { EditShapeEvents } from "./edit-shape-layer/events.js";
19
+ import { getDashArray, getFillColor, getLineColor, getLineWidth, normalizeColor } from "./shared/utils/style-utils.js";
18
20
  import { DisplayShapeLayer } from "./display-shape-layer/index.js";
19
21
  import { useSelectShape } from "./display-shape-layer/use-select-shape.js";
20
- import { DrawShapeEvents } from "./draw-shape-layer/events.js";
21
22
  import { DrawShapeLayer } from "./draw-shape-layer/index.js";
22
23
  import { useDrawShape } from "./draw-shape-layer/use-draw-shape.js";
23
- import { EditShapeEvents } from "./edit-shape-layer/events.js";
24
24
  import { EditShapeLayer } from "./edit-shape-layer/index.js";
25
25
  import { useEditShape } from "./edit-shape-layer/use-edit-shape.js";
26
26
 
@@ -200,15 +200,15 @@ function formatDistance(value) {
200
200
  return value.toFixed(2);
201
201
  }
202
202
  /**
203
- * Format circle tooltip text showing diameter and area.
203
+ * Format circle tooltip text showing radius and area.
204
204
  *
205
- * @param diameter - Circle diameter in the specified units
205
+ * @param radius - Circle radius in the specified units
206
206
  * @param area - Circle area in the specified units squared
207
207
  * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')
208
- * @returns Formatted tooltip text: "d: {diameter} {unit}\n{area} {unit}²"
208
+ * @returns Formatted tooltip text: "r: {radius} {unit}\n{area} {unit}²"
209
209
  */
210
- function formatCircleTooltip(diameter, area, unitAbbrev) {
211
- return `d: ${formatDistance(diameter)} ${unitAbbrev}\n${formatDistance(area)} ${unitAbbrev}²`;
210
+ function formatCircleTooltip(radius, area, unitAbbrev) {
211
+ return `r: ${formatDistance(radius)} ${unitAbbrev}\n${formatDistance(area)} ${unitAbbrev}²`;
212
212
  }
213
213
  /**
214
214
  * Format rectangle tooltip text showing dimensions and area.
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","names":["DEFAULT_STYLE_PROPERTIES: StyleProperties","DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n>","DEFAULT_EDIT_HANDLE_COLOR: Color","DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color","EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection","TOOLTIP_CHARACTER_SET: string[]"],"sources":["../../../../src/deckgl/shapes/shared/constants.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'use client';\n\nimport { DEFAULT_TEXT_STYLE } from '../../text-settings';\nimport type { Color } from '@deck.gl/core';\nimport type { StyleProperties } from './types';\n\n/**\n * Layer IDs for shape layers\n */\nexport const SHAPE_LAYER_IDS = {\n DISPLAY: 'DISPLAY_SHAPES',\n DISPLAY_HIGHLIGHT: 'DISPLAY_SHAPES::Highlight',\n DISPLAY_LABELS: 'DISPLAY_SHAPES::Labels',\n} as const;\n\n/**\n * Base fill opacity multiplier for standard semi-transparent look.\n * Multiplies alpha by 0.2 (reduces to 20% of original opacity).\n */\nexport const BASE_FILL_OPACITY = 0.2;\n\n/**\n * Default border/outline width in pixels when not specified in styleProperties\n */\nexport const DEFAULT_LINE_WIDTH = 2;\n\n/**\n * Additional pixels added to border/outline width on hover\n */\nexport const HOVER_WIDTH_INCREASE = 2;\n\n/**\n * Additional pixels added to border/outline width for selection highlight\n */\nexport const HIGHLIGHT_WIDTH_INCREASE = 5;\n\n/**\n * Fixed opacity for label background (0-255)\n */\nexport const LABEL_BACKGROUND_OPACITY = 200;\n\n/**\n * Fixed opacity for label border (0-255)\n */\nexport const LABEL_BORDER_OPACITY = 255;\n\n/**\n * Default colors as RGBA arrays for DeckGL layers.\n *\n * These are the canonical color values used throughout the shapes system.\n * All other color constants should derive from these to maintain consistency.\n */\nexport const DEFAULT_COLORS = {\n /** Default fill color (white at full alpha) */\n fill: [255, 255, 255, 255] as Color,\n /** Default border/outline color (outline-interactive-hover: #888a8f) */\n line: [136, 138, 143, 255] as Color,\n /** Highlight/selection color (turquoise at ~39% alpha) */\n highlight: [40, 245, 190, 100] as Color,\n} as const;\n\n/**\n * Tentative (during-drawing) colors.\n *\n * These colors are used for the shape preview while drawing.\n * Fill is semi-transparent (8% opacity) to not obscure underlying features.\n * Border/outline uses the same color as saved shapes for consistency.\n */\nexport const DEFAULT_TENTATIVE_COLORS = {\n /** Tentative fill color (white at 8% opacity: 0.08 * 255 ≈ 20) */\n fill: [255, 255, 255, 20] as Color,\n /** Tentative border/outline color (same as saved shapes for consistency) */\n line: DEFAULT_COLORS.line,\n} as const;\n\n/**\n * Default style properties for saved shapes.\n *\n * These are applied when a shape is completed/saved.\n * Can be overridden via styleDefaults in draw options.\n */\nexport const DEFAULT_STYLE_PROPERTIES: StyleProperties = {\n fillColor: DEFAULT_COLORS.fill,\n lineColor: DEFAULT_COLORS.line,\n lineWidth: 2,\n linePattern: 'solid',\n};\n\n/**\n * Border/outline width options (in pixels)\n */\nexport const LINE_WIDTHS = [1, 2, 4, 8] as const;\n\n/**\n * Border/outline pattern options\n */\nexport const LINE_PATTERNS = ['solid', 'dashed', 'dotted'] as const;\n\n/**\n * Dash array patterns for border/outline rendering\n */\nexport const DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n> = {\n solid: null,\n dashed: [8, 4],\n dotted: [2, 4],\n};\n\n/**\n * Default tentative fill color (white at 8% opacity - rgba(255, 255, 255, 0.08))\n * Used when drawing new shapes before they're completed.\n * 0.08 * 255 ≈ 20\n */\nexport const DEFAULT_TENTATIVE_FILL_COLOR: Color = [255, 255, 255, 20];\n\n/**\n * Default tentative border/outline color (outline-interactive-hover: #888a8f)\n * Used when drawing new shapes before they're completed.\n */\nexport const DEFAULT_TENTATIVE_LINE_COLOR: Color = [136, 138, 143, 255];\n\n/**\n * Default edit handle color (white) - used by both draw and edit layers\n */\nexport const DEFAULT_EDIT_HANDLE_COLOR: Color = [255, 255, 255, 255];\n\n/**\n * Edit handle outline color (dark for contrast)\n */\nexport const DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color = [0, 0, 0, 200];\n\n/**\n * Empty feature collection for initializing editable layers\n */\nexport const EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection = {\n type: 'FeatureCollection',\n features: [],\n};\n\n/**\n * Custom character set for deck.gl TextLayer used by tooltip rendering.\n *\n * deck.gl's TextLayer uses SDF (Signed Distance Field) font rendering which\n * by default only supports basic ASCII characters (32-128). Special characters\n * like degree symbol (°) and superscript 2 (²) must be explicitly included\n * for tooltip text like \"100.5 km²\" to render correctly.\n */\nexport const TOOLTIP_CHARACTER_SET: string[] = ['°', '²'];\n\n// Add standard ASCII characters (space through tilde + DEL)\nfor (let i = 32; i <= 128; i++) {\n TOOLTIP_CHARACTER_SET.push(String.fromCharCode(i));\n}\n\n/**\n * Sublayer props for tooltip text rendering.\n * Used by both draw-shape-layer and edit-shape-layer for area/distance tooltips.\n */\nexport const TOOLTIP_SUBLAYER_PROPS = {\n tooltips: {\n ...DEFAULT_TEXT_STYLE,\n fontFamily: 'Roboto MonoVariable, monospace',\n characterSet: TOOLTIP_CHARACTER_SET,\n getTextAnchor: 'start',\n getAlignmentBaseline: 'bottom',\n getPixelOffset: [8, 0],\n },\n};\n\n/**\n * Shared edit handle sublayer props for EditableGeoJsonLayer.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDIT_HANDLE_SUBLAYER_PROPS = {\n editHandlePointOutline: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 6,\n },\n editHandlePoint: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 4,\n },\n};\n\n/**\n * Combined sublayer props for EditableGeoJsonLayer with tooltips and edit handles.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDITABLE_LAYER_SUBLAYER_PROPS = {\n ...TOOLTIP_SUBLAYER_PROPS,\n ...EDIT_HANDLE_SUBLAYER_PROPS,\n};\n\n/**\n * Format a distance value for tooltip display.\n * Used by draw and edit mode tooltips for consistent formatting.\n *\n * @param value - The distance value to format\n * @returns The formatted string with 2 decimal places\n */\nexport function formatDistance(value: number): string {\n return value.toFixed(2);\n}\n\n// =============================================================================\n// Tooltip Text Formatters\n// =============================================================================\n// These functions generate consistent tooltip text for both draw and edit modes.\n\n/**\n * Format circle tooltip text showing diameter and area.\n *\n * @param diameter - Circle diameter in the specified units\n * @param area - Circle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"d: {diameter} {unit}\\n{area} {unit}²\"\n */\nexport function formatCircleTooltip(\n diameter: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `d: ${formatDistance(diameter)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format rectangle tooltip text showing dimensions and area.\n *\n * @param width - Rectangle width in the specified units\n * @param height - Rectangle height in the specified units\n * @param area - Rectangle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{width} {unit} x {height} {unit}\\n{area} {unit}²\"\n */\nexport function formatRectangleTooltip(\n width: number,\n height: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(width)} ${unitAbbrev} x ${formatDistance(height)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format ellipse tooltip text showing axes and area.\n *\n * @param majorAxis - Ellipse major axis (full length) in the specified units\n * @param minorAxis - Ellipse minor axis (full length) in the specified units\n * @param area - Ellipse area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{major} {unit} x {minor} {unit}\\n{area} {unit}²\"\n */\nexport function formatEllipseTooltip(\n majorAxis: number,\n minorAxis: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(majorAxis)} ${unitAbbrev} x ${formatDistance(minorAxis)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format simple distance tooltip text.\n *\n * @param distance - Distance value in the specified units\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{distance} {unit}\"\n */\nexport function formatDistanceTooltip(\n distance: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(distance)} ${unitAbbrev}`;\n}\n\n// =============================================================================\n// Edit Event Type Classification\n// =============================================================================\n\n/**\n * Continuous edit event types that fire during dragging.\n * These are emitted repeatedly while the user drags during an edit operation.\n */\nexport const CONTINUOUS_EDIT_TYPES = new Set([\n 'movePosition',\n 'unionGeometry',\n 'scaling',\n 'rotating',\n 'translating',\n]);\n\n/**\n * Completion edit event types that fire when dragging ends.\n * These are emitted once when the user finishes an edit action.\n */\nexport const COMPLETION_EDIT_TYPES = new Set([\n 'finishMovePosition',\n 'addPosition',\n 'removePosition',\n 'scaled',\n 'rotated',\n 'translated',\n]);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBAAkB;CAC7B,SAAS;CACT,mBAAmB;CACnB,gBAAgB;CACjB;;;;;AAMD,MAAa,oBAAoB;;;;AAKjC,MAAa,qBAAqB;;;;AAKlC,MAAa,uBAAuB;;;;AAKpC,MAAa,2BAA2B;;;;;;;AAkBxC,MAAa,iBAAiB;CAE5B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,WAAW;EAAC;EAAI;EAAK;EAAK;EAAI;CAC/B;;;;;;;;AASD,MAAa,2BAA2B;CAEtC,MAAM;EAAC;EAAK;EAAK;EAAK;EAAG;CAEzB,MAAM,eAAe;CACtB;;;;;;;AAQD,MAAaA,2BAA4C;CACvD,WAAW,eAAe;CAC1B,WAAW,eAAe;CAC1B,WAAW;CACX,aAAa;CACd;;;;AAKD,MAAa,cAAc;CAAC;CAAG;CAAG;CAAG;CAAE;;;;AAKvC,MAAa,gBAAgB;CAAC;CAAS;CAAU;CAAS;;;;AAK1D,MAAaC,cAGT;CACF,OAAO;CACP,QAAQ,CAAC,GAAG,EAAE;CACd,QAAQ,CAAC,GAAG,EAAE;CACf;;;;AAkBD,MAAaC,4BAAmC;CAAC;CAAK;CAAK;CAAK;CAAI;;;;AAKpE,MAAaC,oCAA2C;CAAC;CAAG;CAAG;CAAG;CAAI;;;;AAKtE,MAAaC,2BAAgE;CAC3E,MAAM;CACN,UAAU,EAAE;CACb;;;;;;;;;AAUD,MAAaC,wBAAkC,CAAC,KAAK,IAAI;AAGzD,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,IACzB,uBAAsB,KAAK,OAAO,aAAa,EAAE,CAAC;;;;;AAOpD,MAAa,yBAAyB,EACpC,UAAU;CACR,GAAG;CACH,YAAY;CACZ,cAAc;CACd,eAAe;CACf,sBAAsB;CACtB,gBAAgB,CAAC,GAAG,EAAE;CACvB,EACF;;;;;AAMD,MAAa,6BAA6B;CACxC,wBAAwB;EACtB,cAAc;EACd,WAAW;EACZ;CACD,iBAAiB;EACf,cAAc;EACd,WAAW;EACZ;CACF;;;;;AAMD,MAAa,gCAAgC;CAC3C,GAAG;CACH,GAAG;CACJ;;;;;;;;AASD,SAAgB,eAAe,OAAuB;AACpD,QAAO,MAAM,QAAQ,EAAE;;;;;;;;;;AAgBzB,SAAgB,oBACd,UACA,MACA,YACQ;AACR,QAAO,MAAM,eAAe,SAAS,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAY7F,SAAgB,uBACd,OACA,QACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,MAAM,CAAC,GAAG,WAAW,KAAK,eAAe,OAAO,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAYjI,SAAgB,qBACd,WACA,WACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,UAAU,CAAC,GAAG,WAAW,KAAK,eAAe,UAAU,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;AAUxI,SAAgB,sBACd,UACA,YACQ;AACR,QAAO,GAAG,eAAe,SAAS,CAAC,GAAG;;;;;;AAWxC,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;AAMF,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACA;CACD,CAAC"}
1
+ {"version":3,"file":"constants.js","names":["DEFAULT_STYLE_PROPERTIES: StyleProperties","DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n>","DEFAULT_EDIT_HANDLE_COLOR: Color","DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color","EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection","TOOLTIP_CHARACTER_SET: string[]"],"sources":["../../../../src/deckgl/shapes/shared/constants.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'use client';\n\nimport { DEFAULT_TEXT_STYLE } from '../../text-settings';\nimport type { Color } from '@deck.gl/core';\nimport type { StyleProperties } from './types';\n\n/**\n * Layer IDs for shape layers\n */\nexport const SHAPE_LAYER_IDS = {\n DISPLAY: 'DISPLAY_SHAPES',\n DISPLAY_HIGHLIGHT: 'DISPLAY_SHAPES::Highlight',\n DISPLAY_LABELS: 'DISPLAY_SHAPES::Labels',\n} as const;\n\n/**\n * Base fill opacity multiplier for standard semi-transparent look.\n * Multiplies alpha by 0.2 (reduces to 20% of original opacity).\n */\nexport const BASE_FILL_OPACITY = 0.2;\n\n/**\n * Default border/outline width in pixels when not specified in styleProperties\n */\nexport const DEFAULT_LINE_WIDTH = 2;\n\n/**\n * Additional pixels added to border/outline width on hover\n */\nexport const HOVER_WIDTH_INCREASE = 2;\n\n/**\n * Additional pixels added to border/outline width for selection highlight\n */\nexport const HIGHLIGHT_WIDTH_INCREASE = 5;\n\n/**\n * Fixed opacity for label background (0-255)\n */\nexport const LABEL_BACKGROUND_OPACITY = 200;\n\n/**\n * Fixed opacity for label border (0-255)\n */\nexport const LABEL_BORDER_OPACITY = 255;\n\n/**\n * Default colors as RGBA arrays for DeckGL layers.\n *\n * These are the canonical color values used throughout the shapes system.\n * All other color constants should derive from these to maintain consistency.\n */\nexport const DEFAULT_COLORS = {\n /** Default fill color (white at full alpha) */\n fill: [255, 255, 255, 255] as Color,\n /** Default border/outline color (outline-interactive-hover: #888a8f) */\n line: [136, 138, 143, 255] as Color,\n /** Highlight/selection color (turquoise at ~39% alpha) */\n highlight: [40, 245, 190, 100] as Color,\n} as const;\n\n/**\n * Tentative (during-drawing) colors.\n *\n * These colors are used for the shape preview while drawing.\n * Fill is semi-transparent (8% opacity) to not obscure underlying features.\n * Border/outline uses the same color as saved shapes for consistency.\n */\nexport const DEFAULT_TENTATIVE_COLORS = {\n /** Tentative fill color (white at 8% opacity: 0.08 * 255 ≈ 20) */\n fill: [255, 255, 255, 20] as Color,\n /** Tentative border/outline color (same as saved shapes for consistency) */\n line: DEFAULT_COLORS.line,\n} as const;\n\n/**\n * Default style properties for saved shapes.\n *\n * These are applied when a shape is completed/saved.\n * Can be overridden via styleDefaults in draw options.\n */\nexport const DEFAULT_STYLE_PROPERTIES: StyleProperties = {\n fillColor: DEFAULT_COLORS.fill,\n lineColor: DEFAULT_COLORS.line,\n lineWidth: 2,\n linePattern: 'solid',\n};\n\n/**\n * Border/outline width options (in pixels)\n */\nexport const LINE_WIDTHS = [1, 2, 4, 8] as const;\n\n/**\n * Border/outline pattern options\n */\nexport const LINE_PATTERNS = ['solid', 'dashed', 'dotted'] as const;\n\n/**\n * Dash array patterns for border/outline rendering\n */\nexport const DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n> = {\n solid: null,\n dashed: [8, 4],\n dotted: [2, 4],\n};\n\n/**\n * Default tentative fill color (white at 8% opacity - rgba(255, 255, 255, 0.08))\n * Used when drawing new shapes before they're completed.\n * 0.08 * 255 ≈ 20\n */\nexport const DEFAULT_TENTATIVE_FILL_COLOR: Color = [255, 255, 255, 20];\n\n/**\n * Default tentative border/outline color (outline-interactive-hover: #888a8f)\n * Used when drawing new shapes before they're completed.\n */\nexport const DEFAULT_TENTATIVE_LINE_COLOR: Color = [136, 138, 143, 255];\n\n/**\n * Default edit handle color (white) - used by both draw and edit layers\n */\nexport const DEFAULT_EDIT_HANDLE_COLOR: Color = [255, 255, 255, 255];\n\n/**\n * Edit handle outline color (dark for contrast)\n */\nexport const DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color = [0, 0, 0, 200];\n\n/**\n * Empty feature collection for initializing editable layers\n */\nexport const EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection = {\n type: 'FeatureCollection',\n features: [],\n};\n\n/**\n * Custom character set for deck.gl TextLayer used by tooltip rendering.\n *\n * deck.gl's TextLayer uses SDF (Signed Distance Field) font rendering which\n * by default only supports basic ASCII characters (32-128). Special characters\n * like degree symbol (°) and superscript 2 (²) must be explicitly included\n * for tooltip text like \"100.5 km²\" to render correctly.\n */\nexport const TOOLTIP_CHARACTER_SET: string[] = ['°', '²'];\n\n// Add standard ASCII characters (space through tilde + DEL)\nfor (let i = 32; i <= 128; i++) {\n TOOLTIP_CHARACTER_SET.push(String.fromCharCode(i));\n}\n\n/**\n * Sublayer props for tooltip text rendering.\n * Used by both draw-shape-layer and edit-shape-layer for area/distance tooltips.\n */\nexport const TOOLTIP_SUBLAYER_PROPS = {\n tooltips: {\n ...DEFAULT_TEXT_STYLE,\n fontFamily: 'Roboto MonoVariable, monospace',\n characterSet: TOOLTIP_CHARACTER_SET,\n getTextAnchor: 'start',\n getAlignmentBaseline: 'bottom',\n getPixelOffset: [8, 0],\n },\n};\n\n/**\n * Shared edit handle sublayer props for EditableGeoJsonLayer.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDIT_HANDLE_SUBLAYER_PROPS = {\n editHandlePointOutline: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 6,\n },\n editHandlePoint: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 4,\n },\n};\n\n/**\n * Combined sublayer props for EditableGeoJsonLayer with tooltips and edit handles.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDITABLE_LAYER_SUBLAYER_PROPS = {\n ...TOOLTIP_SUBLAYER_PROPS,\n ...EDIT_HANDLE_SUBLAYER_PROPS,\n};\n\n/**\n * Format a distance value for tooltip display.\n * Used by draw and edit mode tooltips for consistent formatting.\n *\n * @param value - The distance value to format\n * @returns The formatted string with 2 decimal places\n */\nexport function formatDistance(value: number): string {\n return value.toFixed(2);\n}\n\n// =============================================================================\n// Tooltip Text Formatters\n// =============================================================================\n// These functions generate consistent tooltip text for both draw and edit modes.\n\n/**\n * Format circle tooltip text showing radius and area.\n *\n * @param radius - Circle radius in the specified units\n * @param area - Circle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"r: {radius} {unit}\\n{area} {unit}²\"\n */\nexport function formatCircleTooltip(\n radius: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `r: ${formatDistance(radius)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format rectangle tooltip text showing dimensions and area.\n *\n * @param width - Rectangle width in the specified units\n * @param height - Rectangle height in the specified units\n * @param area - Rectangle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{width} {unit} x {height} {unit}\\n{area} {unit}²\"\n */\nexport function formatRectangleTooltip(\n width: number,\n height: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(width)} ${unitAbbrev} x ${formatDistance(height)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format ellipse tooltip text showing axes and area.\n *\n * @param majorAxis - Ellipse major axis (full length) in the specified units\n * @param minorAxis - Ellipse minor axis (full length) in the specified units\n * @param area - Ellipse area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{major} {unit} x {minor} {unit}\\n{area} {unit}²\"\n */\nexport function formatEllipseTooltip(\n majorAxis: number,\n minorAxis: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(majorAxis)} ${unitAbbrev} x ${formatDistance(minorAxis)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format simple distance tooltip text.\n *\n * @param distance - Distance value in the specified units\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{distance} {unit}\"\n */\nexport function formatDistanceTooltip(\n distance: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(distance)} ${unitAbbrev}`;\n}\n\n// =============================================================================\n// Edit Event Type Classification\n// =============================================================================\n\n/**\n * Continuous edit event types that fire during dragging.\n * These are emitted repeatedly while the user drags during an edit operation.\n */\nexport const CONTINUOUS_EDIT_TYPES = new Set([\n 'movePosition',\n 'unionGeometry',\n 'scaling',\n 'rotating',\n 'translating',\n]);\n\n/**\n * Completion edit event types that fire when dragging ends.\n * These are emitted once when the user finishes an edit action.\n */\nexport const COMPLETION_EDIT_TYPES = new Set([\n 'finishMovePosition',\n 'addPosition',\n 'removePosition',\n 'scaled',\n 'rotated',\n 'translated',\n]);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBAAkB;CAC7B,SAAS;CACT,mBAAmB;CACnB,gBAAgB;CACjB;;;;;AAMD,MAAa,oBAAoB;;;;AAKjC,MAAa,qBAAqB;;;;AAKlC,MAAa,uBAAuB;;;;AAKpC,MAAa,2BAA2B;;;;;;;AAkBxC,MAAa,iBAAiB;CAE5B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,WAAW;EAAC;EAAI;EAAK;EAAK;EAAI;CAC/B;;;;;;;;AASD,MAAa,2BAA2B;CAEtC,MAAM;EAAC;EAAK;EAAK;EAAK;EAAG;CAEzB,MAAM,eAAe;CACtB;;;;;;;AAQD,MAAaA,2BAA4C;CACvD,WAAW,eAAe;CAC1B,WAAW,eAAe;CAC1B,WAAW;CACX,aAAa;CACd;;;;AAKD,MAAa,cAAc;CAAC;CAAG;CAAG;CAAG;CAAE;;;;AAKvC,MAAa,gBAAgB;CAAC;CAAS;CAAU;CAAS;;;;AAK1D,MAAaC,cAGT;CACF,OAAO;CACP,QAAQ,CAAC,GAAG,EAAE;CACd,QAAQ,CAAC,GAAG,EAAE;CACf;;;;AAkBD,MAAaC,4BAAmC;CAAC;CAAK;CAAK;CAAK;CAAI;;;;AAKpE,MAAaC,oCAA2C;CAAC;CAAG;CAAG;CAAG;CAAI;;;;AAKtE,MAAaC,2BAAgE;CAC3E,MAAM;CACN,UAAU,EAAE;CACb;;;;;;;;;AAUD,MAAaC,wBAAkC,CAAC,KAAK,IAAI;AAGzD,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,IACzB,uBAAsB,KAAK,OAAO,aAAa,EAAE,CAAC;;;;;AAOpD,MAAa,yBAAyB,EACpC,UAAU;CACR,GAAG;CACH,YAAY;CACZ,cAAc;CACd,eAAe;CACf,sBAAsB;CACtB,gBAAgB,CAAC,GAAG,EAAE;CACvB,EACF;;;;;AAMD,MAAa,6BAA6B;CACxC,wBAAwB;EACtB,cAAc;EACd,WAAW;EACZ;CACD,iBAAiB;EACf,cAAc;EACd,WAAW;EACZ;CACF;;;;;AAMD,MAAa,gCAAgC;CAC3C,GAAG;CACH,GAAG;CACJ;;;;;;;;AASD,SAAgB,eAAe,OAAuB;AACpD,QAAO,MAAM,QAAQ,EAAE;;;;;;;;;;AAgBzB,SAAgB,oBACd,QACA,MACA,YACQ;AACR,QAAO,MAAM,eAAe,OAAO,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAY3F,SAAgB,uBACd,OACA,QACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,MAAM,CAAC,GAAG,WAAW,KAAK,eAAe,OAAO,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAYjI,SAAgB,qBACd,WACA,WACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,UAAU,CAAC,GAAG,WAAW,KAAK,eAAe,UAAU,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;AAUxI,SAAgB,sBACd,UACA,YACQ;AACR,QAAO,GAAG,eAAe,SAAS,CAAC,GAAG;;;;;;AAWxC,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;AAMF,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACA;CACD,CAAC"}
@@ -13,8 +13,8 @@
13
13
 
14
14
  'use client';
15
15
 
16
- import { DEFAULT_EDIT_HANDLE_COLOR, EDITABLE_LAYER_SUBLAYER_PROPS } from "../constants.js";
17
16
  import { DEFAULT_DISTANCE_UNITS, getDistanceUnitFromAbbreviation } from "../../../../shared/units.js";
17
+ import { DEFAULT_EDIT_HANDLE_COLOR, EDITABLE_LAYER_SUBLAYER_PROPS } from "../constants.js";
18
18
 
19
19
  //#region src/deckgl/shapes/shared/utils/layer-config.ts
20
20
  /**
@@ -0,0 +1,39 @@
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 { useEffect } from "react";
15
+
16
+ //#region ../hotkey-manager/dist/react/use-hotkey.js
17
+ /**
18
+ * A React hook that binds a HotkeyManager on mount and unbinds on unmount.
19
+ *
20
+ * @param manager - The hotkey manager to bind.
21
+ * @returns void
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * const myHotkey = registerHotkey({ key: { code: Keycode.KeyA }, onKeyUp: handler });
26
+ *
27
+ * function MyComponent() {
28
+ * useHotkey(myHotkey);
29
+ * return <div />;
30
+ * }
31
+ * ```
32
+ */
33
+ function useHotkey(manager) {
34
+ useEffect(() => manager.bind(), [manager]);
35
+ }
36
+
37
+ //#endregion
38
+ export { useHotkey };
39
+ //# sourceMappingURL=use-hotkey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hotkey.js","names":[],"sources":["../../../../../hotkey-manager/dist/react/use-hotkey.js"],"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\nimport { useEffect } from \"react\";\n\n//#region src/react/use-hotkey.ts\n/**\n* A React hook that binds a HotkeyManager on mount and unbinds on unmount.\n*\n* @param manager - The hotkey manager to bind.\n* @returns void\n*\n* @example\n* ```tsx\n* const myHotkey = registerHotkey({ key: { code: Keycode.KeyA }, onKeyUp: handler });\n*\n* function MyComponent() {\n* useHotkey(myHotkey);\n* return <div />;\n* }\n* ```\n*/\nfunction useHotkey(manager) {\n\tuseEffect(() => manager.bind(), [manager]);\n}\n/**\n* Creates a React hook from a HotkeyManager for module-level usage.\n* This is useful when you want to define the hotkey at module scope and use it as a hook.\n*\n* @param manager - The hotkey manager to wrap.\n* @returns A React hook that binds the hotkey on mount.\n*\n* @example\n* ```tsx\n* const myHotkey = registerHotkey({ key: { code: Keycode.KeyA }, onKeyUp: handler });\n* const useMyHotkey = createUseHotkey(myHotkey);\n*\n* function MyComponent() {\n* useMyHotkey();\n* return <div />;\n* }\n* ```\n*/\nfunction createUseHotkey(manager) {\n\treturn function useHotkeyHook() {\n\t\tuseEffect(() => manager.bind(), []);\n\t};\n}\n\n//#endregion\nexport { createUseHotkey, useHotkey };\n//# sourceMappingURL=use-hotkey.js.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAS,UAAU,SAAS;AAC3B,iBAAgB,QAAQ,MAAM,EAAE,CAAC,QAAQ,CAAC"}
@@ -0,0 +1,58 @@
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 { UniqueId } from "@accelint/core";
14
+
15
+ //#region src/shared/cleanup.d.ts
16
+ /**
17
+ * Returns the current generation counter for a map instance.
18
+ *
19
+ * Use as a `key` prop on `<MapLibre>` to force a clean remount whenever the map's
20
+ * stores are cleared (e.g., on Activity deactivation).
21
+ *
22
+ * @param mapId - The map instance ID
23
+ * @returns The current generation (0 on first render, increments with each cleanup)
24
+ */
25
+ declare function getMapGeneration(mapId: UniqueId): number;
26
+ /**
27
+ * Clears ALL map store state for a given map instance.
28
+ *
29
+ * This function calls cleanup for every store in the map-toolkit. It's called
30
+ * automatically by MapProvider when a map instance unmounts.
31
+ *
32
+ * **⚠️ IMPORTANT: When creating a new store with createMapStore():**
33
+ * 1. Export a `clear*State(mapId)` function from your store
34
+ * 2. Import and add it to this `clearAllMapStores()` function
35
+ * 3. The cleanup function should call your store's internal cleanup mechanism
36
+ *
37
+ * @param mapId - The map instance ID to clean up
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * // In your store file (e.g., my-feature/store.ts)
42
+ * export function clearMyFeatureState(mapId: UniqueId): void {
43
+ * myFeatureStore.cleanup(mapId);
44
+ * }
45
+ *
46
+ * // Then add to this file:
47
+ * import { clearMyFeatureState } from '../my-feature/store';
48
+ *
49
+ * export function clearAllMapStores(mapId: UniqueId): void {
50
+ * // ... existing cleanups
51
+ * clearMyFeatureState(mapId);
52
+ * }
53
+ * ```
54
+ */
55
+ declare function clearAllMapStores(mapId: UniqueId): void;
56
+ //#endregion
57
+ export { clearAllMapStores, getMapGeneration };
58
+ //# sourceMappingURL=cleanup.d.ts.map