@accelint/map-toolkit 1.4.0 → 2.0.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 (204) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/catalog-info.yaml +4 -4
  3. package/dist/camera/events.js +1 -1
  4. package/dist/camera/index.d.ts +1 -1
  5. package/dist/camera/index.js +1 -1
  6. package/dist/camera/store.d.ts +1 -1
  7. package/dist/camera/store.js +4 -6
  8. package/dist/camera/store.js.map +1 -1
  9. package/dist/camera/types.d.ts +1 -1
  10. package/dist/camera/types.js +1 -1
  11. package/dist/cursor-coordinates/constants.js +1 -1
  12. package/dist/cursor-coordinates/index.d.ts +1 -1
  13. package/dist/cursor-coordinates/index.js +1 -1
  14. package/dist/cursor-coordinates/store.d.ts +1 -1
  15. package/dist/cursor-coordinates/store.js +1 -1
  16. package/dist/cursor-coordinates/types.d.ts +1 -1
  17. package/dist/cursor-coordinates/types.js +1 -1
  18. package/dist/cursor-coordinates/use-cursor-coordinates.d.ts +1 -1
  19. package/dist/cursor-coordinates/use-cursor-coordinates.js +4 -9
  20. package/dist/cursor-coordinates/use-cursor-coordinates.js.map +1 -1
  21. package/dist/deckgl/base-map/constants.js +1 -1
  22. package/dist/deckgl/base-map/controls.d.ts +1 -1
  23. package/dist/deckgl/base-map/controls.js +1 -1
  24. package/dist/deckgl/base-map/events.js +1 -1
  25. package/dist/deckgl/base-map/index.d.ts +3 -3
  26. package/dist/deckgl/base-map/index.js +15 -7
  27. package/dist/deckgl/base-map/index.js.map +1 -1
  28. package/dist/deckgl/base-map/provider.d.ts +3 -3
  29. package/dist/deckgl/base-map/provider.js +3 -5
  30. package/dist/deckgl/base-map/provider.js.map +1 -1
  31. package/dist/deckgl/base-map/types.d.ts +1 -1
  32. package/dist/deckgl/base-map/types.js +1 -1
  33. package/dist/deckgl/index.d.ts +4 -4
  34. package/dist/deckgl/index.js +4 -4
  35. package/dist/deckgl/saved-viewports/index.d.ts +1 -1
  36. package/dist/deckgl/saved-viewports/index.js +1 -1
  37. package/dist/deckgl/saved-viewports/storage.d.ts +1 -1
  38. package/dist/deckgl/saved-viewports/storage.js +5 -10
  39. package/dist/deckgl/saved-viewports/storage.js.map +1 -1
  40. package/dist/deckgl/shapes/display-shape-layer/constants.js +66 -13
  41. package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -1
  42. package/dist/deckgl/shapes/display-shape-layer/fiber.d.ts +1 -1
  43. package/dist/deckgl/shapes/display-shape-layer/fiber.js +1 -1
  44. package/dist/deckgl/shapes/display-shape-layer/index.d.ts +74 -35
  45. package/dist/deckgl/shapes/display-shape-layer/index.js +381 -154
  46. package/dist/deckgl/shapes/display-shape-layer/index.js.map +1 -1
  47. package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.js +1 -1
  48. package/dist/deckgl/shapes/display-shape-layer/store.js +8 -2
  49. package/dist/deckgl/shapes/display-shape-layer/store.js.map +1 -1
  50. package/dist/deckgl/shapes/display-shape-layer/types.d.ts +108 -19
  51. package/dist/deckgl/shapes/display-shape-layer/types.js +1 -1
  52. package/dist/deckgl/shapes/display-shape-layer/use-select-shape.d.ts +1 -1
  53. package/dist/deckgl/shapes/display-shape-layer/use-select-shape.js +1 -1
  54. package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js +66 -36
  55. package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js.map +1 -1
  56. package/dist/deckgl/shapes/display-shape-layer/utils/elevation.js +407 -0
  57. package/dist/deckgl/shapes/display-shape-layer/utils/elevation.js.map +1 -0
  58. package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js +151 -0
  59. package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js.map +1 -0
  60. package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js +50 -0
  61. package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js.map +1 -0
  62. package/dist/deckgl/shapes/display-shape-layer/utils/labels.d.ts +1 -1
  63. package/dist/deckgl/shapes/display-shape-layer/utils/labels.js +28 -39
  64. package/dist/deckgl/shapes/display-shape-layer/utils/labels.js.map +1 -1
  65. package/dist/deckgl/shapes/draw-shape-layer/constants.js +1 -1
  66. package/dist/deckgl/shapes/draw-shape-layer/events.d.ts +1 -1
  67. package/dist/deckgl/shapes/draw-shape-layer/events.js +1 -1
  68. package/dist/deckgl/shapes/draw-shape-layer/fiber.js +1 -1
  69. package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +3 -3
  70. package/dist/deckgl/shapes/draw-shape-layer/index.js +7 -17
  71. package/dist/deckgl/shapes/draw-shape-layer/index.js.map +1 -1
  72. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +8 -9
  73. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -1
  74. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +3 -3
  75. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +4 -21
  76. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js.map +1 -1
  77. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +4 -34
  78. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js.map +1 -1
  79. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +11 -12
  80. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js.map +1 -1
  81. package/dist/deckgl/shapes/draw-shape-layer/modes/index.js +2 -32
  82. package/dist/deckgl/shapes/draw-shape-layer/modes/index.js.map +1 -1
  83. package/dist/deckgl/shapes/draw-shape-layer/store.js +38 -4
  84. package/dist/deckgl/shapes/draw-shape-layer/store.js.map +1 -1
  85. package/dist/deckgl/shapes/draw-shape-layer/types.d.ts +1 -1
  86. package/dist/deckgl/shapes/draw-shape-layer/types.js +1 -1
  87. package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.d.ts +1 -1
  88. package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.js +2 -2
  89. package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js +4 -9
  90. package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js.map +1 -1
  91. package/dist/deckgl/shapes/edit-shape-layer/constants.js +17 -2
  92. package/dist/deckgl/shapes/edit-shape-layer/constants.js.map +1 -1
  93. package/dist/deckgl/shapes/edit-shape-layer/events.d.ts +1 -1
  94. package/dist/deckgl/shapes/edit-shape-layer/events.js +1 -1
  95. package/dist/deckgl/shapes/edit-shape-layer/fiber.d.ts +1 -1
  96. package/dist/deckgl/shapes/edit-shape-layer/fiber.js +1 -1
  97. package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +7 -4
  98. package/dist/deckgl/shapes/edit-shape-layer/index.js +52 -21
  99. package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
  100. package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js +4 -1
  101. package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js.map +1 -1
  102. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +2 -2
  103. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js.map +1 -1
  104. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +7 -7
  105. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
  106. package/dist/deckgl/shapes/edit-shape-layer/modes/index.js +2 -2
  107. package/dist/deckgl/shapes/edit-shape-layer/modes/index.js.map +1 -1
  108. package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js +1 -1
  109. package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js.map +1 -1
  110. package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js +2 -2
  111. package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js.map +1 -1
  112. package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js +1 -1
  113. package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js.map +1 -1
  114. package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js +1 -1
  115. package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js.map +1 -1
  116. package/dist/deckgl/shapes/edit-shape-layer/store.js +78 -14
  117. package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
  118. package/dist/deckgl/shapes/edit-shape-layer/types.d.ts +14 -2
  119. package/dist/deckgl/shapes/edit-shape-layer/types.js +1 -1
  120. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.d.ts +1 -1
  121. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js +2 -2
  122. package/dist/deckgl/shapes/index.d.ts +4 -4
  123. package/dist/deckgl/shapes/index.js +5 -5
  124. package/dist/deckgl/shapes/shared/constants.d.ts +4 -3
  125. package/dist/deckgl/shapes/shared/constants.js +55 -15
  126. package/dist/deckgl/shapes/shared/constants.js.map +1 -1
  127. package/dist/deckgl/shapes/shared/events.d.ts +5 -1
  128. package/dist/deckgl/shapes/shared/events.js +1 -1
  129. package/dist/deckgl/shapes/shared/events.js.map +1 -1
  130. package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js +19 -16
  131. package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js.map +1 -1
  132. package/dist/deckgl/shapes/shared/types.d.ts +174 -53
  133. package/dist/deckgl/shapes/shared/types.js +155 -2
  134. package/dist/deckgl/shapes/shared/types.js.map +1 -1
  135. package/dist/deckgl/shapes/shared/utils/geometry-measurements.js +29 -24
  136. package/dist/deckgl/shapes/shared/utils/geometry-measurements.js.map +1 -1
  137. package/dist/deckgl/shapes/shared/utils/layer-config.js +9 -6
  138. package/dist/deckgl/shapes/shared/utils/layer-config.js.map +1 -1
  139. package/dist/deckgl/shapes/shared/utils/mode-utils.js +50 -20
  140. package/dist/deckgl/shapes/shared/utils/mode-utils.js.map +1 -1
  141. package/dist/deckgl/shapes/shared/utils/pick-filtering.js +22 -15
  142. package/dist/deckgl/shapes/shared/utils/pick-filtering.js.map +1 -1
  143. package/dist/deckgl/shapes/shared/utils/style-utils.d.ts +38 -14
  144. package/dist/deckgl/shapes/shared/utils/style-utils.js +43 -32
  145. package/dist/deckgl/shapes/shared/utils/style-utils.js.map +1 -1
  146. package/dist/deckgl/symbol-layer/fiber.d.ts +1 -1
  147. package/dist/deckgl/symbol-layer/fiber.js +1 -1
  148. package/dist/deckgl/symbol-layer/index.d.ts +1 -1
  149. package/dist/deckgl/symbol-layer/index.js +1 -1
  150. package/dist/deckgl/text-layer/character-sets.js +1 -1
  151. package/dist/deckgl/text-layer/default-settings.d.ts +1 -1
  152. package/dist/deckgl/text-layer/default-settings.js +1 -1
  153. package/dist/deckgl/text-layer/fiber.d.ts +1 -1
  154. package/dist/deckgl/text-layer/fiber.js +1 -1
  155. package/dist/deckgl/text-layer/index.d.ts +1 -1
  156. package/dist/deckgl/text-layer/index.js +1 -1
  157. package/dist/deckgl/text-settings.d.ts +3 -3
  158. package/dist/deckgl/text-settings.js +1 -1
  159. package/dist/map-cursor/events.js +1 -1
  160. package/dist/map-cursor/index.d.ts +1 -1
  161. package/dist/map-cursor/index.js +1 -1
  162. package/dist/map-cursor/store.d.ts +1 -1
  163. package/dist/map-cursor/store.js +1 -1
  164. package/dist/map-cursor/types.d.ts +1 -1
  165. package/dist/map-cursor/types.js +1 -1
  166. package/dist/map-cursor/use-map-cursor.d.ts +1 -1
  167. package/dist/map-cursor/use-map-cursor.js +1 -1
  168. package/dist/map-mode/events.js +1 -1
  169. package/dist/map-mode/index.d.ts +1 -1
  170. package/dist/map-mode/index.js +1 -1
  171. package/dist/map-mode/store.d.ts +1 -1
  172. package/dist/map-mode/store.js +3 -8
  173. package/dist/map-mode/store.js.map +1 -1
  174. package/dist/map-mode/types.d.ts +1 -1
  175. package/dist/map-mode/types.js +1 -1
  176. package/dist/map-mode/use-map-mode.d.ts +1 -1
  177. package/dist/map-mode/use-map-mode.js +1 -1
  178. package/dist/maplibre/hooks/use-maplibre.d.ts +1 -1
  179. package/dist/maplibre/hooks/use-maplibre.js +1 -1
  180. package/dist/maplibre/index.d.ts +1 -1
  181. package/dist/maplibre/index.js +1 -1
  182. package/dist/shared/cleanup.d.ts +58 -0
  183. package/dist/shared/cleanup.js +93 -0
  184. package/dist/shared/cleanup.js.map +1 -0
  185. package/dist/shared/constants.js +1 -1
  186. package/dist/shared/create-map-store.d.ts +13 -1
  187. package/dist/shared/create-map-store.js +9 -4
  188. package/dist/shared/create-map-store.js.map +1 -1
  189. package/dist/shared/logger.js +31 -0
  190. package/dist/shared/logger.js.map +1 -0
  191. package/dist/shared/units.js +1 -1
  192. package/dist/viewport/index.d.ts +1 -1
  193. package/dist/viewport/index.js +1 -1
  194. package/dist/viewport/store.d.ts +1 -1
  195. package/dist/viewport/store.js +1 -1
  196. package/dist/viewport/types.d.ts +1 -1
  197. package/dist/viewport/types.js +1 -1
  198. package/dist/viewport/utils.d.ts +1 -1
  199. package/dist/viewport/utils.js +1 -1
  200. package/dist/viewport/viewport-size.d.ts +3 -3
  201. package/dist/viewport/viewport-size.js +1 -1
  202. package/package.json +22 -19
  203. package/dist/hotkey-manager/dist/react/use-hotkey.js +0 -39
  204. package/dist/hotkey-manager/dist/react/use-hotkey.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -11,10 +11,10 @@
11
11
  */
12
12
 
13
13
 
14
- import { formatDistanceTooltip } from "../../shared/constants.js";
15
14
  import { DEFAULT_DISTANCE_UNITS, getDistanceUnitAbbreviation } from "../../../../shared/units.js";
16
- import { DrawLineStringMode } from "@deck.gl-community/editable-layers";
15
+ import { formatDistanceTooltip } from "../../shared/constants.js";
17
16
  import { distance } from "@turf/turf";
17
+ import { DrawLineStringMode } from "@deck.gl-community/editable-layers";
18
18
 
19
19
  //#region src/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.ts
20
20
  /**
@@ -29,9 +29,6 @@ import { distance } from "@turf/turf";
29
29
  * 3. Click to add more points
30
30
  * 4. Double-click to finish the line string
31
31
  *
32
- * ## Double-Click Workaround
33
- * Includes a workaround for the double-click to finish issue in @deck.gl-community/editable-layers ~9.1.
34
- * This will be fixed in a future version (PR #225).
35
32
  *
36
33
  * @example
37
34
  * ```typescript
@@ -44,8 +41,6 @@ import { distance } from "@turf/turf";
44
41
  var DrawLineStringModeWithTooltip = class extends DrawLineStringMode {
45
42
  /** Current tooltip state (null when not drawing) */
46
43
  tooltip = null;
47
- /** Cached mode props for double-click workaround */
48
- lastModeProps = null;
49
44
  /**
50
45
  * Finish drawing the line string.
51
46
  *
@@ -64,20 +59,10 @@ var DrawLineStringModeWithTooltip = class extends DrawLineStringMode {
64
59
  };
65
60
  this.resetClickSequence();
66
61
  this.tooltip = null;
67
- this.lastModeProps = null;
68
62
  const editAction = this.getAddFeatureAction(lineStringToAdd, props.data);
69
63
  if (editAction) props.onEdit(editAction);
70
64
  }
71
65
  /**
72
- * Handle double-click to finish drawing.
73
- * This is called externally via a DOM event listener as a workaround for
74
- * @deck.gl-community/editable-layers ~9.1 which doesn't register 'dblclick' in EVENT_TYPES.
75
- * @see https://github.com/visgl/deck.gl-community/pull/225
76
- */
77
- handleDoubleClick() {
78
- if (this.lastModeProps) this.finishDrawing(this.lastModeProps);
79
- }
80
- /**
81
66
  * Override handleClick to store props for double-click workaround.
82
67
  *
83
68
  * Caches the mode props so that the external double-click handler can
@@ -87,7 +72,6 @@ var DrawLineStringModeWithTooltip = class extends DrawLineStringMode {
87
72
  * @param props - Mode properties including onEdit callback
88
73
  */
89
74
  handleClick(event, props) {
90
- this.lastModeProps = props;
91
75
  super.handleClick(event, props);
92
76
  }
93
77
  /**
@@ -108,10 +92,9 @@ var DrawLineStringModeWithTooltip = class extends DrawLineStringMode {
108
92
  }
109
93
  const { mapCoords } = event;
110
94
  const distanceUnits = props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;
111
- const lastPoint = clickSequence[clickSequence.length - 1];
112
95
  this.tooltip = {
113
96
  position: mapCoords,
114
- text: formatDistanceTooltip(distance(lastPoint, mapCoords, { units: distanceUnits }), getDistanceUnitAbbreviation(distanceUnits))
97
+ text: formatDistanceTooltip(distance(clickSequence.at(-1), mapCoords, { units: distanceUnits }), getDistanceUnitAbbreviation(distanceUnits))
115
98
  };
116
99
  }
117
100
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"draw-line-string-mode-with-tooltip.js","names":[],"sources":["../../../../../src/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.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 DrawLineStringMode,\n type FeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type Tooltip,\n} from '@deck.gl-community/editable-layers';\nimport { type Coord, distance } from '@turf/turf';\nimport {\n DEFAULT_DISTANCE_UNITS,\n getDistanceUnitAbbreviation,\n} from '@/shared/units';\nimport { formatDistanceTooltip } from '../../shared/constants';\n\n/**\n * Extends DrawLineStringMode to display distance tooltip between points.\n *\n * Shows the distance from the last clicked point to the current cursor position\n * while drawing a line string. The tooltip updates in real-time as the cursor moves.\n *\n * ## Drawing Flow\n * 1. Click to add first point\n * 2. Move cursor (tooltip shows distance from last point)\n * 3. Click to add more points\n * 4. Double-click to finish the line string\n *\n * ## Double-Click Workaround\n * Includes a workaround for the double-click to finish issue in @deck.gl-community/editable-layers ~9.1.\n * This will be fixed in a future version (PR #225).\n *\n * @example\n * ```typescript\n * import { DrawLineStringModeWithTooltip } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Used internally by DrawShapeLayer\n * const mode = new DrawLineStringModeWithTooltip();\n * ```\n */\nexport class DrawLineStringModeWithTooltip extends DrawLineStringMode {\n /** Current tooltip state (null when not drawing) */\n private tooltip: Tooltip | null = null;\n /** Cached mode props for double-click workaround */\n private lastModeProps: ModeProps<FeatureCollection> | null = null;\n\n /**\n * Finish drawing the line string.\n *\n * Creates a LineString geometry from the click sequence and emits an edit action.\n * Requires at least 2 points to create a valid line string.\n * Extracted to share between double-click workaround and parent class logic.\n *\n * @param props - Mode properties with onEdit callback\n */\n private finishDrawing(props: ModeProps<FeatureCollection>): void {\n const clickSequence = this.getClickSequence();\n if (clickSequence.length <= 1) {\n return;\n }\n\n const lineStringToAdd = {\n type: 'LineString' as const,\n coordinates: [...clickSequence],\n };\n\n this.resetClickSequence();\n this.tooltip = null;\n this.lastModeProps = null;\n\n const editAction = this.getAddFeatureAction(lineStringToAdd, props.data);\n if (editAction) {\n props.onEdit(editAction);\n }\n }\n\n /**\n * Handle double-click to finish drawing.\n * This is called externally via a DOM event listener as a workaround for\n * @deck.gl-community/editable-layers ~9.1 which doesn't register 'dblclick' in EVENT_TYPES.\n * @see https://github.com/visgl/deck.gl-community/pull/225\n */\n handleDoubleClick(): void {\n if (this.lastModeProps) {\n this.finishDrawing(this.lastModeProps);\n }\n }\n\n /**\n * Override handleClick to store props for double-click workaround.\n *\n * Caches the mode props so that the external double-click handler can\n * access them when finishing the drawing.\n *\n * @param event - Click event with map coordinates\n * @param props - Mode properties including onEdit callback\n */\n override handleClick(\n event: ClickEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n // Store props so handleDoubleClick can access them\n this.lastModeProps = props;\n super.handleClick(event, props);\n }\n\n /**\n * Handle pointer move events to update the tooltip with distance.\n *\n * Calculates the distance from the last clicked point to the current\n * cursor position and displays it in the configured distance units.\n *\n * @param event - Pointer move event with cursor position\n * @param props - Mode properties including distance units configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n super.handlePointerMove(event, props);\n\n const clickSequence = this.getClickSequence();\n if (!clickSequence.length) {\n this.tooltip = null;\n return;\n }\n\n const { mapCoords } = event;\n const distanceUnits =\n props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;\n\n const lastPoint = clickSequence[clickSequence.length - 1] as Coord;\n const currentPoint = mapCoords as Coord;\n\n const dist = distance(lastPoint, currentPoint, { units: distanceUnits });\n const unitAbbrev = getDistanceUnitAbbreviation(distanceUnits);\n\n this.tooltip = {\n position: mapCoords,\n text: formatDistanceTooltip(dist, unitAbbrev),\n };\n }\n\n /**\n * Get the current tooltip array for rendering.\n *\n * @returns Array containing the tooltip if one is active, empty array otherwise\n */\n override getTooltips(): Tooltip[] {\n return this.tooltip ? [this.tooltip] : [];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,IAAa,gCAAb,cAAmD,mBAAmB;;CAEpE,AAAQ,UAA0B;;CAElC,AAAQ,gBAAqD;;;;;;;;;;CAW7D,AAAQ,cAAc,OAA2C;EAC/D,MAAM,gBAAgB,KAAK,kBAAkB;AAC7C,MAAI,cAAc,UAAU,EAC1B;EAGF,MAAM,kBAAkB;GACtB,MAAM;GACN,aAAa,CAAC,GAAG,cAAc;GAChC;AAED,OAAK,oBAAoB;AACzB,OAAK,UAAU;AACf,OAAK,gBAAgB;EAErB,MAAM,aAAa,KAAK,oBAAoB,iBAAiB,MAAM,KAAK;AACxE,MAAI,WACF,OAAM,OAAO,WAAW;;;;;;;;CAU5B,oBAA0B;AACxB,MAAI,KAAK,cACP,MAAK,cAAc,KAAK,cAAc;;;;;;;;;;;CAa1C,AAAS,YACP,OACA,OACM;AAEN,OAAK,gBAAgB;AACrB,QAAM,YAAY,OAAO,MAAM;;;;;;;;;;;CAYjC,AAAS,kBACP,OACA,OACA;AACA,QAAM,kBAAkB,OAAO,MAAM;EAErC,MAAM,gBAAgB,KAAK,kBAAkB;AAC7C,MAAI,CAAC,cAAc,QAAQ;AACzB,QAAK,UAAU;AACf;;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBACJ,MAAM,YAAY,iBAAiB;EAErC,MAAM,YAAY,cAAc,cAAc,SAAS;AAMvD,OAAK,UAAU;GACb,UAAU;GACV,MAAM,sBALK,SAAS,WAFD,WAE0B,EAAE,OAAO,eAAe,CAAC,EACrD,4BAA4B,cAAc,CAId;GAC9C;;;;;;;CAQH,AAAS,cAAyB;AAChC,SAAO,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,EAAE"}
1
+ {"version":3,"file":"draw-line-string-mode-with-tooltip.js","names":[],"sources":["../../../../../src/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.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 DrawLineStringMode,\n type FeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type SimpleFeatureCollection,\n type Tooltip,\n} from '@deck.gl-community/editable-layers';\nimport { type Coord, distance } from '@turf/turf';\nimport {\n DEFAULT_DISTANCE_UNITS,\n getDistanceUnitAbbreviation,\n} from '@/shared/units';\nimport { formatDistanceTooltip } from '../../shared/constants';\n\n/**\n * Extends DrawLineStringMode to display distance tooltip between points.\n *\n * Shows the distance from the last clicked point to the current cursor position\n * while drawing a line string. The tooltip updates in real-time as the cursor moves.\n *\n * ## Drawing Flow\n * 1. Click to add first point\n * 2. Move cursor (tooltip shows distance from last point)\n * 3. Click to add more points\n * 4. Double-click to finish the line string\n *\n *\n * @example\n * ```typescript\n * import { DrawLineStringModeWithTooltip } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Used internally by DrawShapeLayer\n * const mode = new DrawLineStringModeWithTooltip();\n * ```\n */\nexport class DrawLineStringModeWithTooltip extends DrawLineStringMode {\n /** Current tooltip state (null when not drawing) */\n private tooltip: Tooltip | null = null;\n\n /**\n * Finish drawing the line string.\n *\n * Creates a LineString geometry from the click sequence and emits an edit action.\n * Requires at least 2 points to create a valid line string.\n * Extracted to share between double-click workaround and parent class logic.\n *\n * @param props - Mode properties with onEdit callback\n */\n override finishDrawing(props: ModeProps<SimpleFeatureCollection>): void {\n const clickSequence = this.getClickSequence();\n if (clickSequence.length <= 1) {\n return;\n }\n\n const lineStringToAdd = {\n type: 'LineString' as const,\n coordinates: [...clickSequence],\n };\n\n this.resetClickSequence();\n this.tooltip = null;\n\n const editAction = this.getAddFeatureAction(lineStringToAdd, props.data);\n if (editAction) {\n props.onEdit(editAction);\n }\n }\n\n /**\n * Override handleClick to store props for double-click workaround.\n *\n * Caches the mode props so that the external double-click handler can\n * access them when finishing the drawing.\n *\n * @param event - Click event with map coordinates\n * @param props - Mode properties including onEdit callback\n */\n override handleClick(\n event: ClickEvent,\n props: ModeProps<SimpleFeatureCollection>,\n ): void {\n super.handleClick(event, props);\n }\n\n /**\n * Handle pointer move events to update the tooltip with distance.\n *\n * Calculates the distance from the last clicked point to the current\n * cursor position and displays it in the configured distance units.\n *\n * @param event - Pointer move event with cursor position\n * @param props - Mode properties including distance units configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n super.handlePointerMove(event, props);\n\n const clickSequence = this.getClickSequence();\n if (!clickSequence.length) {\n this.tooltip = null;\n return;\n }\n\n const { mapCoords } = event;\n const distanceUnits =\n props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;\n\n const lastPoint = clickSequence.at(-1) as Coord;\n const currentPoint = mapCoords as Coord;\n\n const dist = distance(lastPoint, currentPoint, { units: distanceUnits });\n const unitAbbrev = getDistanceUnitAbbreviation(distanceUnits);\n\n this.tooltip = {\n position: mapCoords,\n text: formatDistanceTooltip(dist, unitAbbrev),\n };\n }\n\n /**\n * Get the current tooltip array for rendering.\n *\n * @returns Array containing the tooltip if one is active, empty array otherwise\n */\n override getTooltips(): Tooltip[] {\n return this.tooltip ? [this.tooltip] : [];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,IAAa,gCAAb,cAAmD,mBAAmB;;CAEpE,AAAQ,UAA0B;;;;;;;;;;CAWlC,AAAS,cAAc,OAAiD;EACtE,MAAM,gBAAgB,KAAK,kBAAkB;AAC7C,MAAI,cAAc,UAAU,EAC1B;EAGF,MAAM,kBAAkB;GACtB,MAAM;GACN,aAAa,CAAC,GAAG,cAAc;GAChC;AAED,OAAK,oBAAoB;AACzB,OAAK,UAAU;EAEf,MAAM,aAAa,KAAK,oBAAoB,iBAAiB,MAAM,KAAK;AACxE,MAAI,WACF,OAAM,OAAO,WAAW;;;;;;;;;;;CAa5B,AAAS,YACP,OACA,OACM;AACN,QAAM,YAAY,OAAO,MAAM;;;;;;;;;;;CAYjC,AAAS,kBACP,OACA,OACA;AACA,QAAM,kBAAkB,OAAO,MAAM;EAErC,MAAM,gBAAgB,KAAK,kBAAkB;AAC7C,MAAI,CAAC,cAAc,QAAQ;AACzB,QAAK,UAAU;AACf;;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBACJ,MAAM,YAAY,iBAAiB;AAQrC,OAAK,UAAU;GACb,UAAU;GACV,MAAM,sBALK,SAHK,cAAc,GAAG,GAAG,EACjB,WAE0B,EAAE,OAAO,eAAe,CAAC,EACrD,4BAA4B,cAAc,CAId;GAC9C;;;;;;;CAQH,AAAS,cAAyB;AAChC,SAAO,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,EAAE"}
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -11,10 +11,10 @@
11
11
  */
12
12
 
13
13
 
14
- import { formatDistanceTooltip } from "../../shared/constants.js";
15
14
  import { DEFAULT_DISTANCE_UNITS, getDistanceUnitAbbreviation } from "../../../../shared/units.js";
16
- import { DrawPolygonMode } from "@deck.gl-community/editable-layers";
15
+ import { formatDistanceTooltip } from "../../shared/constants.js";
17
16
  import { distance } from "@turf/turf";
17
+ import { DrawPolygonMode } from "@deck.gl-community/editable-layers";
18
18
 
19
19
  //#region src/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.ts
20
20
  /**
@@ -29,9 +29,6 @@ import { distance } from "@turf/turf";
29
29
  * 3. Click to add more vertices
30
30
  * 4. Double-click or click the starting point to close the polygon
31
31
  *
32
- * ## Double-Click Workaround
33
- * Includes a workaround for the double-click to finish issue in @deck.gl-community/editable-layers ~9.1.
34
- * This will be fixed in a future version (PR #225).
35
32
  *
36
33
  * @example
37
34
  * ```typescript
@@ -44,15 +41,12 @@ import { distance } from "@turf/turf";
44
41
  var DrawPolygonModeWithTooltip = class extends DrawPolygonMode {
45
42
  /** Current tooltip state (null when not drawing) */
46
43
  tooltip = null;
47
- /** Cached mode props for double-click workaround */
48
- lastModeProps = null;
49
44
  /**
50
45
  * Finish drawing the polygon.
51
46
  *
52
47
  * Creates a Polygon geometry from the click sequence and emits an edit action.
53
48
  * Requires at least 3 points to create a valid polygon. Automatically closes
54
49
  * the polygon by adding the first point to the end of the coordinate ring.
55
- * Extracted to share between double-click workaround and parent class logic.
56
50
  *
57
51
  * @param props - Mode properties with onEdit callback
58
52
  */
@@ -66,33 +60,10 @@ var DrawPolygonModeWithTooltip = class extends DrawPolygonMode {
66
60
  };
67
61
  this.resetClickSequence();
68
62
  this.tooltip = null;
69
- this.lastModeProps = null;
70
63
  const editAction = this.getAddFeatureOrBooleanPolygonAction(polygonToAdd, props);
71
64
  if (editAction) props.onEdit(editAction);
72
65
  }
73
66
  /**
74
- * Handle double-click to finish drawing.
75
- * This is called externally via a DOM event listener as a workaround for
76
- * @deck.gl-community/editable-layers ~9.1 which doesn't register 'dblclick' in EVENT_TYPES.
77
- * @see https://github.com/visgl/deck.gl-community/pull/225
78
- */
79
- handleDoubleClick() {
80
- if (this.lastModeProps) this.finishDrawing(this.lastModeProps);
81
- }
82
- /**
83
- * Override handleClick to store props for double-click workaround.
84
- *
85
- * Caches the mode props so that the external double-click handler can
86
- * access them when finishing the drawing.
87
- *
88
- * @param event - Click event with map coordinates
89
- * @param props - Mode properties including onEdit callback
90
- */
91
- handleClick(event, props) {
92
- this.lastModeProps = props;
93
- super.handleClick(event, props);
94
- }
95
- /**
96
67
  * Handle pointer move events to update the tooltip with distance.
97
68
  *
98
69
  * Calculates the distance from the last clicked vertex to the current
@@ -110,10 +81,9 @@ var DrawPolygonModeWithTooltip = class extends DrawPolygonMode {
110
81
  }
111
82
  const { mapCoords } = event;
112
83
  const distanceUnits = props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;
113
- const lastPoint = clickSequence[clickSequence.length - 1];
114
84
  this.tooltip = {
115
85
  position: mapCoords,
116
- text: formatDistanceTooltip(distance(lastPoint, mapCoords, { units: distanceUnits }), getDistanceUnitAbbreviation(distanceUnits))
86
+ text: formatDistanceTooltip(distance(clickSequence.at(-1), mapCoords, { units: distanceUnits }), getDistanceUnitAbbreviation(distanceUnits))
117
87
  };
118
88
  }
119
89
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"draw-polygon-mode-with-tooltip.js","names":[],"sources":["../../../../../src/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.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 DrawPolygonMode,\n type FeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type Tooltip,\n} from '@deck.gl-community/editable-layers';\nimport { type Coord, distance } from '@turf/turf';\nimport {\n DEFAULT_DISTANCE_UNITS,\n getDistanceUnitAbbreviation,\n} from '@/shared/units';\nimport { formatDistanceTooltip } from '../../shared/constants';\n\n/**\n * Extends DrawPolygonMode to display distance tooltip between points.\n *\n * Shows the distance from the last clicked point to the current cursor position\n * while drawing a polygon. The tooltip updates in real-time as the cursor moves.\n *\n * ## Drawing Flow\n * 1. Click to add first vertex\n * 2. Move cursor (tooltip shows distance from last vertex)\n * 3. Click to add more vertices\n * 4. Double-click or click the starting point to close the polygon\n *\n * ## Double-Click Workaround\n * Includes a workaround for the double-click to finish issue in @deck.gl-community/editable-layers ~9.1.\n * This will be fixed in a future version (PR #225).\n *\n * @example\n * ```typescript\n * import { DrawPolygonModeWithTooltip } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Used internally by DrawShapeLayer\n * const mode = new DrawPolygonModeWithTooltip();\n * ```\n */\nexport class DrawPolygonModeWithTooltip extends DrawPolygonMode {\n /** Current tooltip state (null when not drawing) */\n private tooltip: Tooltip | null = null;\n /** Cached mode props for double-click workaround */\n private lastModeProps: ModeProps<FeatureCollection> | null = null;\n\n /**\n * Finish drawing the polygon.\n *\n * Creates a Polygon geometry from the click sequence and emits an edit action.\n * Requires at least 3 points to create a valid polygon. Automatically closes\n * the polygon by adding the first point to the end of the coordinate ring.\n * Extracted to share between double-click workaround and parent class logic.\n *\n * @param props - Mode properties with onEdit callback\n */\n private finishDrawing(props: ModeProps<FeatureCollection>): void {\n const clickSequence = this.getClickSequence();\n const firstPoint = clickSequence[0];\n if (clickSequence.length <= 2 || !firstPoint) {\n return;\n }\n\n const polygonToAdd = {\n type: 'Polygon' as const,\n coordinates: [[...clickSequence, firstPoint]],\n };\n\n this.resetClickSequence();\n this.tooltip = null;\n this.lastModeProps = null;\n\n const editAction = this.getAddFeatureOrBooleanPolygonAction(\n polygonToAdd,\n props,\n );\n if (editAction) {\n props.onEdit(editAction);\n }\n }\n\n /**\n * Handle double-click to finish drawing.\n * This is called externally via a DOM event listener as a workaround for\n * @deck.gl-community/editable-layers ~9.1 which doesn't register 'dblclick' in EVENT_TYPES.\n * @see https://github.com/visgl/deck.gl-community/pull/225\n */\n handleDoubleClick(): void {\n if (this.lastModeProps) {\n this.finishDrawing(this.lastModeProps);\n }\n }\n\n /**\n * Override handleClick to store props for double-click workaround.\n *\n * Caches the mode props so that the external double-click handler can\n * access them when finishing the drawing.\n *\n * @param event - Click event with map coordinates\n * @param props - Mode properties including onEdit callback\n */\n override handleClick(\n event: ClickEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n // Store props so handleDoubleClick can access them\n this.lastModeProps = props;\n super.handleClick(event, props);\n }\n\n /**\n * Handle pointer move events to update the tooltip with distance.\n *\n * Calculates the distance from the last clicked vertex to the current\n * cursor position and displays it in the configured distance units.\n *\n * @param event - Pointer move event with cursor position\n * @param props - Mode properties including distance units configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n super.handlePointerMove(event, props);\n\n const clickSequence = this.getClickSequence();\n if (!clickSequence.length) {\n this.tooltip = null;\n return;\n }\n\n const { mapCoords } = event;\n const distanceUnits =\n props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;\n\n const lastPoint = clickSequence[clickSequence.length - 1] as Coord;\n const currentPoint = mapCoords as Coord;\n\n const dist = distance(lastPoint, currentPoint, { units: distanceUnits });\n const unitAbbrev = getDistanceUnitAbbreviation(distanceUnits);\n\n this.tooltip = {\n position: mapCoords,\n text: formatDistanceTooltip(dist, unitAbbrev),\n };\n }\n\n /**\n * Get the current tooltip array for rendering.\n *\n * @returns Array containing the tooltip if one is active, empty array otherwise\n */\n override getTooltips(): Tooltip[] {\n return this.tooltip ? [this.tooltip] : [];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,IAAa,6BAAb,cAAgD,gBAAgB;;CAE9D,AAAQ,UAA0B;;CAElC,AAAQ,gBAAqD;;;;;;;;;;;CAY7D,AAAQ,cAAc,OAA2C;EAC/D,MAAM,gBAAgB,KAAK,kBAAkB;EAC7C,MAAM,aAAa,cAAc;AACjC,MAAI,cAAc,UAAU,KAAK,CAAC,WAChC;EAGF,MAAM,eAAe;GACnB,MAAM;GACN,aAAa,CAAC,CAAC,GAAG,eAAe,WAAW,CAAC;GAC9C;AAED,OAAK,oBAAoB;AACzB,OAAK,UAAU;AACf,OAAK,gBAAgB;EAErB,MAAM,aAAa,KAAK,oCACtB,cACA,MACD;AACD,MAAI,WACF,OAAM,OAAO,WAAW;;;;;;;;CAU5B,oBAA0B;AACxB,MAAI,KAAK,cACP,MAAK,cAAc,KAAK,cAAc;;;;;;;;;;;CAa1C,AAAS,YACP,OACA,OACM;AAEN,OAAK,gBAAgB;AACrB,QAAM,YAAY,OAAO,MAAM;;;;;;;;;;;CAYjC,AAAS,kBACP,OACA,OACA;AACA,QAAM,kBAAkB,OAAO,MAAM;EAErC,MAAM,gBAAgB,KAAK,kBAAkB;AAC7C,MAAI,CAAC,cAAc,QAAQ;AACzB,QAAK,UAAU;AACf;;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBACJ,MAAM,YAAY,iBAAiB;EAErC,MAAM,YAAY,cAAc,cAAc,SAAS;AAMvD,OAAK,UAAU;GACb,UAAU;GACV,MAAM,sBALK,SAAS,WAFD,WAE0B,EAAE,OAAO,eAAe,CAAC,EACrD,4BAA4B,cAAc,CAId;GAC9C;;;;;;;CAQH,AAAS,cAAyB;AAChC,SAAO,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,EAAE"}
1
+ {"version":3,"file":"draw-polygon-mode-with-tooltip.js","names":[],"sources":["../../../../../src/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.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 DrawPolygonMode,\n type FeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type SimpleFeatureCollection,\n type Tooltip,\n} from '@deck.gl-community/editable-layers';\nimport { type Coord, distance } from '@turf/turf';\nimport {\n DEFAULT_DISTANCE_UNITS,\n getDistanceUnitAbbreviation,\n} from '@/shared/units';\nimport { formatDistanceTooltip } from '../../shared/constants';\n\n/**\n * Extends DrawPolygonMode to display distance tooltip between points.\n *\n * Shows the distance from the last clicked point to the current cursor position\n * while drawing a polygon. The tooltip updates in real-time as the cursor moves.\n *\n * ## Drawing Flow\n * 1. Click to add first vertex\n * 2. Move cursor (tooltip shows distance from last vertex)\n * 3. Click to add more vertices\n * 4. Double-click or click the starting point to close the polygon\n *\n *\n * @example\n * ```typescript\n * import { DrawPolygonModeWithTooltip } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Used internally by DrawShapeLayer\n * const mode = new DrawPolygonModeWithTooltip();\n * ```\n */\nexport class DrawPolygonModeWithTooltip extends DrawPolygonMode {\n /** Current tooltip state (null when not drawing) */\n private tooltip: Tooltip | null = null;\n\n /**\n * Finish drawing the polygon.\n *\n * Creates a Polygon geometry from the click sequence and emits an edit action.\n * Requires at least 3 points to create a valid polygon. Automatically closes\n * the polygon by adding the first point to the end of the coordinate ring.\n *\n * @param props - Mode properties with onEdit callback\n */\n override finishDrawing(props: ModeProps<SimpleFeatureCollection>): void {\n const clickSequence = this.getClickSequence();\n const firstPoint = clickSequence[0];\n if (clickSequence.length <= 2 || !firstPoint) {\n return;\n }\n\n const polygonToAdd = {\n type: 'Polygon' as const,\n coordinates: [[...clickSequence, firstPoint]],\n };\n\n this.resetClickSequence();\n this.tooltip = null;\n\n const editAction = this.getAddFeatureOrBooleanPolygonAction(\n polygonToAdd,\n props,\n );\n if (editAction) {\n props.onEdit(editAction);\n }\n }\n\n /**\n * Handle pointer move events to update the tooltip with distance.\n *\n * Calculates the distance from the last clicked vertex to the current\n * cursor position and displays it in the configured distance units.\n *\n * @param event - Pointer move event with cursor position\n * @param props - Mode properties including distance units configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n super.handlePointerMove(event, props);\n\n const clickSequence = this.getClickSequence();\n if (!clickSequence.length) {\n this.tooltip = null;\n return;\n }\n\n const { mapCoords } = event;\n const distanceUnits =\n props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;\n\n const lastPoint = clickSequence.at(-1) as Coord;\n const currentPoint = mapCoords as Coord;\n\n const dist = distance(lastPoint, currentPoint, { units: distanceUnits });\n const unitAbbrev = getDistanceUnitAbbreviation(distanceUnits);\n\n this.tooltip = {\n position: mapCoords,\n text: formatDistanceTooltip(dist, unitAbbrev),\n };\n }\n\n /**\n * Get the current tooltip array for rendering.\n *\n * @returns Array containing the tooltip if one is active, empty array otherwise\n */\n override getTooltips(): Tooltip[] {\n return this.tooltip ? [this.tooltip] : [];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,IAAa,6BAAb,cAAgD,gBAAgB;;CAE9D,AAAQ,UAA0B;;;;;;;;;;CAWlC,AAAS,cAAc,OAAiD;EACtE,MAAM,gBAAgB,KAAK,kBAAkB;EAC7C,MAAM,aAAa,cAAc;AACjC,MAAI,cAAc,UAAU,KAAK,CAAC,WAChC;EAGF,MAAM,eAAe;GACnB,MAAM;GACN,aAAa,CAAC,CAAC,GAAG,eAAe,WAAW,CAAC;GAC9C;AAED,OAAK,oBAAoB;AACzB,OAAK,UAAU;EAEf,MAAM,aAAa,KAAK,oCACtB,cACA,MACD;AACD,MAAI,WACF,OAAM,OAAO,WAAW;;;;;;;;;;;CAa5B,AAAS,kBACP,OACA,OACA;AACA,QAAM,kBAAkB,OAAO,MAAM;EAErC,MAAM,gBAAgB,KAAK,kBAAkB;AAC7C,MAAI,CAAC,cAAc,QAAQ;AACzB,QAAK,UAAU;AACf;;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBACJ,MAAM,YAAY,iBAAiB;AAQrC,OAAK,UAAU;GACb,UAAU;GACV,MAAM,sBALK,SAHK,cAAc,GAAG,GAAG,EACjB,WAE0B,EAAE,OAAO,eAAe,CAAC,EACrD,4BAA4B,cAAc,CAId;GAC9C;;;;;;;CAQH,AAAS,cAAyB;AAChC,SAAO,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,EAAE"}
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -11,11 +11,11 @@
11
11
  */
12
12
 
13
13
 
14
- import { formatRectangleTooltip } from "../../shared/constants.js";
15
14
  import { DEFAULT_DISTANCE_UNITS, getDistanceUnitAbbreviation } from "../../../../shared/units.js";
16
- import { DrawRectangleMode } from "@deck.gl-community/editable-layers";
15
+ import { formatRectangleTooltip } from "../../shared/constants.js";
17
16
  import { area, bbox, bboxPolygon, convertArea, destination, distance } from "@turf/turf";
18
- import { featureCollection, point as point$1 } from "@turf/helpers";
17
+ import { DrawRectangleMode } from "@deck.gl-community/editable-layers";
18
+ import { featureCollection, point } from "@turf/helpers";
19
19
 
20
20
  //#region src/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.ts
21
21
  /**
@@ -67,12 +67,12 @@ var DrawRectangleModeWithTooltip = class extends DrawRectangleMode {
67
67
  const lat1 = coord1[1] ?? 0;
68
68
  const lon2 = coord2[0] ?? 0;
69
69
  const lat2 = coord2[1] ?? 0;
70
- const horizontalDist = distance(point$1([lon1, lat1]), point$1([lon2, lat1]), { units: "kilometers" });
71
- const verticalDist = distance(point$1([lon1, lat1]), point$1([lon1, lat2]), { units: "kilometers" });
70
+ const horizontalDist = distance(point([lon1, lat1]), point([lon2, lat1]), { units: "kilometers" });
71
+ const verticalDist = distance(point([lon1, lat1]), point([lon1, lat2]), { units: "kilometers" });
72
72
  const maxDist = Math.max(horizontalDist, verticalDist);
73
73
  const lonSign = lon2 >= lon1 ? 1 : -1;
74
74
  const latSign = lat2 >= lat1 ? 1 : -1;
75
- finalCoord2 = destination(destination(point$1([lon1, lat1]), maxDist, lonSign > 0 ? 90 : 270, { units: "kilometers" }), maxDist, latSign > 0 ? 0 : 180, { units: "kilometers" }).geometry.coordinates;
75
+ finalCoord2 = destination(destination(point([lon1, lat1]), maxDist, lonSign > 0 ? 90 : 270, { units: "kilometers" }), maxDist, latSign > 0 ? 0 : 180, { units: "kilometers" }).geometry.coordinates;
76
76
  }
77
77
  return super.getTwoClickPolygon(coord1, finalCoord2, modeConfig);
78
78
  }
@@ -89,17 +89,16 @@ var DrawRectangleModeWithTooltip = class extends DrawRectangleMode {
89
89
  handlePointerMove(event, props) {
90
90
  this.isShiftPressed = event.sourceEvent?.shiftKey ?? false;
91
91
  super.handlePointerMove(event, props);
92
- const clickSequence = this.getClickSequence();
93
- const firstClick = clickSequence[clickSequence.length - 1];
92
+ const firstClick = this.getClickSequence().at(-1);
94
93
  if (!firstClick) {
95
94
  this.tooltip = null;
96
95
  return;
97
96
  }
98
97
  const { mapCoords } = event;
99
98
  const distanceUnits = props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;
100
- const firstClickPoint = point$1(firstClick);
101
- const currentPoint = point$1(mapCoords);
102
- const cornerPoint = point$1([firstClick[0], mapCoords[1]]);
99
+ const firstClickPoint = point(firstClick);
100
+ const currentPoint = point(mapCoords);
101
+ const cornerPoint = point([firstClick[0], mapCoords[1]]);
103
102
  this.tooltip = {
104
103
  position: mapCoords,
105
104
  text: formatRectangleTooltip(distance(firstClickPoint, cornerPoint, { units: distanceUnits }), distance(currentPoint, cornerPoint, { units: distanceUnits }), convertArea(area(bboxPolygon(bbox(featureCollection([firstClickPoint, currentPoint])))), "meters", distanceUnits), getDistanceUnitAbbreviation(distanceUnits))
@@ -1 +1 @@
1
- {"version":3,"file":"draw-rectangle-mode-with-tooltip.js","names":["point"],"sources":["../../../../../src/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.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 DrawRectangleMode,\n type FeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type Tooltip,\n} from '@deck.gl-community/editable-layers';\nimport { featureCollection, point } from '@turf/helpers';\nimport {\n area,\n bbox,\n bboxPolygon,\n convertArea,\n destination,\n distance,\n} from '@turf/turf';\nimport {\n DEFAULT_DISTANCE_UNITS,\n getDistanceUnitAbbreviation,\n} from '@/shared/units';\nimport { formatRectangleTooltip } from '../../shared/constants';\nimport type { Position } from 'geojson';\n\n/**\n * Extends DrawRectangleMode to display dimensions and area tooltip.\n *\n * Shows the width, height, and total area of the rectangle being drawn.\n * The tooltip updates in real-time as the cursor moves, displaying measurements\n * in the configured distance units.\n *\n * ## Drawing Flow\n * 1. Click to set first corner\n * 2. Move cursor (tooltip shows dimensions and area)\n * 3. Click to set opposite corner and finish the rectangle\n *\n * ## Shift-to-Square Constraint\n * Hold Shift while drawing to constrain the rectangle to a square with equal sides.\n * Uses real-world distances (via Turf.js) to account for lat/lon distortion.\n *\n * @example\n * ```typescript\n * import { DrawRectangleModeWithTooltip } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Used internally by DrawShapeLayer\n * const mode = new DrawRectangleModeWithTooltip();\n * ```\n */\nexport class DrawRectangleModeWithTooltip extends DrawRectangleMode {\n /** Current tooltip state (null when not drawing) */\n private tooltip: Tooltip | null = null;\n /** Tracks whether Shift key is currently pressed for square constraint */\n private isShiftPressed = false;\n\n /**\n * Override getTwoClickPolygon to support Shift-constrained squares.\n *\n * When Shift is held, constrains the rectangle to a square by using the larger\n * of the horizontal or vertical distances as the side length. Uses real-world\n * geographic distances (via Turf.js) to account for lat/lon distortion at different\n * latitudes.\n *\n * @param coord1 - First corner coordinates [lon, lat]\n * @param coord2 - Second corner coordinates [lon, lat]\n * @param modeConfig - Mode configuration options\n * @returns Polygon geometry for the rectangle or square\n */\n override getTwoClickPolygon(\n coord1: Position,\n coord2: Position,\n modeConfig: ModeProps<FeatureCollection>['modeConfig'],\n ) {\n let finalCoord2 = coord2;\n\n // If Shift is pressed, constrain to a square using real distances\n if (this.isShiftPressed && coord1 && coord2) {\n const lon1 = coord1[0] ?? 0;\n const lat1 = coord1[1] ?? 0;\n const lon2 = coord2[0] ?? 0;\n const lat2 = coord2[1] ?? 0;\n\n // Calculate real-world distances using turf\n // Horizontal distance (along latitude)\n const horizontalDist = distance(\n point([lon1, lat1]),\n point([lon2, lat1]),\n {\n units: 'kilometers',\n },\n );\n // Vertical distance (along longitude)\n const verticalDist = distance(point([lon1, lat1]), point([lon1, lat2]), {\n units: 'kilometers',\n });\n\n // Use the larger distance for the square side\n const maxDist = Math.max(horizontalDist, verticalDist);\n\n // Determine direction signs\n const lonSign = lon2 >= lon1 ? 1 : -1;\n const latSign = lat2 >= lat1 ? 1 : -1;\n\n // Calculate new corner using destination() for accurate geographic positioning\n // Move horizontally from coord1\n const horizontalPoint = destination(\n point([lon1, lat1]),\n maxDist,\n lonSign > 0 ? 90 : 270,\n {\n units: 'kilometers',\n },\n );\n // Move vertically from that point\n const cornerPoint = destination(\n horizontalPoint,\n maxDist,\n latSign > 0 ? 0 : 180,\n {\n units: 'kilometers',\n },\n );\n\n finalCoord2 = cornerPoint.geometry.coordinates;\n }\n\n // Call parent implementation with potentially adjusted coordinates\n return super.getTwoClickPolygon(coord1, finalCoord2, modeConfig);\n }\n\n /**\n * Handle pointer move events to update the tooltip with rectangle measurements.\n *\n * Tracks the Shift key state for square constraint and calculates the width,\n * height, and area of the rectangle being drawn. Uses Turf.js for accurate\n * geographic distance and area calculations.\n *\n * @param event - Pointer move event with cursor position and source event\n * @param props - Mode properties including distance units configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n // Track shift key state from the source event\n const sourceEvent = event.sourceEvent as KeyboardEvent | undefined;\n this.isShiftPressed = sourceEvent?.shiftKey ?? false;\n\n super.handlePointerMove(event, props);\n\n const clickSequence = this.getClickSequence();\n const firstClick = clickSequence[clickSequence.length - 1];\n if (!firstClick) {\n this.tooltip = null;\n return;\n }\n\n const { mapCoords } = event;\n const distanceUnits =\n props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;\n\n const firstClickPoint = point(firstClick);\n const currentPoint = point(mapCoords);\n\n // Calculate dimensions by finding the corner point\n const cornerPoint = point([\n firstClick[0] as number,\n mapCoords[1] as number,\n ]);\n const dimension1 = distance(firstClickPoint, cornerPoint, {\n units: distanceUnits,\n });\n const dimension2 = distance(currentPoint, cornerPoint, {\n units: distanceUnits,\n });\n\n // Calculate area properly accounting for Earth's curvature\n const points = featureCollection([firstClickPoint, currentPoint]);\n const bboxPoly = bboxPolygon(bbox(points));\n const rectArea = area(bboxPoly);\n const convertedArea = convertArea(rectArea, 'meters', distanceUnits);\n const unitAbbrev = getDistanceUnitAbbreviation(distanceUnits);\n\n this.tooltip = {\n position: mapCoords,\n text: formatRectangleTooltip(\n dimension1,\n dimension2,\n convertedArea,\n unitAbbrev,\n ),\n };\n }\n\n /**\n * Get the current tooltip array for rendering.\n *\n * @returns Array containing the tooltip if one is active, empty array otherwise\n */\n override getTooltips(): Tooltip[] {\n return this.tooltip ? [this.tooltip] : [];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,IAAa,+BAAb,cAAkD,kBAAkB;;CAElE,AAAQ,UAA0B;;CAElC,AAAQ,iBAAiB;;;;;;;;;;;;;;CAezB,AAAS,mBACP,QACA,QACA,YACA;EACA,IAAI,cAAc;AAGlB,MAAI,KAAK,kBAAkB,UAAU,QAAQ;GAC3C,MAAM,OAAO,OAAO,MAAM;GAC1B,MAAM,OAAO,OAAO,MAAM;GAC1B,MAAM,OAAO,OAAO,MAAM;GAC1B,MAAM,OAAO,OAAO,MAAM;GAI1B,MAAM,iBAAiB,SACrBA,QAAM,CAAC,MAAM,KAAK,CAAC,EACnBA,QAAM,CAAC,MAAM,KAAK,CAAC,EACnB,EACE,OAAO,cACR,CACF;GAED,MAAM,eAAe,SAASA,QAAM,CAAC,MAAM,KAAK,CAAC,EAAEA,QAAM,CAAC,MAAM,KAAK,CAAC,EAAE,EACtE,OAAO,cACR,CAAC;GAGF,MAAM,UAAU,KAAK,IAAI,gBAAgB,aAAa;GAGtD,MAAM,UAAU,QAAQ,OAAO,IAAI;GACnC,MAAM,UAAU,QAAQ,OAAO,IAAI;AAsBnC,iBAToB,YATI,YACtBA,QAAM,CAAC,MAAM,KAAK,CAAC,EACnB,SACA,UAAU,IAAI,KAAK,KACnB,EACE,OAAO,cACR,CACF,EAIC,SACA,UAAU,IAAI,IAAI,KAClB,EACE,OAAO,cACR,CACF,CAEyB,SAAS;;AAIrC,SAAO,MAAM,mBAAmB,QAAQ,aAAa,WAAW;;;;;;;;;;;;CAalE,AAAS,kBACP,OACA,OACA;AAGA,OAAK,iBADe,MAAM,aACS,YAAY;AAE/C,QAAM,kBAAkB,OAAO,MAAM;EAErC,MAAM,gBAAgB,KAAK,kBAAkB;EAC7C,MAAM,aAAa,cAAc,cAAc,SAAS;AACxD,MAAI,CAAC,YAAY;AACf,QAAK,UAAU;AACf;;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBACJ,MAAM,YAAY,iBAAiB;EAErC,MAAM,kBAAkBA,QAAM,WAAW;EACzC,MAAM,eAAeA,QAAM,UAAU;EAGrC,MAAM,cAAcA,QAAM,CACxB,WAAW,IACX,UAAU,GACX,CAAC;AAeF,OAAK,UAAU;GACb,UAAU;GACV,MAAM,uBAhBW,SAAS,iBAAiB,aAAa,EACxD,OAAO,eACR,CAAC,EACiB,SAAS,cAAc,aAAa,EACrD,OAAO,eACR,CAAC,EAMoB,YADL,KADA,YAAY,KADd,kBAAkB,CAAC,iBAAiB,aAAa,CAAC,CACxB,CAAC,CACX,EACa,UAAU,cAAc,EACjD,4BAA4B,cAAc,CAS1D;GACF;;;;;;;CAQH,AAAS,cAAyB;AAChC,SAAO,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,EAAE"}
1
+ {"version":3,"file":"draw-rectangle-mode-with-tooltip.js","names":[],"sources":["../../../../../src/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.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 DrawRectangleMode,\n type FeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type Tooltip,\n} from '@deck.gl-community/editable-layers';\nimport { featureCollection, point } from '@turf/helpers';\nimport {\n area,\n bbox,\n bboxPolygon,\n convertArea,\n destination,\n distance,\n} from '@turf/turf';\nimport {\n DEFAULT_DISTANCE_UNITS,\n getDistanceUnitAbbreviation,\n} from '@/shared/units';\nimport { formatRectangleTooltip } from '../../shared/constants';\nimport type { Position } from 'geojson';\n\n/**\n * Extends DrawRectangleMode to display dimensions and area tooltip.\n *\n * Shows the width, height, and total area of the rectangle being drawn.\n * The tooltip updates in real-time as the cursor moves, displaying measurements\n * in the configured distance units.\n *\n * ## Drawing Flow\n * 1. Click to set first corner\n * 2. Move cursor (tooltip shows dimensions and area)\n * 3. Click to set opposite corner and finish the rectangle\n *\n * ## Shift-to-Square Constraint\n * Hold Shift while drawing to constrain the rectangle to a square with equal sides.\n * Uses real-world distances (via Turf.js) to account for lat/lon distortion.\n *\n * @example\n * ```typescript\n * import { DrawRectangleModeWithTooltip } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Used internally by DrawShapeLayer\n * const mode = new DrawRectangleModeWithTooltip();\n * ```\n */\nexport class DrawRectangleModeWithTooltip extends DrawRectangleMode {\n /** Current tooltip state (null when not drawing) */\n private tooltip: Tooltip | null = null;\n /** Tracks whether Shift key is currently pressed for square constraint */\n private isShiftPressed = false;\n\n /**\n * Override getTwoClickPolygon to support Shift-constrained squares.\n *\n * When Shift is held, constrains the rectangle to a square by using the larger\n * of the horizontal or vertical distances as the side length. Uses real-world\n * geographic distances (via Turf.js) to account for lat/lon distortion at different\n * latitudes.\n *\n * @param coord1 - First corner coordinates [lon, lat]\n * @param coord2 - Second corner coordinates [lon, lat]\n * @param modeConfig - Mode configuration options\n * @returns Polygon geometry for the rectangle or square\n */\n override getTwoClickPolygon(\n coord1: Position,\n coord2: Position,\n modeConfig: ModeProps<FeatureCollection>['modeConfig'],\n ) {\n let finalCoord2 = coord2;\n\n // If Shift is pressed, constrain to a square using real distances\n if (this.isShiftPressed && coord1 && coord2) {\n const lon1 = coord1[0] ?? 0;\n const lat1 = coord1[1] ?? 0;\n const lon2 = coord2[0] ?? 0;\n const lat2 = coord2[1] ?? 0;\n\n // Calculate real-world distances using turf\n // Horizontal distance (along latitude)\n const horizontalDist = distance(\n point([lon1, lat1]),\n point([lon2, lat1]),\n {\n units: 'kilometers',\n },\n );\n // Vertical distance (along longitude)\n const verticalDist = distance(point([lon1, lat1]), point([lon1, lat2]), {\n units: 'kilometers',\n });\n\n // Use the larger distance for the square side\n const maxDist = Math.max(horizontalDist, verticalDist);\n\n // Determine direction signs\n const lonSign = lon2 >= lon1 ? 1 : -1;\n const latSign = lat2 >= lat1 ? 1 : -1;\n\n // Calculate new corner using destination() for accurate geographic positioning\n // Move horizontally from coord1\n const horizontalPoint = destination(\n point([lon1, lat1]),\n maxDist,\n lonSign > 0 ? 90 : 270,\n {\n units: 'kilometers',\n },\n );\n // Move vertically from that point\n const cornerPoint = destination(\n horizontalPoint,\n maxDist,\n latSign > 0 ? 0 : 180,\n {\n units: 'kilometers',\n },\n );\n\n finalCoord2 = cornerPoint.geometry.coordinates;\n }\n\n // Call parent implementation with potentially adjusted coordinates\n return super.getTwoClickPolygon(coord1, finalCoord2, modeConfig);\n }\n\n /**\n * Handle pointer move events to update the tooltip with rectangle measurements.\n *\n * Tracks the Shift key state for square constraint and calculates the width,\n * height, and area of the rectangle being drawn. Uses Turf.js for accurate\n * geographic distance and area calculations.\n *\n * @param event - Pointer move event with cursor position and source event\n * @param props - Mode properties including distance units configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n // Track shift key state from the source event\n const sourceEvent = event.sourceEvent as KeyboardEvent | undefined;\n this.isShiftPressed = sourceEvent?.shiftKey ?? false;\n\n super.handlePointerMove(event, props);\n\n const clickSequence = this.getClickSequence();\n const firstClick = clickSequence.at(-1);\n if (!firstClick) {\n this.tooltip = null;\n return;\n }\n\n const { mapCoords } = event;\n const distanceUnits =\n props.modeConfig?.distanceUnits ?? DEFAULT_DISTANCE_UNITS;\n\n const firstClickPoint = point(firstClick);\n const currentPoint = point(mapCoords);\n\n // Calculate dimensions by finding the corner point\n const cornerPoint = point([\n firstClick[0] as number,\n mapCoords[1] as number,\n ]);\n const dimension1 = distance(firstClickPoint, cornerPoint, {\n units: distanceUnits,\n });\n const dimension2 = distance(currentPoint, cornerPoint, {\n units: distanceUnits,\n });\n\n // Calculate area properly accounting for Earth's curvature\n const points = featureCollection([firstClickPoint, currentPoint]);\n const bboxPoly = bboxPolygon(bbox(points));\n const rectArea = area(bboxPoly);\n const convertedArea = convertArea(rectArea, 'meters', distanceUnits);\n const unitAbbrev = getDistanceUnitAbbreviation(distanceUnits);\n\n this.tooltip = {\n position: mapCoords,\n text: formatRectangleTooltip(\n dimension1,\n dimension2,\n convertedArea,\n unitAbbrev,\n ),\n };\n }\n\n /**\n * Get the current tooltip array for rendering.\n *\n * @returns Array containing the tooltip if one is active, empty array otherwise\n */\n override getTooltips(): Tooltip[] {\n return this.tooltip ? [this.tooltip] : [];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,IAAa,+BAAb,cAAkD,kBAAkB;;CAElE,AAAQ,UAA0B;;CAElC,AAAQ,iBAAiB;;;;;;;;;;;;;;CAezB,AAAS,mBACP,QACA,QACA,YACA;EACA,IAAI,cAAc;AAGlB,MAAI,KAAK,kBAAkB,UAAU,QAAQ;GAC3C,MAAM,OAAO,OAAO,MAAM;GAC1B,MAAM,OAAO,OAAO,MAAM;GAC1B,MAAM,OAAO,OAAO,MAAM;GAC1B,MAAM,OAAO,OAAO,MAAM;GAI1B,MAAM,iBAAiB,SACrB,MAAM,CAAC,MAAM,KAAK,CAAC,EACnB,MAAM,CAAC,MAAM,KAAK,CAAC,EACnB,EACE,OAAO,cACR,CACF;GAED,MAAM,eAAe,SAAS,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,EACtE,OAAO,cACR,CAAC;GAGF,MAAM,UAAU,KAAK,IAAI,gBAAgB,aAAa;GAGtD,MAAM,UAAU,QAAQ,OAAO,IAAI;GACnC,MAAM,UAAU,QAAQ,OAAO,IAAI;AAsBnC,iBAToB,YATI,YACtB,MAAM,CAAC,MAAM,KAAK,CAAC,EACnB,SACA,UAAU,IAAI,KAAK,KACnB,EACE,OAAO,cACR,CACF,EAIC,SACA,UAAU,IAAI,IAAI,KAClB,EACE,OAAO,cACR,CACF,CAEyB,SAAS;;AAIrC,SAAO,MAAM,mBAAmB,QAAQ,aAAa,WAAW;;;;;;;;;;;;CAalE,AAAS,kBACP,OACA,OACA;AAGA,OAAK,iBADe,MAAM,aACS,YAAY;AAE/C,QAAM,kBAAkB,OAAO,MAAM;EAGrC,MAAM,aADgB,KAAK,kBAAkB,CACZ,GAAG,GAAG;AACvC,MAAI,CAAC,YAAY;AACf,QAAK,UAAU;AACf;;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBACJ,MAAM,YAAY,iBAAiB;EAErC,MAAM,kBAAkB,MAAM,WAAW;EACzC,MAAM,eAAe,MAAM,UAAU;EAGrC,MAAM,cAAc,MAAM,CACxB,WAAW,IACX,UAAU,GACX,CAAC;AAeF,OAAK,UAAU;GACb,UAAU;GACV,MAAM,uBAhBW,SAAS,iBAAiB,aAAa,EACxD,OAAO,eACR,CAAC,EACiB,SAAS,cAAc,aAAa,EACrD,OAAO,eACR,CAAC,EAMoB,YADL,KADA,YAAY,KADd,kBAAkB,CAAC,iBAAiB,aAAa,CAAC,CACxB,CAAC,CACX,EACa,UAAU,cAAc,EACjD,4BAA4B,cAAc,CAS1D;GACF;;;;;;;CAQH,AAAS,cAAyB;AAChC,SAAO,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,EAAE"}
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -64,37 +64,7 @@ const MODE_INSTANCES = {
64
64
  function getModeInstance(shapeType) {
65
65
  return MODE_INSTANCES[shapeType];
66
66
  }
67
- /**
68
- * Trigger double-click finish on the active drawing mode.
69
- *
70
- * This is a workaround for @deck.gl-community/editable-layers ~9.1 which doesn't
71
- * register 'dblclick' in EVENT_TYPES. We listen for dblclick at the DOM level
72
- * and call this function to finish drawing.
73
- *
74
- * Only LineString and Polygon modes support double-click to finish. Other shape
75
- * types are completed with a single click and ignore this call.
76
- *
77
- * @param shapeType - The shape type currently being drawn
78
- * @see https://github.com/visgl/deck.gl-community/pull/225
79
- *
80
- * @example
81
- * ```typescript
82
- * import { triggerDoubleClickFinish } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';
83
- * import { ShapeFeatureType } from '@accelint/map-toolkit/deckgl/shapes/shared/types';
84
- *
85
- * // Listen for double-click at the DOM level
86
- * mapContainer.addEventListener('dblclick', () => {
87
- * if (currentShapeType === ShapeFeatureType.Polygon) {
88
- * triggerDoubleClickFinish(currentShapeType);
89
- * }
90
- * });
91
- * ```
92
- */
93
- function triggerDoubleClickFinish(shapeType) {
94
- const mode = MODE_INSTANCES[shapeType];
95
- if (mode instanceof DrawPolygonModeWithTooltip || mode instanceof DrawLineStringModeWithTooltip) mode.handleDoubleClick();
96
- }
97
67
 
98
68
  //#endregion
99
- export { getModeInstance, triggerDoubleClickFinish };
69
+ export { getModeInstance };
100
70
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/deckgl/shapes/draw-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 { DrawPointMode, ViewMode } from '@deck.gl-community/editable-layers';\nimport { ShapeFeatureType } from '../../shared/types';\nimport { DrawCircleModeWithTooltip } from './draw-circle-mode-with-tooltip';\nimport { DrawEllipseModeWithTooltip } from './draw-ellipse-mode-with-tooltip';\nimport { DrawLineStringModeWithTooltip } from './draw-line-string-mode-with-tooltip';\nimport { DrawPolygonModeWithTooltip } from './draw-polygon-mode-with-tooltip';\nimport { DrawRectangleModeWithTooltip } from './draw-rectangle-mode-with-tooltip';\n\nexport { DrawCircleModeWithTooltip } from './draw-circle-mode-with-tooltip';\nexport { DrawEllipseModeWithTooltip } from './draw-ellipse-mode-with-tooltip';\nexport { DrawLineStringModeWithTooltip } from './draw-line-string-mode-with-tooltip';\nexport { DrawPolygonModeWithTooltip } from './draw-polygon-mode-with-tooltip';\nexport { DrawRectangleModeWithTooltip } from './draw-rectangle-mode-with-tooltip';\n\n/**\n * Cached 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 */\nconst MODE_INSTANCES = {\n [ShapeFeatureType.Point]: new DrawPointMode(),\n [ShapeFeatureType.LineString]: new DrawLineStringModeWithTooltip(),\n [ShapeFeatureType.Polygon]: new DrawPolygonModeWithTooltip(),\n [ShapeFeatureType.Rectangle]: new DrawRectangleModeWithTooltip(),\n [ShapeFeatureType.Circle]: new DrawCircleModeWithTooltip(),\n [ShapeFeatureType.Ellipse]: new DrawEllipseModeWithTooltip(),\n view: new ViewMode(),\n};\n\n/**\n * Get the cached mode instance for a shape type.\n *\n * Returns the pre-instantiated drawing mode for the specified shape 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 * @param shapeType - The shape type to get the mode for\n * @returns The cached mode instance for drawing that shape type\n *\n * @example\n * ```typescript\n * import { getModeInstance } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n * import { ShapeFeatureType } from '@accelint/map-toolkit/deckgl/shapes/shared/types';\n *\n * // Get the mode for drawing circles\n * const circleMode = getModeInstance(ShapeFeatureType.Circle);\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: circleMode,\n * // ... other props\n * });\n * ```\n */\nexport function getModeInstance(\n shapeType: ShapeFeatureType,\n): (typeof MODE_INSTANCES)[ShapeFeatureType] {\n return MODE_INSTANCES[shapeType];\n}\n\n/**\n * Get the view mode instance (for when not drawing).\n *\n * Returns the pre-instantiated ViewMode which is the default mode when\n * no drawing operation is active. This mode allows viewing and interacting\n * with the map without drawing new shapes.\n *\n * @returns The cached ViewMode instance\n *\n * @example\n * ```typescript\n * import { getViewModeInstance } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Get the view mode (default when not drawing)\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 MODE_INSTANCES.view;\n}\n\n/**\n * Trigger double-click finish on the active drawing mode.\n *\n * This is a workaround for @deck.gl-community/editable-layers ~9.1 which doesn't\n * register 'dblclick' in EVENT_TYPES. We listen for dblclick at the DOM level\n * and call this function to finish drawing.\n *\n * Only LineString and Polygon modes support double-click to finish. Other shape\n * types are completed with a single click and ignore this call.\n *\n * @param shapeType - The shape type currently being drawn\n * @see https://github.com/visgl/deck.gl-community/pull/225\n *\n * @example\n * ```typescript\n * import { triggerDoubleClickFinish } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n * import { ShapeFeatureType } from '@accelint/map-toolkit/deckgl/shapes/shared/types';\n *\n * // Listen for double-click at the DOM level\n * mapContainer.addEventListener('dblclick', () => {\n * if (currentShapeType === ShapeFeatureType.Polygon) {\n * triggerDoubleClickFinish(currentShapeType);\n * }\n * });\n * ```\n */\nexport function triggerDoubleClickFinish(shapeType: ShapeFeatureType): void {\n const mode = MODE_INSTANCES[shapeType];\n\n // Only Polygon and LineString modes support double-click to finish\n if (\n mode instanceof DrawPolygonModeWithTooltip ||\n mode instanceof DrawLineStringModeWithTooltip\n ) {\n mode.handleDoubleClick();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAM,iBAAiB;EACpB,iBAAiB,QAAQ,IAAI,eAAe;EAC5C,iBAAiB,aAAa,IAAI,+BAA+B;EACjE,iBAAiB,UAAU,IAAI,4BAA4B;EAC3D,iBAAiB,YAAY,IAAI,8BAA8B;EAC/D,iBAAiB,SAAS,IAAI,2BAA2B;EACzD,iBAAiB,UAAU,IAAI,4BAA4B;CAC5D,MAAM,IAAI,UAAU;CACrB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BD,SAAgB,gBACd,WAC2C;AAC3C,QAAO,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDxB,SAAgB,yBAAyB,WAAmC;CAC1E,MAAM,OAAO,eAAe;AAG5B,KACE,gBAAgB,8BAChB,gBAAgB,8BAEhB,MAAK,mBAAmB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/deckgl/shapes/draw-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 { DrawPointMode, ViewMode } from '@deck.gl-community/editable-layers';\nimport { ShapeFeatureType } from '../../shared/types';\nimport { DrawCircleModeWithTooltip } from './draw-circle-mode-with-tooltip';\nimport { DrawEllipseModeWithTooltip } from './draw-ellipse-mode-with-tooltip';\nimport { DrawLineStringModeWithTooltip } from './draw-line-string-mode-with-tooltip';\nimport { DrawPolygonModeWithTooltip } from './draw-polygon-mode-with-tooltip';\nimport { DrawRectangleModeWithTooltip } from './draw-rectangle-mode-with-tooltip';\n\nexport { DrawCircleModeWithTooltip } from './draw-circle-mode-with-tooltip';\nexport { DrawEllipseModeWithTooltip } from './draw-ellipse-mode-with-tooltip';\nexport { DrawLineStringModeWithTooltip } from './draw-line-string-mode-with-tooltip';\nexport { DrawPolygonModeWithTooltip } from './draw-polygon-mode-with-tooltip';\nexport { DrawRectangleModeWithTooltip } from './draw-rectangle-mode-with-tooltip';\n\n/**\n * Cached 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 */\nconst MODE_INSTANCES = {\n [ShapeFeatureType.Point]: new DrawPointMode(),\n [ShapeFeatureType.LineString]: new DrawLineStringModeWithTooltip(),\n [ShapeFeatureType.Polygon]: new DrawPolygonModeWithTooltip(),\n [ShapeFeatureType.Rectangle]: new DrawRectangleModeWithTooltip(),\n [ShapeFeatureType.Circle]: new DrawCircleModeWithTooltip(),\n [ShapeFeatureType.Ellipse]: new DrawEllipseModeWithTooltip(),\n view: new ViewMode(),\n};\n\n/**\n * Get the cached mode instance for a shape type.\n *\n * Returns the pre-instantiated drawing mode for the specified shape 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 * @param shapeType - The shape type to get the mode for\n * @returns The cached mode instance for drawing that shape type\n *\n * @example\n * ```typescript\n * import { getModeInstance } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n * import { ShapeFeatureType } from '@accelint/map-toolkit/deckgl/shapes/shared/types';\n *\n * // Get the mode for drawing circles\n * const circleMode = getModeInstance(ShapeFeatureType.Circle);\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: circleMode,\n * // ... other props\n * });\n * ```\n */\nexport function getModeInstance(\n shapeType: ShapeFeatureType,\n): (typeof MODE_INSTANCES)[ShapeFeatureType] {\n return MODE_INSTANCES[shapeType];\n}\n\n/**\n * Get the view mode instance (for when not drawing).\n *\n * Returns the pre-instantiated ViewMode which is the default mode when\n * no drawing operation is active. This mode allows viewing and interacting\n * with the map without drawing new shapes.\n *\n * @returns The cached ViewMode instance\n *\n * @example\n * ```typescript\n * import { getViewModeInstance } from '@accelint/map-toolkit/deckgl/shapes/draw-shape-layer/modes';\n *\n * // Get the view mode (default when not drawing)\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 MODE_INSTANCES.view;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAM,iBAAiB;EACpB,iBAAiB,QAAQ,IAAI,eAAe;EAC5C,iBAAiB,aAAa,IAAI,+BAA+B;EACjE,iBAAiB,UAAU,IAAI,4BAA4B;EAC3D,iBAAiB,YAAY,IAAI,8BAA8B;EAC/D,iBAAiB,SAAS,IAAI,2BAA2B;EACzD,iBAAiB,UAAU,IAAI,4BAA4B;CAC5D,MAAM,IAAI,UAAU;CACrB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BD,SAAgB,gBACd,WAC2C;AAC3C,QAAO,eAAe"}
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -15,9 +15,9 @@
15
15
 
16
16
  import { createMapStore } from "../../../shared/create-map-store.js";
17
17
  import { MapModeEvents } from "../../../map-mode/events.js";
18
- import { DrawShapeEvents } from "./events.js";
19
- import { DRAW_CURSOR_MAP, DRAW_SHAPE_LAYER_ID, DRAW_SHAPE_MODE } from "./constants.js";
20
18
  import { releaseModeAndCursor, requestModeAndCursor } from "../shared/utils/mode-utils.js";
19
+ import { DRAW_CURSOR_MAP, DRAW_SHAPE_LAYER_ID, DRAW_SHAPE_MODE } from "./constants.js";
20
+ import { DrawShapeEvents } from "./events.js";
21
21
  import { convertFeatureToShape } from "./utils/feature-conversion.js";
22
22
  import { Broadcast } from "@accelint/bus";
23
23
 
@@ -158,6 +158,40 @@ const drawStore = createMapStore({
158
158
  }
159
159
  });
160
160
  /**
161
+ * Manually clear the drawing state for a specific map instance.
162
+ *
163
+ * Removes the drawing store instance for the given map ID, canceling any
164
+ * active drawing operation and releasing mode/cursor ownership. This is
165
+ * typically called automatically during cleanup, but can be used manually
166
+ * when needed.
167
+ *
168
+ * ## When to Use
169
+ * - Cleanup after programmatically managing drawing state
170
+ * - Force-reset drawing state in error conditions
171
+ * - Testing and debugging
172
+ *
173
+ * ## Side Effects
174
+ * - Cancels active drawing (if any)
175
+ * - Releases map mode and cursor
176
+ * - Emits 'shapes:draw-canceled' event
177
+ * - Removes store instance from memory
178
+ *
179
+ * @param mapId - Unique identifier for the map instance
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * import { clearDrawingState } from '@accelint/map-toolkit/deckgl/shapes';
184
+ *
185
+ * // Clear drawing state when unmounting a map
186
+ * function cleanup(mapId: UniqueId) {
187
+ * clearDrawingState(mapId);
188
+ * }
189
+ * ```
190
+ */
191
+ function clearDrawingState(mapId) {
192
+ drawStore.clear(mapId);
193
+ }
194
+ /**
161
195
  * Complete the drawing operation with a GeoJSON feature.
162
196
  *
163
197
  * Called internally by the DrawShapeLayer component when the user finishes
@@ -219,5 +253,5 @@ function cancelDrawingFromLayer(mapId) {
219
253
  }
220
254
 
221
255
  //#endregion
222
- export { cancelDrawingFromLayer, completeDrawingFromLayer, drawStore };
256
+ export { cancelDrawingFromLayer, clearDrawingState, completeDrawingFromLayer, drawStore };
223
257
  //# sourceMappingURL=store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","names":["DEFAULT_DRAWING_STATE: DrawingState"],"sources":["../../../../src/deckgl/shapes/draw-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 * Draw Shape Store\n *\n * Manages drawing state for shape creation.\n *\n * @example\n * ```tsx\n * import { drawStore } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * function DrawControls({ mapId }) {\n * const { state, draw, cancel } = drawStore.use(mapId);\n *\n * return (\n * <div>\n * <p>Drawing: {state.activeShapeType ?? 'none'}</p>\n * <button onClick={() => draw('Polygon')}>Draw Polygon</button>\n * <button onClick={cancel}>Cancel</button>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { MapModeEvents } from '@/map-mode/events';\nimport { createMapStore } from '@/shared/create-map-store';\nimport {\n releaseModeAndCursor,\n requestModeAndCursor,\n} from '../shared/utils/mode-utils';\nimport {\n DRAW_CURSOR_MAP,\n DRAW_SHAPE_LAYER_ID,\n DRAW_SHAPE_MODE,\n} from './constants';\nimport { DrawShapeEvents } from './events';\nimport { convertFeatureToShape } from './utils/feature-conversion';\nimport type { UniqueId } from '@accelint/core';\nimport type { Feature } from 'geojson';\nimport type { MapModeEventType } from '@/map-mode/types';\nimport type { Shape, ShapeFeatureType } from '../shared/types';\nimport type { DrawShapeEvent, ShapeDrawnEvent } from './events';\nimport type { DrawFunction, DrawingState, DrawShapeOptions } from './types';\n\n/**\n * Typed event bus instances\n */\nconst drawShapeBus = Broadcast.getInstance<DrawShapeEvent>();\nconst mapModeBus = Broadcast.getInstance<MapModeEventType>();\n\n/**\n * Default drawing state\n */\nconst DEFAULT_DRAWING_STATE: DrawingState = {\n activeShapeType: null,\n tentativeFeature: null,\n styleDefaults: null,\n circleDefaults: null,\n};\n\n/**\n * Actions for draw shape store\n */\ntype DrawShapeActions = {\n /** Start drawing a shape of the specified type */\n draw: DrawFunction;\n /** Cancel the current drawing operation */\n cancel: () => void;\n};\n\n/**\n * Start drawing a shape\n */\nfunction startDrawing(\n mapId: UniqueId,\n state: DrawingState,\n shapeType: ShapeFeatureType,\n options: DrawShapeOptions | undefined,\n notify: () => void,\n setState: (updates: Partial<DrawingState>) => void,\n): void {\n // Already drawing - cancel first\n if (state.activeShapeType) {\n cancelDrawingInternal(mapId, state, notify, setState);\n }\n\n // Update state with new object reference\n setState({\n activeShapeType: shapeType,\n tentativeFeature: null,\n styleDefaults: options?.styleDefaults ?? null,\n circleDefaults: options?.circleDefaults ?? null,\n });\n\n // Request map mode and cursor using shared utilities\n const cursor = DRAW_CURSOR_MAP[shapeType];\n requestModeAndCursor(mapId, DRAW_SHAPE_MODE, cursor, DRAW_SHAPE_LAYER_ID);\n\n // Emit drawing started event\n drawShapeBus.emit(DrawShapeEvents.drawing, {\n shapeType,\n mapId,\n });\n\n notify();\n}\n\n/**\n * Complete drawing and create a shape\n */\nfunction completeDrawingInternal(\n mapId: UniqueId,\n state: DrawingState,\n feature: Feature,\n notify: () => void,\n setState: (updates: Partial<DrawingState>) => void,\n): Shape {\n if (!state.activeShapeType) {\n throw new Error('Cannot complete drawing - not currently drawing');\n }\n\n const shapeType = state.activeShapeType;\n const styleDefaults = state.styleDefaults;\n\n // Convert feature to Shape\n const shape = convertFeatureToShape(feature, shapeType, styleDefaults);\n\n // Reset state with new object reference\n setState({\n activeShapeType: null,\n tentativeFeature: null,\n styleDefaults: null,\n circleDefaults: null,\n });\n\n // Release mode and cursor using shared utilities\n releaseModeAndCursor(mapId, DRAW_SHAPE_LAYER_ID);\n\n // Emit shape drawn event\n drawShapeBus.emit(DrawShapeEvents.drawn, {\n shape,\n mapId,\n } as unknown as ShapeDrawnEvent['payload']);\n\n notify();\n\n return shape;\n}\n\n/**\n * Cancel the current drawing operation\n */\nfunction cancelDrawingInternal(\n mapId: UniqueId,\n state: DrawingState,\n notify: () => void,\n setState: (updates: Partial<DrawingState>) => void,\n): void {\n if (!state.activeShapeType) {\n return; // Nothing to cancel\n }\n\n const shapeType = state.activeShapeType;\n\n // Reset state with new object reference\n setState({\n activeShapeType: null,\n tentativeFeature: null,\n styleDefaults: null,\n circleDefaults: null,\n });\n\n // Release mode and cursor using shared utilities\n releaseModeAndCursor(mapId, DRAW_SHAPE_LAYER_ID);\n\n // Emit canceled event\n drawShapeBus.emit(DrawShapeEvents.canceled, {\n shapeType,\n mapId,\n });\n\n notify();\n}\n\n/**\n * Draw shape store\n */\nexport const drawStore = createMapStore<DrawingState, DrawShapeActions>({\n defaultState: { ...DEFAULT_DRAWING_STATE },\n\n actions: (mapId, { get, set, notify }) => ({\n draw: (shapeType: ShapeFeatureType, options?: DrawShapeOptions) => {\n startDrawing(mapId, get(), shapeType, options, notify, set);\n },\n\n cancel: () => {\n cancelDrawingInternal(mapId, get(), notify, set);\n },\n }),\n\n bus: (mapId, { get }) => {\n // Listen for mode authorization requests - REJECT when drawing (protected mode)\n const unsubAuth = mapModeBus.on(\n MapModeEvents.changeAuthorization,\n (event) => {\n const { authId, id } = event.payload;\n\n // Filter: only handle if targeted at this map\n if (id !== mapId) {\n return;\n }\n\n // If we're actively drawing, reject the mode change request\n if (get().activeShapeType) {\n mapModeBus.emit(MapModeEvents.changeDecision, {\n authId,\n approved: false,\n owner: DRAW_SHAPE_LAYER_ID,\n reason: 'Drawing in progress - cancel drawing first',\n id: mapId,\n });\n }\n },\n );\n\n return () => {\n unsubAuth();\n };\n },\n\n onCleanup: (mapId, state) => {\n // Cancel any active drawing before cleanup\n if (state.activeShapeType) {\n // Release mode and cursor using shared utilities\n releaseModeAndCursor(mapId, DRAW_SHAPE_LAYER_ID);\n\n // Emit canceled event\n drawShapeBus.emit(DrawShapeEvents.canceled, {\n shapeType: state.activeShapeType,\n mapId,\n });\n }\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get the current drawing state for a map instance.\n *\n * Returns the drawing state (active shape type, style defaults, etc.) for the\n * specified map ID. Returns null if no drawing store instance exists for that map.\n *\n * ## Use Cases\n * - Check if a map is currently in drawing mode\n * - Access drawing state outside of React components\n * - Inspect state for debugging purposes\n *\n * @param mapId - Unique identifier for the map instance\n * @returns The drawing state, or null if no store instance exists\n *\n * @example\n * ```typescript\n * import { getDrawingState } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * const state = getDrawingState('map-1');\n * if (state?.activeShapeType) {\n * console.log(`Currently drawing: ${state.activeShapeType}`);\n * }\n * ```\n */\nexport function getDrawingState(mapId: UniqueId): DrawingState | null {\n if (!drawStore.exists(mapId)) {\n return null;\n }\n return drawStore.get(mapId);\n}\n\n/**\n * React hook for accessing drawing state and actions.\n *\n * Provides access to the drawing store for a specific map instance, including\n * the current state and draw/cancel actions. Uses `useSyncExternalStore` for\n * concurrent-safe React subscriptions.\n *\n * ## Comparison with useDrawShape\n * - `useDrawingState`: Low-level store access without event callbacks\n * - `useDrawShape`: High-level API with onCreate/onCancel callbacks\n *\n * Use `useDrawingState` when you need direct store access without event handling.\n * Use `useDrawShape` (recommended) for most drawing interactions.\n *\n * @param mapId - Unique identifier for the map instance\n * @returns Object containing drawing state and actions (draw, cancel)\n *\n * @example\n * ```tsx\n * import { useDrawingState } from '@accelint/map-toolkit/deckgl/shapes';\n * import { ShapeFeatureType } from '@accelint/map-toolkit/deckgl/shapes/shared/types';\n *\n * function DrawingStatus({ mapId }: { mapId: UniqueId }) {\n * const { state, draw, cancel } = useDrawingState(mapId);\n *\n * return (\n * <div>\n * <p>Status: {state.activeShapeType ?? 'Not drawing'}</p>\n * <button onClick={() => draw(ShapeFeatureType.Polygon)}>\n * Start Drawing\n * </button>\n * {state.activeShapeType && (\n * <button onClick={cancel}>Cancel</button>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useDrawingState(\n mapId: UniqueId,\n): { state: DrawingState } & DrawShapeActions {\n return drawStore.use(mapId);\n}\n\n/**\n * Manually clear the drawing state for a specific map instance.\n *\n * Removes the drawing store instance for the given map ID, canceling any\n * active drawing operation and releasing mode/cursor ownership. This is\n * typically called automatically during cleanup, but can be used manually\n * when needed.\n *\n * ## When to Use\n * - Cleanup after programmatically managing drawing state\n * - Force-reset drawing state in error conditions\n * - Testing and debugging\n *\n * ## Side Effects\n * - Cancels active drawing (if any)\n * - Releases map mode and cursor\n * - Emits 'shapes:draw-canceled' event\n * - Removes store instance from memory\n *\n * @param mapId - Unique identifier for the map instance\n *\n * @example\n * ```typescript\n * import { clearDrawingState } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * // Clear drawing state when unmounting a map\n * function cleanup(mapId: UniqueId) {\n * clearDrawingState(mapId);\n * }\n * ```\n */\nexport function clearDrawingState(mapId: UniqueId): void {\n drawStore.clear(mapId);\n}\n\n/**\n * Complete the drawing operation with a GeoJSON feature.\n *\n * Called internally by the DrawShapeLayer component when the user finishes\n * drawing a shape. Converts the raw EditableGeoJsonLayer feature to a Shape\n * object, resets drawing state, releases mode/cursor, and emits the drawn event.\n *\n * ## Internal API\n * This function is exported for use by the DrawShapeLayer component and should\n * not be called directly from application code. Use the `draw` action from\n * `useDrawShape` or `useDrawingState` instead.\n *\n * @param mapId - Unique identifier for the map instance\n * @param feature - The completed GeoJSON feature from EditableGeoJsonLayer\n * @returns The newly created Shape object\n * @throws Error if not currently drawing\n *\n * @example\n * ```typescript\n * // Internal usage in DrawShapeLayer\n * const handleEdit = ({ updatedData, editType }: EditAction) => {\n * if (editType === 'addFeature') {\n * const feature = updatedData.features[updatedData.features.length - 1];\n * if (feature) {\n * completeDrawingFromLayer(mapId, feature);\n * }\n * }\n * };\n * ```\n */\nexport function completeDrawingFromLayer(\n mapId: UniqueId,\n feature: Feature,\n): Shape {\n const state = drawStore.get(mapId);\n return completeDrawingInternal(\n mapId,\n state,\n feature,\n () => {\n /* notify handled by set */\n },\n (updates) => drawStore.set(mapId, updates),\n );\n}\n\n/**\n * Cancel the current drawing operation from the layer.\n *\n * Called internally by the DrawShapeLayer component when the user presses ESC\n * or the drawing is otherwise canceled. Resets drawing state, releases mode/cursor,\n * and emits the canceled event.\n *\n * ## Internal API\n * This function is exported for use by the DrawShapeLayer component and should\n * not be called directly from application code. Use the `cancel` action from\n * `useDrawShape` or `useDrawingState` instead.\n *\n * @param mapId - Unique identifier for the map instance\n *\n * @example\n * ```typescript\n * // Internal usage in DrawShapeLayer\n * const handleEdit = ({ editType }: EditAction) => {\n * if (editType === 'cancelFeature') {\n * cancelDrawingFromLayer(mapId);\n * }\n * };\n * ```\n */\nexport function cancelDrawingFromLayer(mapId: UniqueId): void {\n drawStore.actions(mapId).cancel();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DA,MAAM,eAAe,UAAU,aAA6B;AAC5D,MAAM,aAAa,UAAU,aAA+B;;;;AAK5D,MAAMA,wBAAsC;CAC1C,iBAAiB;CACjB,kBAAkB;CAClB,eAAe;CACf,gBAAgB;CACjB;;;;AAeD,SAAS,aACP,OACA,OACA,WACA,SACA,QACA,UACM;AAEN,KAAI,MAAM,gBACR,uBAAsB,OAAO,OAAO,QAAQ,SAAS;AAIvD,UAAS;EACP,iBAAiB;EACjB,kBAAkB;EAClB,eAAe,SAAS,iBAAiB;EACzC,gBAAgB,SAAS,kBAAkB;EAC5C,CAAC;CAGF,MAAM,SAAS,gBAAgB;AAC/B,sBAAqB,OAAO,iBAAiB,QAAQ,oBAAoB;AAGzE,cAAa,KAAK,gBAAgB,SAAS;EACzC;EACA;EACD,CAAC;AAEF,SAAQ;;;;;AAMV,SAAS,wBACP,OACA,OACA,SACA,QACA,UACO;AACP,KAAI,CAAC,MAAM,gBACT,OAAM,IAAI,MAAM,kDAAkD;CAGpE,MAAM,YAAY,MAAM;CACxB,MAAM,gBAAgB,MAAM;CAG5B,MAAM,QAAQ,sBAAsB,SAAS,WAAW,cAAc;AAGtE,UAAS;EACP,iBAAiB;EACjB,kBAAkB;EAClB,eAAe;EACf,gBAAgB;EACjB,CAAC;AAGF,sBAAqB,OAAO,oBAAoB;AAGhD,cAAa,KAAK,gBAAgB,OAAO;EACvC;EACA;EACD,CAA0C;AAE3C,SAAQ;AAER,QAAO;;;;;AAMT,SAAS,sBACP,OACA,OACA,QACA,UACM;AACN,KAAI,CAAC,MAAM,gBACT;CAGF,MAAM,YAAY,MAAM;AAGxB,UAAS;EACP,iBAAiB;EACjB,kBAAkB;EAClB,eAAe;EACf,gBAAgB;EACjB,CAAC;AAGF,sBAAqB,OAAO,oBAAoB;AAGhD,cAAa,KAAK,gBAAgB,UAAU;EAC1C;EACA;EACD,CAAC;AAEF,SAAQ;;;;;AAMV,MAAa,YAAY,eAA+C;CACtE,cAAc,EAAE,GAAG,uBAAuB;CAE1C,UAAU,OAAO,EAAE,KAAK,KAAK,cAAc;EACzC,OAAO,WAA6B,YAA+B;AACjE,gBAAa,OAAO,KAAK,EAAE,WAAW,SAAS,QAAQ,IAAI;;EAG7D,cAAc;AACZ,yBAAsB,OAAO,KAAK,EAAE,QAAQ,IAAI;;EAEnD;CAED,MAAM,OAAO,EAAE,UAAU;EAEvB,MAAM,YAAY,WAAW,GAC3B,cAAc,sBACb,UAAU;GACT,MAAM,EAAE,QAAQ,OAAO,MAAM;AAG7B,OAAI,OAAO,MACT;AAIF,OAAI,KAAK,CAAC,gBACR,YAAW,KAAK,cAAc,gBAAgB;IAC5C;IACA,UAAU;IACV,OAAO;IACP,QAAQ;IACR,IAAI;IACL,CAAC;IAGP;AAED,eAAa;AACX,cAAW;;;CAIf,YAAY,OAAO,UAAU;AAE3B,MAAI,MAAM,iBAAiB;AAEzB,wBAAqB,OAAO,oBAAoB;AAGhD,gBAAa,KAAK,gBAAgB,UAAU;IAC1C,WAAW,MAAM;IACjB;IACD,CAAC;;;CAGP,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmJF,SAAgB,yBACd,OACA,SACO;AAEP,QAAO,wBACL,OAFY,UAAU,IAAI,MAAM,EAIhC,eACM,KAGL,YAAY,UAAU,IAAI,OAAO,QAAQ,CAC3C;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BH,SAAgB,uBAAuB,OAAuB;AAC5D,WAAU,QAAQ,MAAM,CAAC,QAAQ"}
1
+ {"version":3,"file":"store.js","names":["DEFAULT_DRAWING_STATE: DrawingState"],"sources":["../../../../src/deckgl/shapes/draw-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 * Draw Shape Store\n *\n * Manages drawing state for shape creation.\n *\n * @example\n * ```tsx\n * import { drawStore } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * function DrawControls({ mapId }) {\n * const { state, draw, cancel } = drawStore.use(mapId);\n *\n * return (\n * <div>\n * <p>Drawing: {state.activeShapeType ?? 'none'}</p>\n * <button onClick={() => draw('Polygon')}>Draw Polygon</button>\n * <button onClick={cancel}>Cancel</button>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { MapModeEvents } from '@/map-mode/events';\nimport { createMapStore } from '@/shared/create-map-store';\nimport {\n releaseModeAndCursor,\n requestModeAndCursor,\n} from '../shared/utils/mode-utils';\nimport {\n DRAW_CURSOR_MAP,\n DRAW_SHAPE_LAYER_ID,\n DRAW_SHAPE_MODE,\n} from './constants';\nimport { DrawShapeEvents } from './events';\nimport { convertFeatureToShape } from './utils/feature-conversion';\nimport type { UniqueId } from '@accelint/core';\nimport type { Feature } from 'geojson';\nimport type { MapModeEventType } from '@/map-mode/types';\nimport type { Shape, ShapeFeatureType } from '../shared/types';\nimport type { DrawShapeEvent, ShapeDrawnEvent } from './events';\nimport type { DrawFunction, DrawingState, DrawShapeOptions } from './types';\n\n/**\n * Typed event bus instances\n */\nconst drawShapeBus = Broadcast.getInstance<DrawShapeEvent>();\nconst mapModeBus = Broadcast.getInstance<MapModeEventType>();\n\n/**\n * Default drawing state\n */\nconst DEFAULT_DRAWING_STATE: DrawingState = {\n activeShapeType: null,\n tentativeFeature: null,\n styleDefaults: null,\n circleDefaults: null,\n};\n\n/**\n * Actions for draw shape store\n */\ntype DrawShapeActions = {\n /** Start drawing a shape of the specified type */\n draw: DrawFunction;\n /** Cancel the current drawing operation */\n cancel: () => void;\n};\n\n/**\n * Start drawing a shape\n */\nfunction startDrawing(\n mapId: UniqueId,\n state: DrawingState,\n shapeType: ShapeFeatureType,\n options: DrawShapeOptions | undefined,\n notify: () => void,\n setState: (updates: Partial<DrawingState>) => void,\n): void {\n // Already drawing - cancel first\n if (state.activeShapeType) {\n cancelDrawingInternal(mapId, state, notify, setState);\n }\n\n // Update state with new object reference\n setState({\n activeShapeType: shapeType,\n tentativeFeature: null,\n styleDefaults: options?.styleDefaults ?? null,\n circleDefaults: options?.circleDefaults ?? null,\n });\n\n // Request map mode and cursor using shared utilities\n const cursor = DRAW_CURSOR_MAP[shapeType];\n requestModeAndCursor(mapId, DRAW_SHAPE_MODE, cursor, DRAW_SHAPE_LAYER_ID);\n\n // Emit drawing started event\n drawShapeBus.emit(DrawShapeEvents.drawing, {\n shapeType,\n mapId,\n });\n\n notify();\n}\n\n/**\n * Complete drawing and create a shape\n */\nfunction completeDrawingInternal(\n mapId: UniqueId,\n state: DrawingState,\n feature: Feature,\n notify: () => void,\n setState: (updates: Partial<DrawingState>) => void,\n): Shape {\n if (!state.activeShapeType) {\n throw new Error('Cannot complete drawing - not currently drawing');\n }\n\n const shapeType = state.activeShapeType;\n const styleDefaults = state.styleDefaults;\n\n // Convert feature to Shape\n const shape = convertFeatureToShape(feature, shapeType, styleDefaults);\n\n // Reset state with new object reference\n setState({\n activeShapeType: null,\n tentativeFeature: null,\n styleDefaults: null,\n circleDefaults: null,\n });\n\n // Release mode and cursor using shared utilities\n releaseModeAndCursor(mapId, DRAW_SHAPE_LAYER_ID);\n\n // Emit shape drawn event\n drawShapeBus.emit(DrawShapeEvents.drawn, {\n shape,\n mapId,\n } as unknown as ShapeDrawnEvent['payload']);\n\n notify();\n\n return shape;\n}\n\n/**\n * Cancel the current drawing operation\n */\nfunction cancelDrawingInternal(\n mapId: UniqueId,\n state: DrawingState,\n notify: () => void,\n setState: (updates: Partial<DrawingState>) => void,\n): void {\n if (!state.activeShapeType) {\n return; // Nothing to cancel\n }\n\n const shapeType = state.activeShapeType;\n\n // Reset state with new object reference\n setState({\n activeShapeType: null,\n tentativeFeature: null,\n styleDefaults: null,\n circleDefaults: null,\n });\n\n // Release mode and cursor using shared utilities\n releaseModeAndCursor(mapId, DRAW_SHAPE_LAYER_ID);\n\n // Emit canceled event\n drawShapeBus.emit(DrawShapeEvents.canceled, {\n shapeType,\n mapId,\n });\n\n notify();\n}\n\n/**\n * Draw shape store\n */\nexport const drawStore = createMapStore<DrawingState, DrawShapeActions>({\n defaultState: { ...DEFAULT_DRAWING_STATE },\n\n actions: (mapId, { get, set, notify }) => ({\n draw: (shapeType: ShapeFeatureType, options?: DrawShapeOptions) => {\n startDrawing(mapId, get(), shapeType, options, notify, set);\n },\n\n cancel: () => {\n cancelDrawingInternal(mapId, get(), notify, set);\n },\n }),\n\n bus: (mapId, { get }) => {\n // Listen for mode authorization requests - REJECT when drawing (protected mode)\n const unsubAuth = mapModeBus.on(\n MapModeEvents.changeAuthorization,\n (event) => {\n const { authId, id } = event.payload;\n\n // Filter: only handle if targeted at this map\n if (id !== mapId) {\n return;\n }\n\n // If we're actively drawing, reject the mode change request\n if (get().activeShapeType) {\n mapModeBus.emit(MapModeEvents.changeDecision, {\n authId,\n approved: false,\n owner: DRAW_SHAPE_LAYER_ID,\n reason: 'Drawing in progress - cancel drawing first',\n id: mapId,\n });\n }\n },\n );\n\n return () => {\n unsubAuth();\n };\n },\n\n onCleanup: (mapId, state) => {\n // Cancel any active drawing before cleanup\n if (state.activeShapeType) {\n // Release mode and cursor using shared utilities\n releaseModeAndCursor(mapId, DRAW_SHAPE_LAYER_ID);\n\n // Emit canceled event\n drawShapeBus.emit(DrawShapeEvents.canceled, {\n shapeType: state.activeShapeType,\n mapId,\n });\n }\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get the current drawing state for a map instance.\n *\n * Returns the drawing state (active shape type, style defaults, etc.) for the\n * specified map ID. Returns null if no drawing store instance exists for that map.\n *\n * ## Use Cases\n * - Check if a map is currently in drawing mode\n * - Access drawing state outside of React components\n * - Inspect state for debugging purposes\n *\n * @param mapId - Unique identifier for the map instance\n * @returns The drawing state, or null if no store instance exists\n *\n * @example\n * ```typescript\n * import { getDrawingState } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * const state = getDrawingState('map-1');\n * if (state?.activeShapeType) {\n * console.log(`Currently drawing: ${state.activeShapeType}`);\n * }\n * ```\n */\nexport function getDrawingState(mapId: UniqueId): DrawingState | null {\n if (!drawStore.exists(mapId)) {\n return null;\n }\n return drawStore.get(mapId);\n}\n\n/**\n * React hook for accessing drawing state and actions.\n *\n * Provides access to the drawing store for a specific map instance, including\n * the current state and draw/cancel actions. Uses `useSyncExternalStore` for\n * concurrent-safe React subscriptions.\n *\n * ## Comparison with useDrawShape\n * - `useDrawingState`: Low-level store access without event callbacks\n * - `useDrawShape`: High-level API with onCreate/onCancel callbacks\n *\n * Use `useDrawingState` when you need direct store access without event handling.\n * Use `useDrawShape` (recommended) for most drawing interactions.\n *\n * @param mapId - Unique identifier for the map instance\n * @returns Object containing drawing state and actions (draw, cancel)\n *\n * @example\n * ```tsx\n * import { useDrawingState } from '@accelint/map-toolkit/deckgl/shapes';\n * import { ShapeFeatureType } from '@accelint/map-toolkit/deckgl/shapes/shared/types';\n *\n * function DrawingStatus({ mapId }: { mapId: UniqueId }) {\n * const { state, draw, cancel } = useDrawingState(mapId);\n *\n * return (\n * <div>\n * <p>Status: {state.activeShapeType ?? 'Not drawing'}</p>\n * <button onClick={() => draw(ShapeFeatureType.Polygon)}>\n * Start Drawing\n * </button>\n * {state.activeShapeType && (\n * <button onClick={cancel}>Cancel</button>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useDrawingState(\n mapId: UniqueId,\n): { state: DrawingState } & DrawShapeActions {\n return drawStore.use(mapId);\n}\n\n/**\n * Manually clear the drawing state for a specific map instance.\n *\n * Removes the drawing store instance for the given map ID, canceling any\n * active drawing operation and releasing mode/cursor ownership. This is\n * typically called automatically during cleanup, but can be used manually\n * when needed.\n *\n * ## When to Use\n * - Cleanup after programmatically managing drawing state\n * - Force-reset drawing state in error conditions\n * - Testing and debugging\n *\n * ## Side Effects\n * - Cancels active drawing (if any)\n * - Releases map mode and cursor\n * - Emits 'shapes:draw-canceled' event\n * - Removes store instance from memory\n *\n * @param mapId - Unique identifier for the map instance\n *\n * @example\n * ```typescript\n * import { clearDrawingState } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * // Clear drawing state when unmounting a map\n * function cleanup(mapId: UniqueId) {\n * clearDrawingState(mapId);\n * }\n * ```\n */\nexport function clearDrawingState(mapId: UniqueId): void {\n drawStore.clear(mapId);\n}\n\n/**\n * Complete the drawing operation with a GeoJSON feature.\n *\n * Called internally by the DrawShapeLayer component when the user finishes\n * drawing a shape. Converts the raw EditableGeoJsonLayer feature to a Shape\n * object, resets drawing state, releases mode/cursor, and emits the drawn event.\n *\n * ## Internal API\n * This function is exported for use by the DrawShapeLayer component and should\n * not be called directly from application code. Use the `draw` action from\n * `useDrawShape` or `useDrawingState` instead.\n *\n * @param mapId - Unique identifier for the map instance\n * @param feature - The completed GeoJSON feature from EditableGeoJsonLayer\n * @returns The newly created Shape object\n * @throws Error if not currently drawing\n *\n * @example\n * ```typescript\n * // Internal usage in DrawShapeLayer\n * const handleEdit = ({ updatedData, editType }: EditAction) => {\n * if (editType === 'addFeature') {\n * const feature = updatedData.features[updatedData.features.length - 1];\n * if (feature) {\n * completeDrawingFromLayer(mapId, feature);\n * }\n * }\n * };\n * ```\n */\nexport function completeDrawingFromLayer(\n mapId: UniqueId,\n feature: Feature,\n): Shape {\n const state = drawStore.get(mapId);\n return completeDrawingInternal(\n mapId,\n state,\n feature,\n () => {\n /* notify handled by set */\n },\n (updates) => drawStore.set(mapId, updates),\n );\n}\n\n/**\n * Cancel the current drawing operation from the layer.\n *\n * Called internally by the DrawShapeLayer component when the user presses ESC\n * or the drawing is otherwise canceled. Resets drawing state, releases mode/cursor,\n * and emits the canceled event.\n *\n * ## Internal API\n * This function is exported for use by the DrawShapeLayer component and should\n * not be called directly from application code. Use the `cancel` action from\n * `useDrawShape` or `useDrawingState` instead.\n *\n * @param mapId - Unique identifier for the map instance\n *\n * @example\n * ```typescript\n * // Internal usage in DrawShapeLayer\n * const handleEdit = ({ editType }: EditAction) => {\n * if (editType === 'cancelFeature') {\n * cancelDrawingFromLayer(mapId);\n * }\n * };\n * ```\n */\nexport function cancelDrawingFromLayer(mapId: UniqueId): void {\n drawStore.actions(mapId).cancel();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DA,MAAM,eAAe,UAAU,aAA6B;AAC5D,MAAM,aAAa,UAAU,aAA+B;;;;AAK5D,MAAMA,wBAAsC;CAC1C,iBAAiB;CACjB,kBAAkB;CAClB,eAAe;CACf,gBAAgB;CACjB;;;;AAeD,SAAS,aACP,OACA,OACA,WACA,SACA,QACA,UACM;AAEN,KAAI,MAAM,gBACR,uBAAsB,OAAO,OAAO,QAAQ,SAAS;AAIvD,UAAS;EACP,iBAAiB;EACjB,kBAAkB;EAClB,eAAe,SAAS,iBAAiB;EACzC,gBAAgB,SAAS,kBAAkB;EAC5C,CAAC;CAGF,MAAM,SAAS,gBAAgB;AAC/B,sBAAqB,OAAO,iBAAiB,QAAQ,oBAAoB;AAGzE,cAAa,KAAK,gBAAgB,SAAS;EACzC;EACA;EACD,CAAC;AAEF,SAAQ;;;;;AAMV,SAAS,wBACP,OACA,OACA,SACA,QACA,UACO;AACP,KAAI,CAAC,MAAM,gBACT,OAAM,IAAI,MAAM,kDAAkD;CAGpE,MAAM,YAAY,MAAM;CACxB,MAAM,gBAAgB,MAAM;CAG5B,MAAM,QAAQ,sBAAsB,SAAS,WAAW,cAAc;AAGtE,UAAS;EACP,iBAAiB;EACjB,kBAAkB;EAClB,eAAe;EACf,gBAAgB;EACjB,CAAC;AAGF,sBAAqB,OAAO,oBAAoB;AAGhD,cAAa,KAAK,gBAAgB,OAAO;EACvC;EACA;EACD,CAA0C;AAE3C,SAAQ;AAER,QAAO;;;;;AAMT,SAAS,sBACP,OACA,OACA,QACA,UACM;AACN,KAAI,CAAC,MAAM,gBACT;CAGF,MAAM,YAAY,MAAM;AAGxB,UAAS;EACP,iBAAiB;EACjB,kBAAkB;EAClB,eAAe;EACf,gBAAgB;EACjB,CAAC;AAGF,sBAAqB,OAAO,oBAAoB;AAGhD,cAAa,KAAK,gBAAgB,UAAU;EAC1C;EACA;EACD,CAAC;AAEF,SAAQ;;;;;AAMV,MAAa,YAAY,eAA+C;CACtE,cAAc,EAAE,GAAG,uBAAuB;CAE1C,UAAU,OAAO,EAAE,KAAK,KAAK,cAAc;EACzC,OAAO,WAA6B,YAA+B;AACjE,gBAAa,OAAO,KAAK,EAAE,WAAW,SAAS,QAAQ,IAAI;;EAG7D,cAAc;AACZ,yBAAsB,OAAO,KAAK,EAAE,QAAQ,IAAI;;EAEnD;CAED,MAAM,OAAO,EAAE,UAAU;EAEvB,MAAM,YAAY,WAAW,GAC3B,cAAc,sBACb,UAAU;GACT,MAAM,EAAE,QAAQ,OAAO,MAAM;AAG7B,OAAI,OAAO,MACT;AAIF,OAAI,KAAK,CAAC,gBACR,YAAW,KAAK,cAAc,gBAAgB;IAC5C;IACA,UAAU;IACV,OAAO;IACP,QAAQ;IACR,IAAI;IACL,CAAC;IAGP;AAED,eAAa;AACX,cAAW;;;CAIf,YAAY,OAAO,UAAU;AAE3B,MAAI,MAAM,iBAAiB;AAEzB,wBAAqB,OAAO,oBAAoB;AAGhD,gBAAa,KAAK,gBAAgB,UAAU;IAC1C,WAAW,MAAM;IACjB;IACD,CAAC;;;CAGP,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiHF,SAAgB,kBAAkB,OAAuB;AACvD,WAAU,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCxB,SAAgB,yBACd,OACA,SACO;AAEP,QAAO,wBACL,OAFY,UAAU,IAAI,MAAM,EAIhC,eACM,KAGL,YAAY,UAAU,IAAI,OAAO,QAAQ,CAC3C;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BH,SAAgB,uBAAuB,OAAuB;AAC5D,WAAU,QAAQ,MAAM,CAAC,QAAQ"}
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
3
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License. You may obtain a copy
5
5
  * of the License at https://www.apache.org/licenses/LICENSE-2.0
@@ -13,9 +13,9 @@
13
13
 
14
14
  'use client';
15
15
 
16
- import { MapContext } from "../../base-map/provider.js";
17
16
  import { DrawShapeEvents } from "./events.js";
18
17
  import { drawStore } 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