@accelint/map-toolkit 0.6.0 → 1.1.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 (207) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/catalog-info.yaml +7 -6
  3. package/dist/camera/events.js.map +1 -1
  4. package/dist/camera/index.d.ts +2 -2
  5. package/dist/camera/index.js +2 -2
  6. package/dist/camera/store.d.ts +120 -0
  7. package/dist/camera/store.js +279 -0
  8. package/dist/camera/store.js.map +1 -0
  9. package/dist/cursor-coordinates/index.d.ts +4 -2
  10. package/dist/cursor-coordinates/index.js +3 -2
  11. package/dist/cursor-coordinates/store.d.ts +48 -0
  12. package/dist/cursor-coordinates/store.js +92 -0
  13. package/dist/cursor-coordinates/store.js.map +1 -0
  14. package/dist/cursor-coordinates/types.d.ts +87 -0
  15. package/dist/cursor-coordinates/types.js +12 -0
  16. package/dist/cursor-coordinates/use-cursor-coordinates.d.ts +41 -37
  17. package/dist/cursor-coordinates/use-cursor-coordinates.js +131 -202
  18. package/dist/cursor-coordinates/use-cursor-coordinates.js.map +1 -1
  19. package/dist/deckgl/base-map/constants.d.ts +1 -6
  20. package/dist/deckgl/base-map/constants.js +1 -6
  21. package/dist/deckgl/base-map/constants.js.map +1 -1
  22. package/dist/deckgl/base-map/controls.js +2 -0
  23. package/dist/deckgl/base-map/controls.js.map +1 -1
  24. package/dist/deckgl/base-map/events.js.map +1 -1
  25. package/dist/deckgl/base-map/index.d.ts +2 -2
  26. package/dist/deckgl/base-map/index.js +10 -11
  27. package/dist/deckgl/base-map/index.js.map +1 -1
  28. package/dist/deckgl/base-map/provider.d.ts +2 -2
  29. package/dist/deckgl/base-map/provider.js +1 -1
  30. package/dist/deckgl/base-map/provider.js.map +1 -1
  31. package/dist/deckgl/index.d.ts +4 -4
  32. package/dist/deckgl/index.js +4 -4
  33. package/dist/deckgl/saved-viewports/index.js.map +1 -1
  34. package/dist/deckgl/saved-viewports/storage.js +10 -2
  35. package/dist/deckgl/saved-viewports/storage.js.map +1 -1
  36. package/dist/deckgl/shapes/display-shape-layer/constants.js +5 -8
  37. package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -1
  38. package/dist/deckgl/shapes/display-shape-layer/fiber.js.map +1 -1
  39. package/dist/deckgl/shapes/display-shape-layer/index.d.ts +18 -14
  40. package/dist/deckgl/shapes/display-shape-layer/index.js +63 -30
  41. package/dist/deckgl/shapes/display-shape-layer/index.js.map +1 -1
  42. package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.js +2 -16
  43. package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.js.map +1 -1
  44. package/dist/deckgl/shapes/display-shape-layer/store.js +58 -272
  45. package/dist/deckgl/shapes/display-shape-layer/store.js.map +1 -1
  46. package/dist/deckgl/shapes/display-shape-layer/types.d.ts +22 -11
  47. package/dist/deckgl/shapes/display-shape-layer/{use-shape-selection.d.ts → use-select-shape.d.ts} +9 -9
  48. package/dist/deckgl/shapes/display-shape-layer/{use-shape-selection.js → use-select-shape.js} +12 -12
  49. package/dist/deckgl/shapes/display-shape-layer/use-select-shape.js.map +1 -0
  50. package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js +5 -66
  51. package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js.map +1 -1
  52. package/dist/deckgl/shapes/display-shape-layer/utils/labels.d.ts +2 -65
  53. package/dist/deckgl/shapes/display-shape-layer/utils/labels.js +3 -121
  54. package/dist/deckgl/shapes/display-shape-layer/utils/labels.js.map +1 -1
  55. package/dist/deckgl/shapes/draw-shape-layer/constants.js +46 -0
  56. package/dist/deckgl/shapes/draw-shape-layer/constants.js.map +1 -0
  57. package/dist/deckgl/shapes/draw-shape-layer/events.d.ts +92 -0
  58. package/dist/deckgl/shapes/draw-shape-layer/events.js +56 -0
  59. package/dist/deckgl/shapes/draw-shape-layer/events.js.map +1 -0
  60. package/dist/deckgl/shapes/draw-shape-layer/fiber.d.ts +11 -0
  61. package/dist/{maplibre/constants.js → deckgl/shapes/draw-shape-layer/fiber.js} +6 -12
  62. package/dist/deckgl/shapes/draw-shape-layer/fiber.js.map +1 -0
  63. package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +53 -0
  64. package/dist/deckgl/shapes/draw-shape-layer/index.js +95 -0
  65. package/dist/deckgl/shapes/draw-shape-layer/index.js.map +1 -0
  66. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +51 -0
  67. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -0
  68. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +73 -0
  69. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js.map +1 -0
  70. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +87 -0
  71. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js.map +1 -0
  72. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +88 -0
  73. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js.map +1 -0
  74. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +77 -0
  75. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js.map +1 -0
  76. package/dist/deckgl/shapes/draw-shape-layer/modes/index.js +64 -0
  77. package/dist/deckgl/shapes/draw-shape-layer/modes/index.js.map +1 -0
  78. package/dist/deckgl/shapes/draw-shape-layer/store.js +175 -0
  79. package/dist/deckgl/shapes/draw-shape-layer/store.js.map +1 -0
  80. package/dist/deckgl/shapes/draw-shape-layer/types.d.ts +86 -0
  81. package/dist/{viewport/constants.js → deckgl/shapes/draw-shape-layer/types.js} +1 -12
  82. package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.d.ts +82 -0
  83. package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.js +112 -0
  84. package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.js.map +1 -0
  85. package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js +147 -0
  86. package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js.map +1 -0
  87. package/dist/deckgl/shapes/edit-shape-layer/constants.js +41 -0
  88. package/dist/deckgl/shapes/edit-shape-layer/constants.js.map +1 -0
  89. package/dist/deckgl/shapes/edit-shape-layer/events.d.ts +92 -0
  90. package/dist/deckgl/shapes/edit-shape-layer/events.js +56 -0
  91. package/dist/deckgl/shapes/edit-shape-layer/events.js.map +1 -0
  92. package/dist/deckgl/shapes/edit-shape-layer/fiber.d.ts +13 -0
  93. package/dist/deckgl/shapes/edit-shape-layer/fiber.js +14 -0
  94. package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +63 -0
  95. package/dist/deckgl/shapes/edit-shape-layer/index.js +162 -0
  96. package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -0
  97. package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js +154 -0
  98. package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js.map +1 -0
  99. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +147 -0
  100. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js.map +1 -0
  101. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +87 -0
  102. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -0
  103. package/dist/deckgl/shapes/edit-shape-layer/modes/index.js +61 -0
  104. package/dist/deckgl/shapes/edit-shape-layer/modes/index.js.map +1 -0
  105. package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js +109 -0
  106. package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js.map +1 -0
  107. package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js +289 -0
  108. package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js.map +1 -0
  109. package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js +121 -0
  110. package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js.map +1 -0
  111. package/dist/deckgl/shapes/edit-shape-layer/store.js +194 -0
  112. package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -0
  113. package/dist/deckgl/shapes/edit-shape-layer/types.d.ts +93 -0
  114. package/dist/deckgl/shapes/edit-shape-layer/types.js +14 -0
  115. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.d.ts +82 -0
  116. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js +114 -0
  117. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js.map +1 -0
  118. package/dist/deckgl/shapes/index.d.ts +15 -6
  119. package/dist/deckgl/shapes/index.js +12 -5
  120. package/dist/deckgl/shapes/shared/constants.d.ts +27 -32
  121. package/dist/deckgl/shapes/shared/constants.js +189 -25
  122. package/dist/deckgl/shapes/shared/constants.js.map +1 -1
  123. package/dist/deckgl/shapes/shared/events.d.ts +1 -20
  124. package/dist/deckgl/shapes/shared/events.js +1 -31
  125. package/dist/deckgl/shapes/shared/events.js.map +1 -1
  126. package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js +84 -0
  127. package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js.map +1 -0
  128. package/dist/deckgl/shapes/shared/types.d.ts +187 -28
  129. package/dist/deckgl/shapes/shared/types.js +55 -1
  130. package/dist/deckgl/shapes/shared/types.js.map +1 -1
  131. package/dist/deckgl/shapes/shared/utils/geometry-measurements.js +128 -0
  132. package/dist/deckgl/shapes/shared/utils/geometry-measurements.js.map +1 -0
  133. package/dist/deckgl/shapes/shared/utils/layer-config.js +50 -0
  134. package/dist/deckgl/shapes/shared/utils/layer-config.js.map +1 -0
  135. package/dist/deckgl/shapes/shared/utils/mode-utils.js +113 -0
  136. package/dist/deckgl/shapes/shared/utils/mode-utils.js.map +1 -0
  137. package/dist/deckgl/shapes/shared/utils/pick-filtering.js +57 -0
  138. package/dist/deckgl/shapes/shared/utils/pick-filtering.js.map +1 -0
  139. package/dist/deckgl/shapes/shared/utils/style-utils.d.ts +64 -0
  140. package/dist/deckgl/shapes/shared/utils/style-utils.js +101 -0
  141. package/dist/deckgl/shapes/shared/utils/style-utils.js.map +1 -0
  142. package/dist/deckgl/symbol-layer/fiber.js.map +1 -1
  143. package/dist/deckgl/symbol-layer/index.js.map +1 -1
  144. package/dist/deckgl/text-layer/character-sets.js.map +1 -1
  145. package/dist/deckgl/text-layer/default-settings.js +4 -24
  146. package/dist/deckgl/text-layer/default-settings.js.map +1 -1
  147. package/dist/deckgl/text-layer/fiber.js.map +1 -1
  148. package/dist/deckgl/text-layer/index.js.map +1 -1
  149. package/dist/deckgl/text-settings.d.ts +77 -0
  150. package/dist/deckgl/text-settings.js +83 -0
  151. package/dist/deckgl/text-settings.js.map +1 -0
  152. package/dist/map-cursor/events.js.map +1 -1
  153. package/dist/map-cursor/index.d.ts +2 -2
  154. package/dist/map-cursor/index.js +2 -2
  155. package/dist/map-cursor/store.d.ts +32 -61
  156. package/dist/map-cursor/store.js +165 -294
  157. package/dist/map-cursor/store.js.map +1 -1
  158. package/dist/map-cursor/use-map-cursor.d.ts +5 -2
  159. package/dist/map-cursor/use-map-cursor.js +33 -15
  160. package/dist/map-cursor/use-map-cursor.js.map +1 -1
  161. package/dist/map-mode/events.js.map +1 -1
  162. package/dist/map-mode/index.d.ts +2 -2
  163. package/dist/map-mode/index.js +2 -2
  164. package/dist/map-mode/store.d.ts +36 -37
  165. package/dist/map-mode/store.js +131 -237
  166. package/dist/map-mode/store.js.map +1 -1
  167. package/dist/map-mode/use-map-mode.js +6 -5
  168. package/dist/map-mode/use-map-mode.js.map +1 -1
  169. package/dist/maplibre/hooks/use-maplibre.js.map +1 -1
  170. package/dist/maplibre/index.d.ts +2 -2
  171. package/dist/maplibre/index.js +2 -2
  172. package/dist/shared/constants.d.ts +19 -0
  173. package/dist/shared/constants.js +33 -0
  174. package/dist/shared/constants.js.map +1 -0
  175. package/dist/shared/create-map-store.d.ts +202 -0
  176. package/dist/shared/create-map-store.js +223 -0
  177. package/dist/shared/create-map-store.js.map +1 -0
  178. package/dist/shared/units.d.ts +39 -0
  179. package/dist/shared/units.js +49 -0
  180. package/dist/shared/units.js.map +1 -0
  181. package/dist/viewport/index.d.ts +3 -3
  182. package/dist/viewport/index.js +3 -3
  183. package/dist/viewport/store.d.ts +69 -0
  184. package/dist/viewport/store.js +125 -0
  185. package/dist/viewport/store.js.map +1 -0
  186. package/dist/viewport/types.d.ts +2 -2
  187. package/dist/viewport/utils.js +2 -2
  188. package/dist/viewport/utils.js.map +1 -1
  189. package/dist/viewport/viewport-size.d.ts +2 -2
  190. package/dist/viewport/viewport-size.js +2 -2
  191. package/dist/viewport/viewport-size.js.map +1 -1
  192. package/package.json +39 -19
  193. package/dist/camera/use-camera-state.d.ts +0 -153
  194. package/dist/camera/use-camera-state.js +0 -418
  195. package/dist/camera/use-camera-state.js.map +0 -1
  196. package/dist/deckgl/shapes/display-shape-layer/constants.d.ts +0 -44
  197. package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.d.ts +0 -66
  198. package/dist/deckgl/shapes/display-shape-layer/store.d.ts +0 -87
  199. package/dist/deckgl/shapes/display-shape-layer/use-shape-selection.js.map +0 -1
  200. package/dist/deckgl/shapes/display-shape-layer/utils/display-style.d.ts +0 -61
  201. package/dist/maplibre/constants.d.ts +0 -13
  202. package/dist/maplibre/constants.js.map +0 -1
  203. package/dist/viewport/constants.d.ts +0 -11
  204. package/dist/viewport/constants.js.map +0 -1
  205. package/dist/viewport/use-viewport-state.d.ts +0 -100
  206. package/dist/viewport/use-viewport-state.js +0 -222
  207. package/dist/viewport/use-viewport-state.js.map +0 -1
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ 'use client';
15
+
16
+ //#region src/deckgl/shapes/edit-shape-layer/events.ts
17
+ /**
18
+ * Edit Shape Events
19
+ *
20
+ * Note on event payload structure:
21
+ * These events define explicit payload types rather than using the `Payload<T, P>` helper
22
+ * from @accelint/bus. This is because the `Shape` type contains GeoJSON `Feature` objects
23
+ * from the `geojson` package, which don't satisfy TypeScript's `StructuredCloneable` type
24
+ * constraint used by the bus.
25
+ *
26
+ * The issue: `StructuredCloneable` (from type-fest) requires objects to have an index
27
+ * signature `[key: string]: StructuredCloneable`, but GeoJSON interfaces define strict
28
+ * property types without index signatures. At runtime, GeoJSON data IS structurally
29
+ * cloneable (can be passed through postMessage, stored in IndexedDB, etc.), but
30
+ * TypeScript can't verify this statically.
31
+ *
32
+ * Events that only contain primitive values (like ShapeId, mapId) can use the `Payload`
33
+ * helper directly - see shared/events.ts for examples.
34
+ *
35
+ * When emitting these events via the bus, use type assertions:
36
+ * @example
37
+ * ```ts
38
+ * bus.emit('shapes:updated', {
39
+ * type: 'shapes:updated',
40
+ * payload: { shape, mapId },
41
+ * source: componentId,
42
+ * } as unknown as Payload);
43
+ * ```
44
+ */
45
+ /**
46
+ * Edit shape lifecycle events
47
+ */
48
+ const EditShapeEvents = {
49
+ editing: "shapes:editing",
50
+ updated: "shapes:updated",
51
+ canceled: "shapes:edit-canceled"
52
+ };
53
+
54
+ //#endregion
55
+ export { EditShapeEvents };
56
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","names":[],"sources":["../../../../src/deckgl/shapes/edit-shape-layer/events.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Edit Shape Events\n *\n * Note on event payload structure:\n * These events define explicit payload types rather than using the `Payload<T, P>` helper\n * from @accelint/bus. This is because the `Shape` type contains GeoJSON `Feature` objects\n * from the `geojson` package, which don't satisfy TypeScript's `StructuredCloneable` type\n * constraint used by the bus.\n *\n * The issue: `StructuredCloneable` (from type-fest) requires objects to have an index\n * signature `[key: string]: StructuredCloneable`, but GeoJSON interfaces define strict\n * property types without index signatures. At runtime, GeoJSON data IS structurally\n * cloneable (can be passed through postMessage, stored in IndexedDB, etc.), but\n * TypeScript can't verify this statically.\n *\n * Events that only contain primitive values (like ShapeId, mapId) can use the `Payload`\n * helper directly - see shared/events.ts for examples.\n *\n * When emitting these events via the bus, use type assertions:\n * @example\n * ```ts\n * bus.emit('shapes:updated', {\n * type: 'shapes:updated',\n * payload: { shape, mapId },\n * source: componentId,\n * } as unknown as Payload);\n * ```\n */\n\n'use client';\n\nimport type { UniqueId } from '@accelint/core';\nimport type { Shape } from '../shared/types';\n\n/**\n * Edit shape lifecycle events\n */\nexport const EditShapeEvents = {\n /** Editing has started for a shape */\n editing: 'shapes:editing',\n /** Shape has been successfully updated */\n updated: 'shapes:updated',\n /** Editing was canceled */\n canceled: 'shapes:edit-canceled',\n} as const;\n\nexport type EditShapeEventType =\n (typeof EditShapeEvents)[keyof typeof EditShapeEvents];\n\n/**\n * Payload for shapes:editing event.\n */\nexport type ShapeEditingPayload = {\n /** The shape being edited */\n shape: Shape;\n /** Map instance ID for multi-map event isolation */\n mapId: UniqueId;\n};\n\n/**\n * Event payload for shapes:editing\n * Emitted when editing starts\n */\nexport type ShapeEditingEvent = {\n type: 'shapes:editing';\n payload: ShapeEditingPayload;\n source: UniqueId;\n target?: UniqueId;\n};\n\n/**\n * Payload for shapes:updated event.\n */\nexport type ShapeUpdatedPayload = {\n /** The updated shape with new geometry */\n shape: Shape;\n /** Map instance ID for multi-map event isolation */\n mapId: UniqueId;\n};\n\n/**\n * Event payload for shapes:updated\n * Emitted when shape edits are saved\n */\nexport type ShapeUpdatedEvent = {\n type: 'shapes:updated';\n payload: ShapeUpdatedPayload;\n source: UniqueId;\n target?: UniqueId;\n};\n\n/**\n * Payload for shapes:edit-canceled event.\n */\nexport type ShapeEditCanceledPayload = {\n /** The shape that was being edited (original, unchanged) */\n shape: Shape;\n /** Map instance ID for multi-map event isolation */\n mapId: UniqueId;\n};\n\n/**\n * Event payload for shapes:edit-canceled\n * Emitted when editing is canceled\n */\nexport type ShapeEditCanceledEvent = {\n type: 'shapes:edit-canceled';\n payload: ShapeEditCanceledPayload;\n source: UniqueId;\n target?: UniqueId;\n};\n\n/**\n * Union of all edit shape event types\n */\nexport type EditShapeEvent =\n | ShapeEditingEvent\n | ShapeUpdatedEvent\n | ShapeEditCanceledEvent;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,MAAa,kBAAkB;CAE7B,SAAS;CAET,SAAS;CAET,UAAU;CACX"}
@@ -0,0 +1,13 @@
1
+ /*
2
+ * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import "../draw-shape-layer/fiber.js";
@@ -0,0 +1,14 @@
1
+ /*
2
+ * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ import "../draw-shape-layer/fiber.js";
@@ -0,0 +1,63 @@
1
+ /*
2
+ * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { EditShapeLayerProps } from "./types.js";
14
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
15
+
16
+ //#region src/deckgl/shapes/edit-shape-layer/index.d.ts
17
+
18
+ /**
19
+ * EditShapeLayer - A React component for editing existing shapes on the map.
20
+ *
21
+ * This component wraps the EditableGeoJsonLayer from @deck.gl-community/editable-layers
22
+ * and integrates with the map-mode and map-cursor systems for proper coordination.
23
+ *
24
+ * Key features:
25
+ * - Renders only when actively editing (returns null otherwise)
26
+ * - Uses cached mode instances to prevent deck.gl assertion errors
27
+ * - Integrates with the editing store for state management
28
+ * - Neutral mode authorization (lets UI decide how to handle mode conflicts)
29
+ * - Circles use ResizeCircleMode with tooltip, other shapes use ModifyMode
30
+ * - Fill colors rendered at 20% opacity, edit handles are white
31
+ * - Live dimension/area tooltips during editing
32
+ * - requestAnimationFrame() batching for smooth drag performance
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * // Import the fiber registration for JSX support
37
+ * import '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/fiber';
38
+ * import '@accelint/map-toolkit/deckgl/shapes/display-shape-layer/fiber';
39
+ *
40
+ * function Map({ mapId }) {
41
+ * const { editingShape } = useEditShape(mapId);
42
+ *
43
+ * return (
44
+ * <BaseMap id={mapId}>
45
+ * <displayShapeLayer
46
+ * data={shapes}
47
+ * mapId={mapId}
48
+ * selectedShapeId={editingShape?.id}
49
+ * />
50
+ * <EditShapeLayer mapId={mapId} />
51
+ * </BaseMap>
52
+ * );
53
+ * }
54
+ * ```
55
+ */
56
+ declare function EditShapeLayer({
57
+ id,
58
+ mapId,
59
+ unit
60
+ }: EditShapeLayerProps): react_jsx_runtime3.JSX.Element | null;
61
+ //#endregion
62
+ export { EditShapeLayer };
63
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,162 @@
1
+ /*
2
+ * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ 'use client';
15
+
16
+ import { MapContext } from "../../base-map/provider.js";
17
+ import { COMPLETION_EDIT_TYPES, CONTINUOUS_EDIT_TYPES } from "../shared/constants.js";
18
+ import { getFillColor, getLineColor } from "../shared/utils/style-utils.js";
19
+ import { ShapeFeatureType } from "../shared/types.js";
20
+ import { useShiftZoomDisable } from "../shared/hooks/use-shift-zoom-disable.js";
21
+ import { getDefaultEditableLayerProps } from "../shared/utils/layer-config.js";
22
+ import { EDIT_SHAPE_LAYER_ID } from "./constants.js";
23
+ import { getEditModeInstance } from "./modes/index.js";
24
+ import { cancelEditingFromLayer, editStore, updateFeatureFromLayer } from "./store.js";
25
+ import { useContext, useEffect, useRef } from "react";
26
+ import { jsx } from "react/jsx-runtime";
27
+
28
+ //#region src/deckgl/shapes/edit-shape-layer/index.tsx
29
+ function isContinuousEditType(editType) {
30
+ return CONTINUOUS_EDIT_TYPES.has(editType);
31
+ }
32
+ function isCompletionEditType(editType) {
33
+ return COMPLETION_EDIT_TYPES.has(editType);
34
+ }
35
+ /**
36
+ * Convert a GeoJSON Feature to a FeatureCollection for EditableGeoJsonLayer.
37
+ * The editable-layers library accepts standard GeoJSON FeatureCollection at runtime,
38
+ * but has stricter internal types. We use the geojson types which are compatible.
39
+ *
40
+ * For circles, adds the `shape: 'Circle'` property required by ResizeCircleMode.
41
+ * ResizeCircleMode checks `properties.shape.includes('Circle')` to identify circles.
42
+ *
43
+ * For rectangles, adds the `shape: 'Rectangle'` property required by ModifyMode's
44
+ * lockRectangles feature. ModifyMode checks `properties.shape === 'Rectangle'`.
45
+ */
46
+ function toFeatureCollection(feature, shape) {
47
+ let shapeProperty;
48
+ if (shape === ShapeFeatureType.Circle) shapeProperty = "Circle";
49
+ else if (shape === ShapeFeatureType.Rectangle) shapeProperty = "Rectangle";
50
+ return {
51
+ type: "FeatureCollection",
52
+ features: [shapeProperty ? {
53
+ ...feature,
54
+ properties: {
55
+ ...feature.properties,
56
+ shape: shapeProperty
57
+ }
58
+ } : feature]
59
+ };
60
+ }
61
+ /**
62
+ * EditShapeLayer - A React component for editing existing shapes on the map.
63
+ *
64
+ * This component wraps the EditableGeoJsonLayer from @deck.gl-community/editable-layers
65
+ * and integrates with the map-mode and map-cursor systems for proper coordination.
66
+ *
67
+ * Key features:
68
+ * - Renders only when actively editing (returns null otherwise)
69
+ * - Uses cached mode instances to prevent deck.gl assertion errors
70
+ * - Integrates with the editing store for state management
71
+ * - Neutral mode authorization (lets UI decide how to handle mode conflicts)
72
+ * - Circles use ResizeCircleMode with tooltip, other shapes use ModifyMode
73
+ * - Fill colors rendered at 20% opacity, edit handles are white
74
+ * - Live dimension/area tooltips during editing
75
+ * - requestAnimationFrame() batching for smooth drag performance
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * // Import the fiber registration for JSX support
80
+ * import '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/fiber';
81
+ * import '@accelint/map-toolkit/deckgl/shapes/display-shape-layer/fiber';
82
+ *
83
+ * function Map({ mapId }) {
84
+ * const { editingShape } = useEditShape(mapId);
85
+ *
86
+ * return (
87
+ * <BaseMap id={mapId}>
88
+ * <displayShapeLayer
89
+ * data={shapes}
90
+ * mapId={mapId}
91
+ * selectedShapeId={editingShape?.id}
92
+ * />
93
+ * <EditShapeLayer mapId={mapId} />
94
+ * </BaseMap>
95
+ * );
96
+ * }
97
+ * ```
98
+ */
99
+ function EditShapeLayer({ id = EDIT_SHAPE_LAYER_ID, mapId, unit }) {
100
+ const contextId = useContext(MapContext);
101
+ const actualMapId = mapId ?? contextId;
102
+ if (!actualMapId) throw new Error("EditShapeLayer requires either a mapId prop or to be used within a MapProvider");
103
+ const { state: editingState } = editStore.use(actualMapId);
104
+ useShiftZoomDisable(actualMapId, editingState?.editingShape != null);
105
+ const pendingUpdateRef = useRef(null);
106
+ useEffect(() => {
107
+ return () => {
108
+ if (pendingUpdateRef.current) cancelAnimationFrame(pendingUpdateRef.current.rafId);
109
+ };
110
+ }, []);
111
+ if (!editingState?.editingShape) return null;
112
+ const { editingShape, editMode, featureBeingEdited } = editingState;
113
+ const mode = getEditModeInstance(editMode);
114
+ const data = toFeatureCollection(featureBeingEdited ?? editingShape.feature, editingShape.shape);
115
+ const cancelPendingUpdate = () => {
116
+ if (pendingUpdateRef.current) {
117
+ cancelAnimationFrame(pendingUpdateRef.current.rafId);
118
+ pendingUpdateRef.current = null;
119
+ }
120
+ };
121
+ const handleEdit = ({ updatedData, editType }) => {
122
+ const feature = updatedData.features[0];
123
+ if (isContinuousEditType(editType) && feature) {
124
+ cancelPendingUpdate();
125
+ pendingUpdateRef.current = {
126
+ feature,
127
+ rafId: requestAnimationFrame(() => {
128
+ updateFeatureFromLayer(actualMapId, feature);
129
+ pendingUpdateRef.current = null;
130
+ })
131
+ };
132
+ return;
133
+ }
134
+ if (isCompletionEditType(editType)) {
135
+ cancelPendingUpdate();
136
+ if (feature) updateFeatureFromLayer(actualMapId, feature);
137
+ return;
138
+ }
139
+ if (editType === "cancelFeature") {
140
+ cancelPendingUpdate();
141
+ cancelEditingFromLayer(actualMapId);
142
+ }
143
+ };
144
+ const fillColor = getFillColor(editingShape.feature, true);
145
+ const lineColor = getLineColor(editingShape.feature);
146
+ return /* @__PURE__ */ jsx("editableGeoJsonLayer", {
147
+ id,
148
+ data,
149
+ mode,
150
+ selectedFeatureIndexes: [0],
151
+ onEdit: handleEdit,
152
+ getFillColor: fillColor,
153
+ getLineColor: lineColor,
154
+ getTentativeFillColor: fillColor,
155
+ getTentativeLineColor: lineColor,
156
+ ...getDefaultEditableLayerProps(unit)
157
+ });
158
+ }
159
+
160
+ //#endregion
161
+ export { EditShapeLayer };
162
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["shapeProperty: string | undefined"],"sources":["../../../../src/deckgl/shapes/edit-shape-layer/index.tsx"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\nimport { useContext, useEffect, useRef } from 'react';\nimport { MapContext } from '../../base-map/provider';\nimport { useShiftZoomDisable } from '../shared/hooks/use-shift-zoom-disable';\nimport { ShapeFeatureType, type ShapeFeatureTypeValues } from '../shared/types';\nimport { getDefaultEditableLayerProps } from '../shared/utils/layer-config';\nimport { getFillColor, getLineColor } from '../shared/utils/style-utils';\nimport {\n COMPLETION_EDIT_TYPES,\n CONTINUOUS_EDIT_TYPES,\n EDIT_SHAPE_LAYER_ID,\n} from './constants';\nimport { getEditModeInstance } from './modes';\nimport {\n cancelEditingFromLayer,\n editStore,\n updateFeatureFromLayer,\n} from './store';\nimport type {\n EditAction,\n FeatureCollection,\n} from '@deck.gl-community/editable-layers';\nimport type { Feature } from 'geojson';\nimport type { EditShapeLayerProps } from './types';\n\nfunction isContinuousEditType(editType: string): boolean {\n return CONTINUOUS_EDIT_TYPES.has(editType);\n}\n\nfunction isCompletionEditType(editType: string): boolean {\n return COMPLETION_EDIT_TYPES.has(editType);\n}\n\n/**\n * Convert a GeoJSON Feature to a FeatureCollection for EditableGeoJsonLayer.\n * The editable-layers library accepts standard GeoJSON FeatureCollection at runtime,\n * but has stricter internal types. We use the geojson types which are compatible.\n *\n * For circles, adds the `shape: 'Circle'` property required by ResizeCircleMode.\n * ResizeCircleMode checks `properties.shape.includes('Circle')` to identify circles.\n *\n * For rectangles, adds the `shape: 'Rectangle'` property required by ModifyMode's\n * lockRectangles feature. ModifyMode checks `properties.shape === 'Rectangle'`.\n */\nfunction toFeatureCollection(\n feature: Feature,\n shape: ShapeFeatureTypeValues,\n): import('geojson').FeatureCollection {\n // Add shape property for modes that require it\n // - ResizeCircleMode requires shape: 'Circle'\n // - ModifyMode lockRectangles requires shape: 'Rectangle'\n let shapeProperty: string | undefined;\n if (shape === ShapeFeatureType.Circle) {\n shapeProperty = 'Circle';\n } else if (shape === ShapeFeatureType.Rectangle) {\n shapeProperty = 'Rectangle';\n }\n\n const featureWithShape = shapeProperty\n ? {\n ...feature,\n properties: {\n ...feature.properties,\n shape: shapeProperty,\n },\n }\n : feature;\n\n return {\n type: 'FeatureCollection',\n features: [featureWithShape],\n };\n}\n\n/**\n * EditShapeLayer - A React component for editing existing shapes on the map.\n *\n * This component wraps the EditableGeoJsonLayer from @deck.gl-community/editable-layers\n * and integrates with the map-mode and map-cursor systems for proper coordination.\n *\n * Key features:\n * - Renders only when actively editing (returns null otherwise)\n * - Uses cached mode instances to prevent deck.gl assertion errors\n * - Integrates with the editing store for state management\n * - Neutral mode authorization (lets UI decide how to handle mode conflicts)\n * - Circles use ResizeCircleMode with tooltip, other shapes use ModifyMode\n * - Fill colors rendered at 20% opacity, edit handles are white\n * - Live dimension/area tooltips during editing\n * - requestAnimationFrame() batching for smooth drag performance\n *\n * @example\n * ```tsx\n * // Import the fiber registration for JSX support\n * import '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/fiber';\n * import '@accelint/map-toolkit/deckgl/shapes/display-shape-layer/fiber';\n *\n * function Map({ mapId }) {\n * const { editingShape } = useEditShape(mapId);\n *\n * return (\n * <BaseMap id={mapId}>\n * <displayShapeLayer\n * data={shapes}\n * mapId={mapId}\n * selectedShapeId={editingShape?.id}\n * />\n * <EditShapeLayer mapId={mapId} />\n * </BaseMap>\n * );\n * }\n * ```\n */\nexport function EditShapeLayer({\n id = EDIT_SHAPE_LAYER_ID,\n mapId,\n unit,\n}: EditShapeLayerProps) {\n // Get mapId from context if not provided\n const contextId = useContext(MapContext);\n const actualMapId = mapId ?? contextId;\n\n if (!actualMapId) {\n throw new Error(\n 'EditShapeLayer requires either a mapId prop or to be used within a MapProvider',\n );\n }\n\n // Subscribe to editing state using the v2 store API\n const { state: editingState } = editStore.use(actualMapId);\n\n const isEditing = editingState?.editingShape != null;\n\n // Disable zoom while Shift is held during editing\n // This prevents boxZoom (Shift+drag) from interfering with Shift modifier constraints\n // (e.g., Shift for uniform scaling, Shift for rotation snap)\n useShiftZoomDisable(actualMapId, isEditing);\n\n // RAF batching for movePosition events to reduce React updates during drag\n const pendingUpdateRef = useRef<{\n feature: Feature;\n rafId: number;\n } | null>(null);\n\n // Cleanup RAF on unmount\n useEffect(() => {\n return () => {\n if (pendingUpdateRef.current) {\n cancelAnimationFrame(pendingUpdateRef.current.rafId);\n }\n };\n }, []);\n\n // If not editing, return null (don't render the editable layer)\n if (!editingState?.editingShape) {\n return null;\n }\n\n const { editingShape, editMode, featureBeingEdited } = editingState;\n\n // Get the cached mode instance\n const mode = getEditModeInstance(editMode);\n\n // Use the live feature being edited, or fall back to original shape\n const featureToRender = featureBeingEdited ?? editingShape.feature;\n const data = toFeatureCollection(featureToRender, editingShape.shape);\n\n // Helper to cancel any pending RAF update\n const cancelPendingUpdate = () => {\n if (pendingUpdateRef.current) {\n cancelAnimationFrame(pendingUpdateRef.current.rafId);\n pendingUpdateRef.current = null;\n }\n };\n\n // Handle edit events from EditableGeoJsonLayer\n const handleEdit = ({\n updatedData,\n editType,\n }: EditAction<FeatureCollection>) => {\n const feature = updatedData.features[0];\n\n // Continuous events (during drag): batch with RAF for smooth performance\n if (isContinuousEditType(editType) && feature) {\n cancelPendingUpdate();\n const rafId = requestAnimationFrame(() => {\n updateFeatureFromLayer(actualMapId, feature as Feature);\n pendingUpdateRef.current = null;\n });\n pendingUpdateRef.current = { feature: feature as Feature, rafId };\n return;\n }\n\n // Completion events (drag end): update immediately\n if (isCompletionEditType(editType)) {\n cancelPendingUpdate();\n if (feature) {\n updateFeatureFromLayer(actualMapId, feature as Feature);\n }\n return;\n }\n\n // ESC key cancellation\n if (editType === 'cancelFeature') {\n cancelPendingUpdate();\n cancelEditingFromLayer(actualMapId);\n }\n };\n\n // Get colors from the shape's existing style properties with base opacity applied\n const fillColor = getFillColor(editingShape.feature, true);\n const lineColor = getLineColor(editingShape.feature);\n\n return (\n <editableGeoJsonLayer\n id={id}\n data={data}\n mode={mode}\n selectedFeatureIndexes={[0]}\n onEdit={handleEdit}\n getFillColor={fillColor}\n getLineColor={lineColor}\n getTentativeFillColor={fillColor}\n getTentativeLineColor={lineColor}\n {...getDefaultEditableLayerProps(unit)}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAS,qBAAqB,UAA2B;AACvD,QAAO,sBAAsB,IAAI,SAAS;;AAG5C,SAAS,qBAAqB,UAA2B;AACvD,QAAO,sBAAsB,IAAI,SAAS;;;;;;;;;;;;;AAc5C,SAAS,oBACP,SACA,OACqC;CAIrC,IAAIA;AACJ,KAAI,UAAU,iBAAiB,OAC7B,iBAAgB;UACP,UAAU,iBAAiB,UACpC,iBAAgB;AAalB,QAAO;EACL,MAAM;EACN,UAAU,CAZa,gBACrB;GACE,GAAG;GACH,YAAY;IACV,GAAG,QAAQ;IACX,OAAO;IACR;GACF,GACD,QAI0B;EAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCH,SAAgB,eAAe,EAC7B,KAAK,qBACL,OACA,QACsB;CAEtB,MAAM,YAAY,WAAW,WAAW;CACxC,MAAM,cAAc,SAAS;AAE7B,KAAI,CAAC,YACH,OAAM,IAAI,MACR,iFACD;CAIH,MAAM,EAAE,OAAO,iBAAiB,UAAU,IAAI,YAAY;AAO1D,qBAAoB,aALF,cAAc,gBAAgB,KAKL;CAG3C,MAAM,mBAAmB,OAGf,KAAK;AAGf,iBAAgB;AACd,eAAa;AACX,OAAI,iBAAiB,QACnB,sBAAqB,iBAAiB,QAAQ,MAAM;;IAGvD,EAAE,CAAC;AAGN,KAAI,CAAC,cAAc,aACjB,QAAO;CAGT,MAAM,EAAE,cAAc,UAAU,uBAAuB;CAGvD,MAAM,OAAO,oBAAoB,SAAS;CAI1C,MAAM,OAAO,oBADW,sBAAsB,aAAa,SACT,aAAa,MAAM;CAGrE,MAAM,4BAA4B;AAChC,MAAI,iBAAiB,SAAS;AAC5B,wBAAqB,iBAAiB,QAAQ,MAAM;AACpD,oBAAiB,UAAU;;;CAK/B,MAAM,cAAc,EAClB,aACA,eACmC;EACnC,MAAM,UAAU,YAAY,SAAS;AAGrC,MAAI,qBAAqB,SAAS,IAAI,SAAS;AAC7C,wBAAqB;AAKrB,oBAAiB,UAAU;IAAW;IAAoB,OAJ5C,4BAA4B;AACxC,4BAAuB,aAAa,QAAmB;AACvD,sBAAiB,UAAU;MAC3B;IAC+D;AACjE;;AAIF,MAAI,qBAAqB,SAAS,EAAE;AAClC,wBAAqB;AACrB,OAAI,QACF,wBAAuB,aAAa,QAAmB;AAEzD;;AAIF,MAAI,aAAa,iBAAiB;AAChC,wBAAqB;AACrB,0BAAuB,YAAY;;;CAKvC,MAAM,YAAY,aAAa,aAAa,SAAS,KAAK;CAC1D,MAAM,YAAY,aAAa,aAAa,QAAQ;AAEpD,QACE,oBAAC;EACK;EACE;EACA;EACN,wBAAwB,CAAC,EAAE;EAC3B,QAAQ;EACR,cAAc;EACd,cAAc;EACd,uBAAuB;EACvB,uBAAuB;EACvB,GAAI,6BAA6B,KAAK;GACtC"}
@@ -0,0 +1,154 @@
1
+ /*
2
+ * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ import { filterGeometryAwarePicks } from "../../shared/utils/pick-filtering.js";
15
+ import { CompositeMode } from "@deck.gl-community/editable-layers";
16
+
17
+ //#region src/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.ts
18
+ /**
19
+ * Abstract base class for composite transform modes.
20
+ *
21
+ * This class extracts the common patterns shared by CircleTransformMode,
22
+ * BoundingTransformMode, and VertexTransformMode:
23
+ *
24
+ * - Active mode tracking during drag operations
25
+ * - Cursor aggregation from child modes
26
+ * - Pick-based mode selection at drag start
27
+ * - Shift key modifier handling for scale/rotate operations
28
+ * - Clean state reset on drag stop
29
+ * - Pick filtering to prevent TypeError from sublayer elements
30
+ *
31
+ * Subclasses define their specific modes and handle matchers, while this
32
+ * base class handles the delegation logic.
33
+ */
34
+ var BaseTransformMode = class extends CompositeMode {
35
+ /** Track which mode is currently handling the drag operation */
36
+ activeDragMode = null;
37
+ /** Track current Shift state for dynamic modifier behavior */
38
+ isShiftHeld = false;
39
+ /** Tooltip for operations that show live measurements */
40
+ tooltip = null;
41
+ /**
42
+ * Aggregates cursor updates from all child modes.
43
+ * The first non-null cursor from any mode is used.
44
+ */
45
+ handlePointerMove(event, props) {
46
+ let updatedCursor = null;
47
+ super.handlePointerMove(event, {
48
+ ...props,
49
+ onUpdateCursor: (cursor) => {
50
+ updatedCursor = cursor || updatedCursor;
51
+ }
52
+ });
53
+ props.onUpdateCursor(updatedCursor);
54
+ }
55
+ /**
56
+ * Determines which mode should handle the drag based on picked handles.
57
+ * Cancels map panning and delegates to the matched mode.
58
+ */
59
+ handleStartDragging(event, props) {
60
+ if (event.picks.length) event.cancelPan();
61
+ const picks = event.picks ?? [];
62
+ const matchers = this.getHandleMatchers();
63
+ for (const matcher of matchers) if (picks.some(matcher.match)) {
64
+ this.activeDragMode = matcher.mode;
65
+ break;
66
+ }
67
+ if (!this.activeDragMode) this.activeDragMode = this.getDefaultMode();
68
+ this.activeDragMode.handleStartDragging(event, props);
69
+ }
70
+ /**
71
+ * Delegates dragging to the active mode with Shift key handling.
72
+ * Reads Shift state from the source event and applies configured modifiers.
73
+ */
74
+ handleDragging(event, props) {
75
+ if (!this.activeDragMode) return;
76
+ this.isShiftHeld = event.sourceEvent?.shiftKey ?? false;
77
+ const shiftConfig = this.getHandleMatchers().find((m) => m.mode === this.activeDragMode)?.shiftConfig;
78
+ if (shiftConfig && this.isShiftHeld) {
79
+ const propsWithConfig = {
80
+ ...props,
81
+ modeConfig: {
82
+ ...props.modeConfig,
83
+ [shiftConfig.configKey]: shiftConfig.value ?? true
84
+ }
85
+ };
86
+ this.activeDragMode.handleDragging(event, propsWithConfig);
87
+ } else this.activeDragMode.handleDragging(event, props);
88
+ this.onDragging?.(event, props);
89
+ }
90
+ /**
91
+ * Delegates stop dragging to the active mode with final Shift state.
92
+ * Resets all drag-related state.
93
+ */
94
+ handleStopDragging(event, props) {
95
+ if (!this.activeDragMode) return;
96
+ const shiftConfig = this.getHandleMatchers().find((m) => m.mode === this.activeDragMode)?.shiftConfig;
97
+ if (shiftConfig && this.isShiftHeld) {
98
+ const propsWithConfig = {
99
+ ...props,
100
+ modeConfig: {
101
+ ...props.modeConfig,
102
+ [shiftConfig.configKey]: shiftConfig.value ?? true
103
+ }
104
+ };
105
+ this.activeDragMode.handleStopDragging(event, propsWithConfig);
106
+ } else this.activeDragMode.handleStopDragging(event, props);
107
+ this.resetDragState();
108
+ }
109
+ /**
110
+ * Returns tooltips for display during drag operations.
111
+ * Subclasses update `this.tooltip` in their `onDragging` hook.
112
+ */
113
+ getTooltips() {
114
+ return this.tooltip ? [this.tooltip] : [];
115
+ }
116
+ /**
117
+ * Filters picks to prevent TypeError from sublayer elements without geometry.
118
+ *
119
+ * Some child modes (like ModifyMode, ResizeCircleMode) access
120
+ * `pick.object.geometry.type` which throws if the pick doesn't have
121
+ * a geometry property. This happens when picks include sublayer elements
122
+ * like tooltip text that aren't GeoJSON features.
123
+ */
124
+ getGuides(props) {
125
+ const picks = props.lastPointerMoveEvent?.picks;
126
+ if (picks && picks.length > 0) {
127
+ const { filteredPicks, didFilter } = filterGeometryAwarePicks(picks);
128
+ if (didFilter) {
129
+ const filteredProps = {
130
+ ...props,
131
+ lastPointerMoveEvent: {
132
+ ...props.lastPointerMoveEvent,
133
+ picks: filteredPicks
134
+ }
135
+ };
136
+ return super.getGuides(filteredProps);
137
+ }
138
+ }
139
+ return super.getGuides(props);
140
+ }
141
+ /**
142
+ * Resets drag-related state. Called after drag stops.
143
+ * Subclasses can override to reset additional state but should call super.
144
+ */
145
+ resetDragState() {
146
+ this.activeDragMode = null;
147
+ this.isShiftHeld = false;
148
+ this.tooltip = null;
149
+ }
150
+ };
151
+
152
+ //#endregion
153
+ export { BaseTransformMode };
154
+ //# sourceMappingURL=base-transform-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-transform-mode.js","names":["updatedCursor: string | null | undefined","propsWithConfig: ModeProps<FeatureCollection>","filteredProps: ModeProps<FeatureCollection>"],"sources":["../../../../../src/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CompositeMode,\n type DraggingEvent,\n type FeatureCollection,\n type GeoJsonEditMode,\n type GuideFeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type StartDraggingEvent,\n type StopDraggingEvent,\n type Tooltip,\n} from '@deck.gl-community/editable-layers';\nimport { filterGeometryAwarePicks } from '../../shared/utils/pick-filtering';\n\n/**\n * Configuration for how a mode handles the Shift key modifier.\n */\nexport type ShiftKeyConfig = {\n /** The modeConfig property name to set (e.g., 'lockScaling', 'snapRotation') */\n configKey: string;\n /** The value to set when Shift is held (defaults to true) */\n value?: boolean;\n};\n\n/**\n * Definition for how to detect and handle a specific edit handle type.\n */\nexport type HandleMatcher = {\n /** Function to determine if a pick matches this handle type */\n match: (pick: {\n isGuide?: boolean;\n object?: {\n properties?: {\n guideType?: string;\n editHandleType?: string;\n mode?: string;\n };\n };\n }) => boolean;\n /** The mode instance to delegate to when this handle is matched */\n mode: GeoJsonEditMode;\n /** Optional Shift key configuration for this mode */\n shiftConfig?: ShiftKeyConfig;\n};\n\n/**\n * Abstract base class for composite transform modes.\n *\n * This class extracts the common patterns shared by CircleTransformMode,\n * BoundingTransformMode, and VertexTransformMode:\n *\n * - Active mode tracking during drag operations\n * - Cursor aggregation from child modes\n * - Pick-based mode selection at drag start\n * - Shift key modifier handling for scale/rotate operations\n * - Clean state reset on drag stop\n * - Pick filtering to prevent TypeError from sublayer elements\n *\n * Subclasses define their specific modes and handle matchers, while this\n * base class handles the delegation logic.\n */\nexport abstract class BaseTransformMode extends CompositeMode {\n /** Track which mode is currently handling the drag operation */\n protected activeDragMode: GeoJsonEditMode | null = null;\n\n /** Track current Shift state for dynamic modifier behavior */\n protected isShiftHeld = false;\n\n /** Tooltip for operations that show live measurements */\n protected tooltip: Tooltip | null = null;\n\n /**\n * Get the handle matchers that define how picks map to modes.\n * Matchers are evaluated in order; first match wins.\n * The last matcher should typically be a catch-all for the default mode.\n */\n protected abstract getHandleMatchers(): HandleMatcher[];\n\n /**\n * Get the default mode to use when no handle matchers match.\n * This is typically TranslateMode for dragging the shape body.\n */\n protected abstract getDefaultMode(): GeoJsonEditMode;\n\n /**\n * Optional hook called during drag when the active mode is set.\n * Subclasses can override to update tooltips or perform other side effects.\n */\n protected onDragging?(\n event: DraggingEvent,\n props: ModeProps<FeatureCollection>,\n ): void;\n\n /**\n * Aggregates cursor updates from all child modes.\n * The first non-null cursor from any mode is used.\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n let updatedCursor: string | null | undefined = null;\n\n super.handlePointerMove(event, {\n ...props,\n onUpdateCursor: (cursor: string | null | undefined) => {\n updatedCursor = cursor || updatedCursor;\n },\n });\n\n props.onUpdateCursor(updatedCursor);\n }\n\n /**\n * Determines which mode should handle the drag based on picked handles.\n * Cancels map panning and delegates to the matched mode.\n */\n override handleStartDragging(\n event: StartDraggingEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n if (event.picks.length) {\n event.cancelPan();\n }\n\n const picks = event.picks ?? [];\n const matchers = this.getHandleMatchers();\n\n // Find the first matcher that matches any pick\n for (const matcher of matchers) {\n if (picks.some(matcher.match)) {\n this.activeDragMode = matcher.mode;\n break;\n }\n }\n\n // Fall back to default mode if no matcher matched\n if (!this.activeDragMode) {\n this.activeDragMode = this.getDefaultMode();\n }\n\n this.activeDragMode.handleStartDragging(event, props);\n }\n\n /**\n * Delegates dragging to the active mode with Shift key handling.\n * Reads Shift state from the source event and applies configured modifiers.\n */\n override handleDragging(\n event: DraggingEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n if (!this.activeDragMode) {\n return;\n }\n\n const sourceEvent = event.sourceEvent as KeyboardEvent | undefined;\n this.isShiftHeld = sourceEvent?.shiftKey ?? false;\n\n // Find the matcher for the active mode to get shift config\n const matchers = this.getHandleMatchers();\n const activeMatcher = matchers.find((m) => m.mode === this.activeDragMode);\n const shiftConfig = activeMatcher?.shiftConfig;\n\n // Apply shift key modifier if configured\n if (shiftConfig && this.isShiftHeld) {\n const propsWithConfig: ModeProps<FeatureCollection> = {\n ...props,\n modeConfig: {\n ...props.modeConfig,\n [shiftConfig.configKey]: shiftConfig.value ?? true,\n },\n };\n this.activeDragMode.handleDragging(event, propsWithConfig);\n } else {\n this.activeDragMode.handleDragging(event, props);\n }\n\n // Call subclass hook for tooltips or other side effects\n this.onDragging?.(event, props);\n }\n\n /**\n * Delegates stop dragging to the active mode with final Shift state.\n * Resets all drag-related state.\n */\n override handleStopDragging(\n event: StopDraggingEvent,\n props: ModeProps<FeatureCollection>,\n ) {\n if (!this.activeDragMode) {\n return;\n }\n\n // Find the matcher for the active mode to get shift config\n const matchers = this.getHandleMatchers();\n const activeMatcher = matchers.find((m) => m.mode === this.activeDragMode);\n const shiftConfig = activeMatcher?.shiftConfig;\n\n // Apply shift key modifier if configured (use last known state)\n if (shiftConfig && this.isShiftHeld) {\n const propsWithConfig: ModeProps<FeatureCollection> = {\n ...props,\n modeConfig: {\n ...props.modeConfig,\n [shiftConfig.configKey]: shiftConfig.value ?? true,\n },\n };\n this.activeDragMode.handleStopDragging(event, propsWithConfig);\n } else {\n this.activeDragMode.handleStopDragging(event, props);\n }\n\n this.resetDragState();\n }\n\n /**\n * Returns tooltips for display during drag operations.\n * Subclasses update `this.tooltip` in their `onDragging` hook.\n */\n override getTooltips(): Tooltip[] {\n return this.tooltip ? [this.tooltip] : [];\n }\n\n /**\n * Filters picks to prevent TypeError from sublayer elements without geometry.\n *\n * Some child modes (like ModifyMode, ResizeCircleMode) access\n * `pick.object.geometry.type` which throws if the pick doesn't have\n * a geometry property. This happens when picks include sublayer elements\n * like tooltip text that aren't GeoJSON features.\n */\n override getGuides(\n props: ModeProps<FeatureCollection>,\n ): GuideFeatureCollection {\n const picks = props.lastPointerMoveEvent?.picks;\n\n if (picks && picks.length > 0) {\n const { filteredPicks, didFilter } = filterGeometryAwarePicks(picks);\n\n if (didFilter) {\n const filteredProps: ModeProps<FeatureCollection> = {\n ...props,\n lastPointerMoveEvent: {\n ...props.lastPointerMoveEvent,\n picks: filteredPicks,\n },\n };\n return super.getGuides(filteredProps);\n }\n }\n\n return super.getGuides(props);\n }\n\n /**\n * Resets drag-related state. Called after drag stops.\n * Subclasses can override to reset additional state but should call super.\n */\n protected resetDragState(): void {\n this.activeDragMode = null;\n this.isShiftHeld = false;\n this.tooltip = null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEA,IAAsB,oBAAtB,cAAgD,cAAc;;CAE5D,AAAU,iBAAyC;;CAGnD,AAAU,cAAc;;CAGxB,AAAU,UAA0B;;;;;CA4BpC,AAAS,kBACP,OACA,OACA;EACA,IAAIA,gBAA2C;AAE/C,QAAM,kBAAkB,OAAO;GAC7B,GAAG;GACH,iBAAiB,WAAsC;AACrD,oBAAgB,UAAU;;GAE7B,CAAC;AAEF,QAAM,eAAe,cAAc;;;;;;CAOrC,AAAS,oBACP,OACA,OACA;AACA,MAAI,MAAM,MAAM,OACd,OAAM,WAAW;EAGnB,MAAM,QAAQ,MAAM,SAAS,EAAE;EAC/B,MAAM,WAAW,KAAK,mBAAmB;AAGzC,OAAK,MAAM,WAAW,SACpB,KAAI,MAAM,KAAK,QAAQ,MAAM,EAAE;AAC7B,QAAK,iBAAiB,QAAQ;AAC9B;;AAKJ,MAAI,CAAC,KAAK,eACR,MAAK,iBAAiB,KAAK,gBAAgB;AAG7C,OAAK,eAAe,oBAAoB,OAAO,MAAM;;;;;;CAOvD,AAAS,eACP,OACA,OACA;AACA,MAAI,CAAC,KAAK,eACR;AAIF,OAAK,cADe,MAAM,aACM,YAAY;EAK5C,MAAM,cAFW,KAAK,mBAAmB,CACV,MAAM,MAAM,EAAE,SAAS,KAAK,eAAe,EACvC;AAGnC,MAAI,eAAe,KAAK,aAAa;GACnC,MAAMC,kBAAgD;IACpD,GAAG;IACH,YAAY;KACV,GAAG,MAAM;MACR,YAAY,YAAY,YAAY,SAAS;KAC/C;IACF;AACD,QAAK,eAAe,eAAe,OAAO,gBAAgB;QAE1D,MAAK,eAAe,eAAe,OAAO,MAAM;AAIlD,OAAK,aAAa,OAAO,MAAM;;;;;;CAOjC,AAAS,mBACP,OACA,OACA;AACA,MAAI,CAAC,KAAK,eACR;EAMF,MAAM,cAFW,KAAK,mBAAmB,CACV,MAAM,MAAM,EAAE,SAAS,KAAK,eAAe,EACvC;AAGnC,MAAI,eAAe,KAAK,aAAa;GACnC,MAAMA,kBAAgD;IACpD,GAAG;IACH,YAAY;KACV,GAAG,MAAM;MACR,YAAY,YAAY,YAAY,SAAS;KAC/C;IACF;AACD,QAAK,eAAe,mBAAmB,OAAO,gBAAgB;QAE9D,MAAK,eAAe,mBAAmB,OAAO,MAAM;AAGtD,OAAK,gBAAgB;;;;;;CAOvB,AAAS,cAAyB;AAChC,SAAO,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,EAAE;;;;;;;;;;CAW3C,AAAS,UACP,OACwB;EACxB,MAAM,QAAQ,MAAM,sBAAsB;AAE1C,MAAI,SAAS,MAAM,SAAS,GAAG;GAC7B,MAAM,EAAE,eAAe,cAAc,yBAAyB,MAAM;AAEpE,OAAI,WAAW;IACb,MAAMC,gBAA8C;KAClD,GAAG;KACH,sBAAsB;MACpB,GAAG,MAAM;MACT,OAAO;MACR;KACF;AACD,WAAO,MAAM,UAAU,cAAc;;;AAIzC,SAAO,MAAM,UAAU,MAAM;;;;;;CAO/B,AAAU,iBAAuB;AAC/B,OAAK,iBAAiB;AACtB,OAAK,cAAc;AACnB,OAAK,UAAU"}