@element-editor/ui 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/AGENTS.md +65 -0
  2. package/LICENSE +21 -0
  3. package/README.md +46 -2
  4. package/dist/BooleanOperations-WXcmW9Vy.cjs +1 -0
  5. package/dist/BooleanOperations-oF0WybQP.js +111 -0
  6. package/dist/DataTable-CNfB01y2.cjs +2 -0
  7. package/dist/DataTable-DNmjUwka.js +510 -0
  8. package/dist/DataTablePanel-BknCxC1K.cjs +1 -0
  9. package/dist/DataTablePanel-rWdaQubk.js +208 -0
  10. package/dist/EditToolbarBtn-SZIsnIn3.js +378 -0
  11. package/dist/EditToolbarBtn-dpCmKnzk.cjs +3 -0
  12. package/dist/FeatureEditModal-BF-fGhVD.js +77 -0
  13. package/dist/FeatureEditModal-CM6BObUO.cjs +1 -0
  14. package/dist/FeatureList-CQb2kTrV.js +520 -0
  15. package/dist/FeatureList-Csr-anLA.cjs +1 -0
  16. package/dist/FeatureRowContextMenu-BLt7VlUU.js +130 -0
  17. package/dist/FeatureRowContextMenu-Gwq3OMEA.cjs +1 -0
  18. package/dist/GeoJSONModal-BPFWeaLZ.js +886 -0
  19. package/dist/GeoJSONModal-iwUcvrg7.cjs +9 -0
  20. package/dist/SchemaEditor-BEsKUe2p.js +293 -0
  21. package/dist/SchemaEditor-qkoYMg0C.cjs +1 -0
  22. package/dist/SchemaModal-9nNrgorr.js +95 -0
  23. package/dist/SchemaModal-GrtgA7cH.cjs +1 -0
  24. package/dist/SettingsModal-6_qmRyCi.cjs +1 -0
  25. package/dist/SettingsModal-DTP0Xx_Z.js +237 -0
  26. package/dist/ShortcutsModal-CdyQlrqK.cjs +1 -0
  27. package/dist/ShortcutsModal-DwxZu71W.js +299 -0
  28. package/dist/components/ActiveDrawingToolbar.d.cts +1 -0
  29. package/dist/components/ActiveDrawingToolbar.d.ts +1 -0
  30. package/dist/components/BasemapPicker.d.cts +26 -0
  31. package/dist/components/BasemapPicker.d.ts +26 -0
  32. package/dist/components/BooleanOperations.d.cts +1 -0
  33. package/dist/components/BooleanOperations.d.ts +1 -0
  34. package/dist/components/BufferPanel.d.cts +1 -0
  35. package/dist/components/BufferPanel.d.ts +1 -0
  36. package/dist/components/DataTable.d.cts +9 -0
  37. package/dist/components/DataTable.d.ts +9 -0
  38. package/dist/components/DataTablePanel.d.cts +10 -0
  39. package/dist/components/DataTablePanel.d.ts +10 -0
  40. package/dist/components/EditingToolbar.d.cts +1 -0
  41. package/dist/components/EditingToolbar.d.ts +1 -0
  42. package/dist/components/ElementEditorErrorBoundary.d.cts +28 -0
  43. package/dist/components/ElementEditorErrorBoundary.d.ts +28 -0
  44. package/dist/components/ElementEditorUIProvider.d.cts +50 -0
  45. package/dist/components/ElementEditorUIProvider.d.ts +50 -0
  46. package/dist/components/FeatureMapContextMenu.d.cts +23 -0
  47. package/dist/components/FeatureMapContextMenu.d.ts +23 -0
  48. package/dist/components/FitBoundsButton.d.cts +6 -0
  49. package/dist/components/FitBoundsButton.d.ts +6 -0
  50. package/dist/components/FloatingToolbar.d.cts +3 -0
  51. package/dist/components/FloatingToolbar.d.ts +3 -0
  52. package/dist/components/LocateButton.d.cts +11 -0
  53. package/dist/components/LocateButton.d.ts +11 -0
  54. package/dist/components/ReadonlyBanner.d.cts +1 -0
  55. package/dist/components/ReadonlyBanner.d.ts +1 -0
  56. package/dist/components/ShortcutsModal.d.cts +1 -0
  57. package/dist/components/ShortcutsModal.d.ts +1 -0
  58. package/dist/components/SimplifyPanel.d.cts +1 -0
  59. package/dist/components/SimplifyPanel.d.ts +1 -0
  60. package/dist/components/SmoothPanel.d.cts +1 -0
  61. package/dist/components/SmoothPanel.d.ts +1 -0
  62. package/dist/components/UndoRedoToolbar.d.cts +20 -0
  63. package/dist/components/UndoRedoToolbar.d.ts +20 -0
  64. package/dist/components/VertexSelectionBar.d.cts +12 -0
  65. package/dist/components/VertexSelectionBar.d.ts +12 -0
  66. package/dist/components/ZoomIndicator.d.cts +15 -0
  67. package/dist/components/ZoomIndicator.d.ts +15 -0
  68. package/dist/components/dialogs/DynamicFieldRenderer.d.cts +11 -0
  69. package/dist/components/dialogs/DynamicFieldRenderer.d.ts +11 -0
  70. package/dist/components/dialogs/SettingsModal.d.cts +1 -0
  71. package/dist/components/dialogs/SettingsModal.d.ts +1 -0
  72. package/dist/components/lazyParts.d.cts +12 -0
  73. package/dist/components/lazyParts.d.ts +12 -0
  74. package/dist/components/sidebar/FeatureEditModal.d.cts +6 -0
  75. package/dist/components/sidebar/FeatureEditModal.d.ts +6 -0
  76. package/dist/components/sidebar/FeatureList.d.cts +4 -0
  77. package/dist/components/sidebar/FeatureList.d.ts +4 -0
  78. package/dist/components/sidebar/FeatureRow.d.cts +38 -0
  79. package/dist/components/sidebar/FeatureRow.d.ts +38 -0
  80. package/dist/components/sidebar/FeatureRowContextMenu.d.cts +12 -0
  81. package/dist/components/sidebar/FeatureRowContextMenu.d.ts +12 -0
  82. package/dist/components/sidebar/FeatureSidePanel.d.cts +8 -0
  83. package/dist/components/sidebar/FeatureSidePanel.d.ts +8 -0
  84. package/dist/components/sidebar/GeoJSONModal.d.cts +5 -0
  85. package/dist/components/sidebar/GeoJSONModal.d.ts +5 -0
  86. package/dist/components/sidebar/GroupRow.d.cts +21 -0
  87. package/dist/components/sidebar/GroupRow.d.ts +21 -0
  88. package/dist/components/sidebar/HideLayersToggle.d.cts +2 -0
  89. package/dist/components/sidebar/HideLayersToggle.d.ts +2 -0
  90. package/dist/components/sidebar/LayersPanel.d.cts +5 -0
  91. package/dist/components/sidebar/LayersPanel.d.ts +5 -0
  92. package/dist/components/sidebar/PartSubRow.d.cts +9 -0
  93. package/dist/components/sidebar/PartSubRow.d.ts +9 -0
  94. package/dist/components/sidebar/SchemaEditor.d.cts +4 -0
  95. package/dist/components/sidebar/SchemaEditor.d.ts +4 -0
  96. package/dist/components/sidebar/SchemaModal.d.cts +5 -0
  97. package/dist/components/sidebar/SchemaModal.d.ts +5 -0
  98. package/dist/components/sidebar/codeDock.d.cts +21 -0
  99. package/dist/components/sidebar/codeDock.d.ts +21 -0
  100. package/dist/components/ui/Button.d.cts +9 -0
  101. package/dist/components/ui/Button.d.ts +9 -0
  102. package/dist/components/ui/CloseButton.d.cts +6 -0
  103. package/dist/components/ui/CloseButton.d.ts +6 -0
  104. package/dist/components/ui/ContextMenu.d.cts +28 -0
  105. package/dist/components/ui/ContextMenu.d.ts +28 -0
  106. package/dist/components/ui/EditToolbarBtn.d.cts +13 -0
  107. package/dist/components/ui/EditToolbarBtn.d.ts +13 -0
  108. package/dist/components/ui/ElementToaster.d.cts +3 -0
  109. package/dist/components/ui/ElementToaster.d.ts +3 -0
  110. package/dist/components/ui/GeometryTypeIcon.d.cts +7 -0
  111. package/dist/components/ui/GeometryTypeIcon.d.ts +7 -0
  112. package/dist/components/ui/IconButton.d.cts +28 -0
  113. package/dist/components/ui/IconButton.d.ts +28 -0
  114. package/dist/components/ui/Input.d.cts +14 -0
  115. package/dist/components/ui/Input.d.ts +14 -0
  116. package/dist/components/ui/JsonCode.d.cts +4 -0
  117. package/dist/components/ui/JsonCode.d.ts +4 -0
  118. package/dist/components/ui/Kbd.d.cts +16 -0
  119. package/dist/components/ui/Kbd.d.ts +16 -0
  120. package/dist/components/ui/NoFeaturesEmptyState.d.cts +1 -0
  121. package/dist/components/ui/NoFeaturesEmptyState.d.ts +1 -0
  122. package/dist/components/ui/SearchDropdown.d.cts +28 -0
  123. package/dist/components/ui/SearchDropdown.d.ts +28 -0
  124. package/dist/components/ui/ToolButton.d.cts +19 -0
  125. package/dist/components/ui/ToolButton.d.ts +19 -0
  126. package/dist/components/ui/Tooltip.d.cts +12 -0
  127. package/dist/components/ui/Tooltip.d.ts +12 -0
  128. package/dist/components/ui/panelHeader.d.cts +2 -0
  129. package/dist/components/ui/panelHeader.d.ts +2 -0
  130. package/dist/components/ui/resizeEdge.d.cts +4 -0
  131. package/dist/components/ui/resizeEdge.d.ts +4 -0
  132. package/dist/contexts/ElementEditorConfigContext.d.cts +351 -0
  133. package/dist/contexts/ElementEditorConfigContext.d.ts +351 -0
  134. package/dist/contexts/EventContext.d.cts +69 -0
  135. package/dist/contexts/EventContext.d.ts +69 -0
  136. package/dist/contexts/MapControllerContext.d.cts +24 -0
  137. package/dist/contexts/MapControllerContext.d.ts +24 -0
  138. package/dist/contexts/ShortcutConfigContext.d.cts +16 -0
  139. package/dist/contexts/ShortcutConfigContext.d.ts +16 -0
  140. package/dist/contexts/ThemeContext.d.cts +12 -0
  141. package/dist/contexts/ThemeContext.d.ts +12 -0
  142. package/dist/element-editor-ui.cjs +1 -0
  143. package/dist/element-editor-ui.es.js +102 -0
  144. package/dist/geometryWorker-CCwg4tNC.cjs +1 -0
  145. package/dist/geometryWorker-DgQCFSmD.js +25 -0
  146. package/dist/hooks/dragShield.d.cts +7 -0
  147. package/dist/hooks/dragShield.d.ts +7 -0
  148. package/dist/hooks/themeInputs.d.cts +14 -0
  149. package/dist/hooks/themeInputs.d.ts +14 -0
  150. package/dist/hooks/useAccentPalette.d.cts +15 -0
  151. package/dist/hooks/useAccentPalette.d.ts +15 -0
  152. package/dist/hooks/useAccentStyle.d.cts +39 -0
  153. package/dist/hooks/useAccentStyle.d.ts +39 -0
  154. package/dist/hooks/useAdapterControls.d.cts +280 -0
  155. package/dist/hooks/useAdapterControls.d.ts +280 -0
  156. package/dist/hooks/useBalancedWrap.d.cts +8 -0
  157. package/dist/hooks/useBalancedWrap.d.ts +8 -0
  158. package/dist/hooks/useContextMenu.d.cts +11 -0
  159. package/dist/hooks/useContextMenu.d.ts +11 -0
  160. package/dist/hooks/useDataChangeSubscription.d.cts +9 -0
  161. package/dist/hooks/useDataChangeSubscription.d.ts +9 -0
  162. package/dist/hooks/useDragWindow.d.cts +9 -0
  163. package/dist/hooks/useDragWindow.d.ts +9 -0
  164. package/dist/hooks/useFocusTrap.d.cts +7 -0
  165. package/dist/hooks/useFocusTrap.d.ts +7 -0
  166. package/dist/hooks/useGeoJSONDrop.d.cts +40 -0
  167. package/dist/hooks/useGeoJSONDrop.d.ts +40 -0
  168. package/dist/hooks/useGeoJSONExport.d.cts +69 -0
  169. package/dist/hooks/useGeoJSONExport.d.ts +69 -0
  170. package/dist/hooks/useGeoJSONFileImport.d.cts +24 -0
  171. package/dist/hooks/useGeoJSONFileImport.d.ts +24 -0
  172. package/dist/hooks/useInlineRename.d.cts +26 -0
  173. package/dist/hooks/useInlineRename.d.ts +26 -0
  174. package/dist/hooks/useJumpToFeature.d.cts +3 -0
  175. package/dist/hooks/useJumpToFeature.d.ts +3 -0
  176. package/dist/hooks/useKeyboardShortcuts.d.cts +9 -0
  177. package/dist/hooks/useKeyboardShortcuts.d.ts +9 -0
  178. package/dist/hooks/useNominatim.d.cts +24 -0
  179. package/dist/hooks/useNominatim.d.ts +24 -0
  180. package/dist/hooks/usePanelOffset.d.cts +14 -0
  181. package/dist/hooks/usePanelOffset.d.ts +14 -0
  182. package/dist/hooks/useResizablePanel.d.cts +4 -0
  183. package/dist/hooks/useResizablePanel.d.ts +4 -0
  184. package/dist/hooks/useRootTokens.d.cts +27 -0
  185. package/dist/hooks/useRootTokens.d.ts +27 -0
  186. package/dist/hooks/useSearchState.d.cts +23 -0
  187. package/dist/hooks/useSearchState.d.ts +23 -0
  188. package/dist/hooks/useServiceAttribution.d.cts +13 -0
  189. package/dist/hooks/useServiceAttribution.d.ts +13 -0
  190. package/dist/hooks/useWindowEscape.d.cts +25 -0
  191. package/dist/hooks/useWindowEscape.d.ts +25 -0
  192. package/dist/hooks/useWindowFocus.d.cts +4 -0
  193. package/dist/hooks/useWindowFocus.d.ts +4 -0
  194. package/dist/hooks/useWorkerGeometryPreview.d.cts +22 -0
  195. package/dist/hooks/useWorkerGeometryPreview.d.ts +22 -0
  196. package/dist/index-BKdDZ4Y9.cjs +1 -0
  197. package/dist/index-CtZterPc.js +3165 -0
  198. package/dist/index.d.cts +89 -0
  199. package/dist/index.d.ts +89 -0
  200. package/dist/internal.cjs +1 -0
  201. package/dist/internal.d.cts +16 -0
  202. package/dist/internal.d.ts +16 -0
  203. package/dist/internal.es.js +42 -0
  204. package/dist/primitives.cjs +1 -0
  205. package/dist/primitives.d.cts +19 -0
  206. package/dist/primitives.d.ts +19 -0
  207. package/dist/primitives.es.js +17 -0
  208. package/dist/store/StoreContext.d.cts +17 -0
  209. package/dist/store/StoreContext.d.ts +17 -0
  210. package/dist/types/events.d.cts +95 -0
  211. package/dist/types/events.d.ts +95 -0
  212. package/dist/useAccentStyle-CPo2XqAn.js +412 -0
  213. package/dist/useAccentStyle-hsGvyHZc.cjs +1 -0
  214. package/dist/useAdapterControls-BBObhzVX.cjs +1 -0
  215. package/dist/useAdapterControls-DVjkwRZ_.js +691 -0
  216. package/dist/useContextMenu-DJ2Cti85.js +10 -0
  217. package/dist/useContextMenu-DbxMvb1s.cjs +1 -0
  218. package/dist/useFocusTrap-BBjPCfDR.cjs +1 -0
  219. package/dist/useFocusTrap-CKxKT8De.js +25 -0
  220. package/dist/useJumpToFeature-Bdz2hqOC.js +16 -0
  221. package/dist/useJumpToFeature-LwjxGzfy.cjs +1 -0
  222. package/dist/useWindowFocus-D-_yEm_V.cjs +1 -0
  223. package/dist/useWindowFocus-DGAWA1au.js +80 -0
  224. package/dist/utils/booleanValue.d.cts +4 -0
  225. package/dist/utils/booleanValue.d.ts +4 -0
  226. package/dist/utils/clipboardError.d.cts +3 -0
  227. package/dist/utils/clipboardError.d.ts +3 -0
  228. package/dist/utils/download.d.cts +42 -0
  229. package/dist/utils/download.d.ts +42 -0
  230. package/dist/utils/geojsonDocument.d.cts +168 -0
  231. package/dist/utils/geojsonDocument.d.ts +168 -0
  232. package/dist/utils/geometryWorkerClient.d.cts +6 -0
  233. package/dist/utils/geometryWorkerClient.d.ts +6 -0
  234. package/dist/utils/layerOrder.d.cts +9 -0
  235. package/dist/utils/layerOrder.d.ts +9 -0
  236. package/dist/utils/lazyWithPreload.d.cts +24 -0
  237. package/dist/utils/lazyWithPreload.d.ts +24 -0
  238. package/dist/utils/lineSmooth.d.cts +7 -0
  239. package/dist/utils/lineSmooth.d.ts +7 -0
  240. package/dist/utils/platform.d.cts +2 -0
  241. package/dist/utils/platform.d.ts +2 -0
  242. package/dist/workers/geometryWorker.d.cts +1 -0
  243. package/dist/workers/geometryWorker.d.ts +1 -0
  244. package/package.json +133 -3
package/AGENTS.md ADDED
@@ -0,0 +1,65 @@
1
+ # @element-editor/ui: guide for coding agents
2
+
3
+ The React UI of the Element map editor, engine-neutral: toolbars, layers panel, data table, schema editor, GeoJSON inspector, settings and shortcut dialogs, plus the providers and store hooks they need. It has no map of its own.
4
+
5
+ You need it only with an adapter (`@element-editor/adapter-maplibre` or `@element-editor/adapter-leaflet`) on a map you own, to place the editor UI yourself. The drop-in `@element-editor/react` already renders all of it; don't combine the two. Start from `node_modules/@element-editor/react/AGENTS.md` (when installed) or https://elementeditor.dev/docs/introduction/choosing-a-package.
6
+
7
+ ## Install and CSS
8
+
9
+ ```bash
10
+ pnpm add @element-editor/ui @element-editor/adapter-maplibre maplibre-gl # MapLibre
11
+ pnpm add @element-editor/ui @element-editor/adapter-leaflet leaflet react-leaflet # or Leaflet
12
+ ```
13
+
14
+ Peers: `react`, `react-dom` `^19.2.0`. This package has no stylesheet of its own: import the adapter's (`@element-editor/adapter-maplibre/style.css` plus `maplibre-gl/dist/maplibre-gl.css`, or `@element-editor/adapter-leaflet/style.css`). Keep all `@element-editor/*` packages on one version.
15
+
16
+ ## Entries
17
+
18
+ | Entry | What | Semver |
19
+ |---|---|---|
20
+ | `@element-editor/ui` | components, providers, hooks, `ElementEditorImperativeAPI`, `MutationOptions`, `ElementEditorConfig`, `DEFAULT_LAYOUT`, `withLayout` | yes |
21
+ | `@element-editor/ui/primitives` | `Button`, `Input`, `Textarea`, `SelectInput`, `Tooltip`, `Kbd`, `ToolButton`, `ContextMenu`, `SearchDropdown`, `EditToolbarBtn` (no store needed) | yes |
22
+ | `@element-editor/ui/internal` | plumbing shared by the Element packages | **no**: don't import |
23
+
24
+ ## Provider stack
25
+
26
+ | Layer | Required | Notes |
27
+ |---|---|---|
28
+ | `ElementEditorUIProvider` | yes | error boundary, `config`, shortcuts, events + its own toaster, map controller. Props: `config`, `accentColor`, `featureColor`, `onEvent`, `onError`, `toaster` (default `true`) |
29
+ | `GeoStoreProvider` | yes | the store shared by the adapter and these components; one per editor |
30
+ | `ThemeContext.Provider value="light" \| "dark"` | for dark mode | portaled menus and modals read it |
31
+ | `<div data-elm-theme="light">` | yes | scopes styles and keyboard shortcuts; contains the map and all UI |
32
+
33
+ `ElementEditorUIProvider` and `GeoStoreProvider` are also exported by both adapters (same components); `ThemeContext` comes from here. Full examples (MapLibre: UI as `children` of `ElementEditorControls`; Leaflet: UI as siblings of `MapContainer`) are in each adapter's `AGENTS.md`.
34
+
35
+ ## Your own UI on the store
36
+
37
+ Any component under `GeoStoreProvider` can read and change editor state:
38
+
39
+ ```tsx
40
+ import { useDataStore, useUIStore } from '@element-editor/ui'
41
+
42
+ export function StatusChip() {
43
+ const count = useDataStore((s) => s.features.length)
44
+ const selected = useDataStore((s) => s.selectedIds.length)
45
+ const toggleTable = useUIStore((s) => s.toggleTable)
46
+ return (
47
+ <button onClick={toggleTable}>
48
+ {count} features, {selected} selected
49
+ </button>
50
+ )
51
+ }
52
+ ```
53
+
54
+ For data changes prefer the adapter's ref (`ElementEditorControlsRef`: `addFeature`, `updateFeature`, `setFeatureCollection`, …), which fires `onChange` and the other callbacks like a user edit.
55
+
56
+ ## Gotchas
57
+
58
+ - `DataTablePanel`, `SchemaModal`, `GeoJSONModal`, `SettingsModal`, `ShortcutsModal` and `BooleanOperations` are lazy: wrap each in its own `<Suspense>` (a shared boundary unmounts loaded siblings while another loads).
59
+ - `SchemaModal` and `GeoJSONModal` render whenever mounted: mount them only while `useUIStore((s) => s.schemaModalOpen)` / `codeModalOpen` is true and pass `onClose={toggleSchemaModal}` / `toggleCodeModal`.
60
+ - UI you portal outside the `data-elm-theme` element needs a `data-elm-portal` attribute, or it is unstyled and shortcuts stop while it has focus.
61
+ - `onEvent` on the provider silences every built-in toast; use `onError` (returns `void | false | string`) for logging or translated messages.
62
+ - Several editors on one origin: give each `config={{ persistKey: '…' }}` so their localStorage keys don't collide.
63
+ - `Button` joins `className` with `clsx` (no tailwind-merge), so it can't reliably override the variant's own classes (hover, transition); use your own element for different looks.
64
+
65
+ Docs: https://elementeditor.dev/docs/guides/custom-ui-with-adapters, https://elementeditor.dev/docs/reference/element-editor-ui, https://elementeditor.dev/docs/reference/events. Markdown: append `.md`; everything at once: https://elementeditor.dev/llms-full.txt.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michal Acler and Element Editor contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,47 @@
1
- # Temporary Holding Version
1
+ # @element-editor/ui
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The toolbars, layers panel, data table, schema forms, GeoJSON inspector and modals of the [Element](https://elementeditor.dev) map editor, as separate React components. Use it with `@element-editor/adapter-leaflet` or `@element-editor/adapter-maplibre` to place the editor UI in your own layout. You don't need it with `@element-editor/react`, which includes it.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @element-editor/ui @element-editor/adapter-leaflet leaflet react-leaflet
9
+ # or, for MapLibre: npm install @element-editor/ui @element-editor/adapter-maplibre maplibre-gl
10
+ ```
11
+
12
+ Peer dependencies: `react` and `react-dom` `^19.2` (React 18 is not supported). It has no stylesheet of its own: import your adapter's (`@element-editor/adapter-leaflet/style.css` or `@element-editor/adapter-maplibre/style.css`). Render every component inside `ElementEditorUIProvider`, `GeoStoreProvider` and an element with `data-elm-theme="light"` or `"dark"`. Keep all `@element-editor/*` packages on the same version.
13
+
14
+ ## Quick start
15
+
16
+ ```tsx
17
+ import { MapContainer, TileLayer } from 'react-leaflet'
18
+ import { ElementEditorUIProvider, GeoStoreProvider, ElementEditorControls } from '@element-editor/adapter-leaflet'
19
+ import { LayersPanel } from '@element-editor/ui'
20
+ import '@element-editor/adapter-leaflet/style.css'
21
+
22
+ export default function MyEditor() {
23
+ return (
24
+ <ElementEditorUIProvider>
25
+ <GeoStoreProvider>
26
+ <div data-elm-theme="light" style={{ position: 'relative', height: 600 }}>
27
+ <MapContainer center={[48.86, 2.35]} zoom={12} style={{ height: '100%' }}>
28
+ <TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
29
+ <ElementEditorControls />
30
+ </MapContainer>
31
+ <LayersPanel />
32
+ </div>
33
+ </GeoStoreProvider>
34
+ </ElementEditorUIProvider>
35
+ )
36
+ }
37
+ ```
38
+
39
+ The panels are ordinary HTML overlays: render them next to the map, not inside `MapContainer`. The data table and modals are lazy-loaded, so wrap each in its own `<Suspense>`.
40
+
41
+ ## Documentation
42
+
43
+ - [Custom UI with adapters](https://elementeditor.dev/docs/guides/custom-ui-with-adapters)
44
+ - [UI API reference](https://elementeditor.dev/docs/reference/element-editor-ui)
45
+ - [All docs](https://elementeditor.dev/docs) · [Changelog](https://github.com/spatibase/element/blob/main/CHANGELOG.md) · [Issues](https://github.com/spatibase/element/issues)
46
+
47
+ MIT licence.
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),r=require("./useAdapterControls-BBObhzVX.cjs"),g=require("./EditToolbarBtn-dpCmKnzk.cjs"),l=require("@phosphor-icons/react"),h=require("sonner"),I=require("@element-editor/core"),M=require("@element-editor/core/internal"),U=require("./index-BKdDZ4Y9.cjs");function k(){const{dataStore:b}=r.useGeoStore(),u=r.useDataStore(e=>e.selectedIds),v=r.useDataStore(e=>e.features),i=r.useUIStore(e=>e.geometryProcessing),S=r.useUIStore(e=>e.setGeometryProcessing),a=r.useEmit(),w=r.useIsManaged(),P=r.useToasterId();if(u.length<2)return null;const j=new Map(v.map(e=>[e.id,e])),n=u.flatMap(e=>{const t=j.get(e);return t?[t]:[]}),c=n.every(e=>e.geometry.type==="Polygon"||e.geometry.type==="MultiPolygon"),x=n.every(e=>e.geometry.type==="LineString"||e.geometry.type==="MultiLineString"),y=n.every(e=>e.geometry.type==="Point"||e.geometry.type==="MultiPoint");if(y)return null;function p(e){b.getState().replaceFeatures(u,[{...n[0],id:crypto.randomUUID(),...M.freeGeometry(e)}])}function E(){const e=[];for(const t of n)t.geometry.type==="Point"?e.push(t.geometry.coordinates):t.geometry.type==="MultiPoint"&&e.push(...t.geometry.coordinates);p({type:"MultiPoint",coordinates:e}),a({type:"success",message:"Union completed"})}function q(){const e=[];for(const t of n)t.geometry.type==="LineString"?e.push(t.geometry.coordinates):t.geometry.type==="MultiLineString"&&e.push(...t.geometry.coordinates);p({type:"MultiLineString",coordinates:e}),a({type:"success",message:"Union completed"})}async function d(e){if(e==="union"&&y)return E();if(e==="union"&&x)return q();if(!c){a({type:"warning",message:"These work on areas only. Select just areas and try again."});return}if(i)return;const t=w?void 0:h.toast.loading("Working…",{toasterId:P});S(!0);try{const s=await U.runGeometryWorkerOperation({type:"boolean",op:e,features:n}),m=new Set(b.getState().features.map(f=>f.id));if(!u.every(f=>m.has(f)))throw new Error("a selected shape was removed while it ran");p(s),t!==void 0&&h.toast.dismiss(t),a({type:"success",message:`${e[0].toUpperCase()}${e.slice(1)} completed`})}catch(s){t!==void 0&&h.toast.dismiss(t);const m=s instanceof Error?s.message:void 0;a({type:"error",code:s instanceof I.ElementEditorError?s.code:"geometry",source:"geometry",message:m?`Failed to perform ${e}: ${m}`:`Failed to perform ${e}`,cause:s})}finally{S(!1)}}return o.jsxs("div",{className:"flex items-center gap-2 bg-elm-surface/95 backdrop-blur-md border border-elm-border/80 shadow-elm rounded-elm px-2 py-2 pointer-events-auto antialiased",children:[o.jsx(g.EditToolbarBtn,{label:"Union: join into one shape",onClick:()=>d("union"),disabled:!c&&!x&&!y||i,children:i?o.jsx(l.Spinner,{size:24,className:"animate-spin"}):o.jsx(l.UniteSquare,{size:24,weight:"duotone"})}),o.jsx(g.EditToolbarBtn,{label:"Subtract: cut the others out of the first selected",onClick:()=>d("subtract"),disabled:!c||i,children:o.jsx(l.SubtractSquare,{size:24,weight:"duotone"})}),o.jsx(g.EditToolbarBtn,{label:"Intersect: keep only the overlap",onClick:()=>d("intersect"),disabled:!c||i,children:o.jsx(l.IntersectSquare,{size:24,weight:"duotone"})}),o.jsx(g.EditToolbarBtn,{label:"Exclude: keep only what doesn't overlap",onClick:()=>d("exclude"),disabled:!c||i,children:o.jsx(l.ExcludeSquare,{size:24,weight:"duotone"})})]})}exports.default=k;
@@ -0,0 +1,111 @@
1
+ import { jsxs as U, jsx as o } from "react/jsx-runtime";
2
+ import { e as x, f as b, u as w, h as L, i as j, j as z } from "./useAdapterControls-DVjkwRZ_.js";
3
+ import { E as u } from "./EditToolbarBtn-SZIsnIn3.js";
4
+ import { Spinner as C, UniteSquare as G, SubtractSquare as $, IntersectSquare as q, ExcludeSquare as F } from "@phosphor-icons/react";
5
+ import { toast as y } from "sonner";
6
+ import { ElementEditorError as B } from "@element-editor/core";
7
+ import { freeGeometry as O } from "@element-editor/core/internal";
8
+ import { c as T } from "./index-CtZterPc.js";
9
+ function Q() {
10
+ const { dataStore: f } = x(), c = b((e) => e.selectedIds), v = b((e) => e.features), n = w((e) => e.geometryProcessing), h = w((e) => e.setGeometryProcessing), i = L(), P = j(), I = z();
11
+ if (c.length < 2) return null;
12
+ const k = new Map(v.map((e) => [e.id, e])), r = c.flatMap((e) => {
13
+ const t = k.get(e);
14
+ return t ? [t] : [];
15
+ }), a = r.every((e) => e.geometry.type === "Polygon" || e.geometry.type === "MultiPolygon"), S = r.every((e) => e.geometry.type === "LineString" || e.geometry.type === "MultiLineString"), m = r.every((e) => e.geometry.type === "Point" || e.geometry.type === "MultiPoint");
16
+ if (m) return null;
17
+ function p(e) {
18
+ f.getState().replaceFeatures(c, [{
19
+ ...r[0],
20
+ id: crypto.randomUUID(),
21
+ ...O(e)
22
+ }]);
23
+ }
24
+ function E() {
25
+ const e = [];
26
+ for (const t of r)
27
+ t.geometry.type === "Point" ? e.push(t.geometry.coordinates) : t.geometry.type === "MultiPoint" && e.push(...t.geometry.coordinates);
28
+ p({ type: "MultiPoint", coordinates: e }), i({ type: "success", message: "Union completed" });
29
+ }
30
+ function M() {
31
+ const e = [];
32
+ for (const t of r)
33
+ t.geometry.type === "LineString" ? e.push(t.geometry.coordinates) : t.geometry.type === "MultiLineString" && e.push(...t.geometry.coordinates);
34
+ p({ type: "MultiLineString", coordinates: e }), i({ type: "success", message: "Union completed" });
35
+ }
36
+ async function l(e) {
37
+ if (e === "union" && m)
38
+ return E();
39
+ if (e === "union" && S)
40
+ return M();
41
+ if (!a) {
42
+ i({ type: "warning", message: "These work on areas only. Select just areas and try again." });
43
+ return;
44
+ }
45
+ if (n) return;
46
+ const t = P ? void 0 : y.loading("Working…", { toasterId: I });
47
+ h(!0);
48
+ try {
49
+ const s = await T({
50
+ type: "boolean",
51
+ op: e,
52
+ features: r
53
+ }), d = new Set(f.getState().features.map((g) => g.id));
54
+ if (!c.every((g) => d.has(g))) throw new Error("a selected shape was removed while it ran");
55
+ p(s), t !== void 0 && y.dismiss(t), i({ type: "success", message: `${e[0].toUpperCase()}${e.slice(1)} completed` });
56
+ } catch (s) {
57
+ t !== void 0 && y.dismiss(t);
58
+ const d = s instanceof Error ? s.message : void 0;
59
+ i({
60
+ type: "error",
61
+ code: s instanceof B ? s.code : "geometry",
62
+ source: "geometry",
63
+ message: d ? `Failed to perform ${e}: ${d}` : `Failed to perform ${e}`,
64
+ cause: s
65
+ });
66
+ } finally {
67
+ h(!1);
68
+ }
69
+ }
70
+ return /* @__PURE__ */ U("div", { className: "flex items-center gap-2 bg-elm-surface/95 backdrop-blur-md border border-elm-border/80 shadow-elm rounded-elm px-2 py-2 pointer-events-auto antialiased", children: [
71
+ /* @__PURE__ */ o(
72
+ u,
73
+ {
74
+ label: "Union: join into one shape",
75
+ onClick: () => l("union"),
76
+ disabled: !a && !S && !m || n,
77
+ children: n ? /* @__PURE__ */ o(C, { size: 24, className: "animate-spin" }) : /* @__PURE__ */ o(G, { size: 24, weight: "duotone" })
78
+ }
79
+ ),
80
+ /* @__PURE__ */ o(
81
+ u,
82
+ {
83
+ label: "Subtract: cut the others out of the first selected",
84
+ onClick: () => l("subtract"),
85
+ disabled: !a || n,
86
+ children: /* @__PURE__ */ o($, { size: 24, weight: "duotone" })
87
+ }
88
+ ),
89
+ /* @__PURE__ */ o(
90
+ u,
91
+ {
92
+ label: "Intersect: keep only the overlap",
93
+ onClick: () => l("intersect"),
94
+ disabled: !a || n,
95
+ children: /* @__PURE__ */ o(q, { size: 24, weight: "duotone" })
96
+ }
97
+ ),
98
+ /* @__PURE__ */ o(
99
+ u,
100
+ {
101
+ label: "Exclude: keep only what doesn't overlap",
102
+ onClick: () => l("exclude"),
103
+ disabled: !a || n,
104
+ children: /* @__PURE__ */ o(F, { size: 24, weight: "duotone" })
105
+ }
106
+ )
107
+ ] });
108
+ }
109
+ export {
110
+ Q as default
111
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),h=require("react"),X=require("react-data-grid"),S=require("@phosphor-icons/react"),g=require("./useAdapterControls-BBObhzVX.cjs"),ne=require("zustand/react/shallow"),ae=require("@element-editor/core"),oe=require("@element-editor/core/internal"),Y=require("./EditToolbarBtn-dpCmKnzk.cjs"),se=require("./FeatureRowContextMenu-Gwq3OMEA.cjs"),le=require("./useContextMenu-DbxMvb1s.cjs"),k=require("./index-BKdDZ4Y9.cjs"),ie=new Intl.Collator(void 0,{numeric:!0}),ce=new Set(["_id","_type","_size","_schemaId","_schemaName","_lat","_lng"]);function O(a){const u=new Set,c=[];for(const i of a)for(const d of i.fields)u.has(d.key)||(u.add(d.key),c.push(d));return c}function ue(a){const u=i=>`${i} point${i===1?"":"s"}`,c=(i,d)=>`${i} part${i===1?"":"s"} · ${u(d)}`;switch(a.type){case"Point":return"";case"MultiPoint":return u(a.coordinates.length);case"LineString":return u(a.coordinates.length);case"Polygon":return u(a.coordinates[0].length-1);case"MultiLineString":return c(a.coordinates.length,a.coordinates.reduce((i,d)=>i+d.length,0));case"MultiPolygon":return c(a.coordinates.length,a.coordinates.reduce((i,d)=>i+d[0].length-1,0));case"GeometryCollection":return`${a.geometries.length} part${a.geometries.length===1?"":"s"}`;default:return""}}function de({type:a}){return o.jsxs("span",{className:"flex items-center gap-1.5 flex-shrink-0 text-elm-text-secondary",children:[o.jsx("span",{className:"text-(--elm-text-subtle,var(--color-gray-400)) flex-shrink-0",children:o.jsx(k.GeometryTypeIcon,{type:a,size:16})}),o.jsx("span",{className:"text-sm",children:k.geometryTypeLabel(a)})]})}function U({row:a,column:u,onRowChange:c,onClose:i}){return o.jsx("input",{autoFocus:!0,type:"number",step:"any",className:"rdg-text-editor w-full h-full border-0 outline-none px-2 text-sm font-elm-mono bg-transparent text-inherit caret-primary-500",value:String(a[u.key]??""),onChange:d=>c({...a,[u.key]:d.target.value}),onBlur:()=>i(!0)})}function Q({checked:a,label:u,disabled:c,onToggle:i,autoFocus:d}){return o.jsx("span",{className:"flex h-full items-center px-0.5",children:o.jsx("button",{type:"button",role:"switch","aria-checked":a,"aria-label":u,tabIndex:-1,autoFocus:d,disabled:c,onClick:f=>{f.stopPropagation(),i()},className:`relative inline-flex h-4 w-7 flex-shrink-0 items-center rounded-full outline-none disabled:cursor-default enabled:cursor-pointer
2
+ ${a?"bg-primary-500":"bg-elm-border"} ${c?"opacity-50":"opacity-90 enabled:hover:opacity-100"}`,children:o.jsx("span",{"aria-hidden":!0,className:`absolute left-[2px] top-[2px] h-3 w-3 rounded-full border bg-white ${a?"border-white":"border-(--elm-border-strong,var(--color-gray-300))"}`,style:{transform:a?"translateX(12px)":void 0}})})})}function J(a){return function({row:c,column:i,onRowChange:d,onClose:f}){const j=String(c[i.key]??"");if(a.type==="boolean"){const y=k.readBooleanValue(c[i.key]);return o.jsx("div",{className:"w-full h-full px-2",onBlur:()=>f(!0),children:o.jsx(Q,{autoFocus:!0,checked:y,label:a.label,onToggle:()=>d({...c,[i.key]:!y})})})}if(a.type==="select"&&a.options)return o.jsxs("div",{className:"relative w-full h-full",children:[o.jsxs("select",{autoFocus:!0,className:"rdg-text-editor w-full h-full border-0 outline-none pl-2 pr-7 text-sm bg-transparent text-inherit appearance-none",value:j,onChange:y=>d({...c,[i.key]:y.target.value}),onBlur:()=>f(!0),children:[o.jsx("option",{value:"",children:"—"}),a.options.map(y=>o.jsx("option",{value:y,children:y},y))]}),o.jsx(S.CaretDown,{size:12,"aria-hidden":!0,className:"pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 opacity-60"})]});const m=a.type==="number"?"number":a.type==="date"?"date":a.type==="url"?"url":"text";return o.jsx("input",{autoFocus:!0,type:m,className:"rdg-text-editor w-full h-full border-0 outline-none px-2 text-sm bg-transparent text-inherit caret-primary-500",value:j,onChange:y=>d({...c,[i.key]:y.target.value}),onBlur:()=>f(!0)})}}function C(a){return o.jsx("span",{className:"block w-0 min-w-full truncate",children:a})}function me({sortDirection:a,priority:u}){if(!a)return null;const c=a==="ASC"?S.ArrowUp:S.ArrowDown;return o.jsxs("span",{className:"flex h-full items-center gap-0.5 pl-1",children:[o.jsx(c,{size:12,className:"shrink-0","aria-hidden":!0}),u!==void 0&&u>1&&o.jsx("span",{className:"text-[10px] leading-none opacity-60",children:u})]})}function pe({schemaFilter:a,focusRowId:u,onFocusRowHandled:c,selectedRows:i,onSelectedRowsChange:d}){const f=g.useDataStore(e=>e.features),j=g.useDataStore(e=>e.groups),m=g.useDataStore(ne.useShallow(e=>e.getVisibleSchemas())),y=g.useDataStore(e=>e.selectFeature),P=g.useDataStore(e=>e.updateFeature),q=g.useDataStore(e=>e.deleteFeature),b=g.useUIStore(e=>e.readonly),I=g.useDataStore(e=>e.selectedIds),{panTo:T,fitBounds:E}=g.useMapController(),$=g.useTheme(),F=h.useRef(null),{dataStore:_}=g.useGeoStore(),L=g.useEmit(),v=le.useContextMenu(),[M,Z]=h.useState([]),N=h.useMemo(()=>{if(a==="all")return O(m);const e=m.find(t=>t.id===a);return e?e.fields:O(m)},[m,a]),K=h.useMemo(()=>{const e={};for(const t of m)e[t.id]=t.name;return e},[m]),A=h.useMemo(()=>{var s;const e=new Map,t=[];for(const l of f){if(!l.groupId){t.push(l);continue}const p=e.get(l.groupId);p?p.push(l):e.set(l.groupId,[l])}const r=[...j.flatMap(l=>e.get(l.id)??[]),...t];if(a==="all")return r;const n=(s=m[0])==null?void 0:s.id;return r.filter(l=>(l.schemaId??n)===a)},[f,j,m,a]),w=h.useMemo(()=>A.map(e=>{var s,l;let t="",r="";if(e.geometry.type==="Point"){const[p,x]=e.geometry.coordinates;t=String(x),r=String(p)}const n=e.schemaId??((s=m[0])==null?void 0:s.id)??"";return{_id:e.id,_type:e.geometry.type,_size:ue(e.geometry),_schemaId:n,_schemaName:K[n]??((l=m[0])==null?void 0:l.name)??"",_lat:t,_lng:r,...e.properties}}),[A,K,m]),z=h.useMemo(()=>new Set(N.filter(e=>e.type==="boolean").map(e=>e.key)),[N]),B=h.useMemo(()=>{if(M.length===0)return w;const e=(t,r)=>z.has(r)?k.readBooleanValue(t[r])?"1":"0":String(t[r]??"");return[...w].sort((t,r)=>{for(const n of M){const s=e(t,n.columnKey),l=e(r,n.columnKey),p=ie.compare(s,l);if(p!==0)return n.direction==="ASC"?p:-p}return 0})},[w,M,z]),V=h.useMemo(()=>w.some(e=>e._type==="Point"),[w]),G=h.useCallback((e,t)=>{var s;if(b)return;const r=_.getState(),n=r.features.find(l=>l.id===e);n&&r.updateFeatures([{id:e,patch:{properties:{...n.properties,[t]:!k.readBooleanValue((s=n.properties)==null?void 0:s[t])}}}])},[_,b]),W=h.useMemo(()=>{const e=[X.SelectColumn,{key:"_type",name:C("Type"),width:150,resizable:!0,sortable:!0,renderCell:({row:t})=>o.jsxs("span",{className:"flex items-center gap-2 min-w-0",children:[o.jsx(de,{type:t._type}),t._size&&o.jsx("span",{className:"truncate text-xs text-elm-text-muted",children:t._size})]})}];m.length>1&&e.push({key:"_schemaName",name:C("Schema"),width:100,resizable:!0,sortable:!0,editable:!0,renderCell:({row:t})=>o.jsx("span",{className:"inline-block px-1.5 py-0.5 rounded-elm-chip bg-elm-surface-hover text-(--elm-text-secondary,var(--color-gray-600)) dark:text-(--elm-text-secondary,var(--color-gray-300)) text-[10px] font-medium",children:t._schemaName}),renderEditCell:({row:t,onRowChange:r,onClose:n})=>o.jsxs("div",{className:"relative w-full h-full",children:[o.jsx("select",{autoFocus:!0,className:"rdg-text-editor w-full h-full border-0 outline-none pl-2 pr-7 text-sm appearance-none",value:t._schemaId,onChange:s=>{const l=m.find(p=>p.id===s.target.value);l&&r({...t,_schemaId:l.id,_schemaName:l.name})},onBlur:()=>n(!0),children:m.map(s=>o.jsx("option",{value:s.id,children:s.name},s.id))}),o.jsx(S.CaretDown,{size:12,"aria-hidden":!0,className:"pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 opacity-60"})]})}),V&&e.push({key:"_lat",name:C("Lat"),width:110,resizable:!0,sortable:!0,editable:t=>t._type==="Point",renderCell:({row:t})=>o.jsx("span",{className:"font-elm-mono text-xs text-(--elm-text-secondary,var(--color-gray-600)) dark:text-(--elm-text-secondary,var(--color-gray-300))",children:t._lat}),renderEditCell:U},{key:"_lng",name:C("Lng"),width:110,resizable:!0,sortable:!0,editable:t=>t._type==="Point",renderCell:({row:t})=>o.jsx("span",{className:"font-elm-mono text-xs text-(--elm-text-secondary,var(--color-gray-600)) dark:text-(--elm-text-secondary,var(--color-gray-300))",children:t._lng}),renderEditCell:U});for(const t of N){if(t.type==="boolean"){e.push({key:t.key,name:C(t.label),minWidth:80,resizable:!0,sortable:!0,editable:!0,renderCell:({row:r})=>o.jsx(Q,{checked:k.readBooleanValue(r[t.key]),label:t.label,disabled:b,onToggle:()=>G(r._id,t.key)}),renderEditCell:J(t)});continue}e.push({key:t.key,name:C(t.label),...t.key==="name"&&{width:200},minWidth:80,resizable:!0,sortable:!0,editable:!0,renderEditCell:J(t)})}return e.push({key:"_spacer",name:"",minWidth:0,width:"minmax(0, 1fr)",resizable:!1,sortable:!1,renderCell:()=>null}),e.push({key:"_delete",name:"",width:36,resizable:!1,sortable:!1,renderHeaderCell:()=>i.size>0?o.jsx("div",{className:"w-full h-full flex items-center justify-center",children:o.jsx(Y.Tooltip,{content:`Delete ${i.size} selected`,children:o.jsx("button",{"aria-label":`Delete ${i.size} selected`,onMouseDown:t=>t.stopPropagation(),onClick:t=>{t.stopPropagation();const r=_.getState(),n=i.size;r.setSelection([...i]),r.deleteSelection(),d(new Set),L({type:"features:deleted",count:n,undo:()=>_.getState().undo()})},className:"w-7 h-7 rounded-elm-control flex items-center justify-center text-(--elm-text-secondary,var(--color-gray-600)) dark:text-(--elm-text-secondary,var(--color-gray-300)) hover:bg-(--elm-surface-hover,var(--color-gray-100)) dark:hover:bg-(--elm-surface-hover,var(--color-gray-700)) hover:text-(--elm-text-secondary,var(--color-gray-700)) dark:hover:text-(--elm-text-secondary,var(--color-gray-200)) transition-colors",children:o.jsx(S.Trash,{size:16})})})}):null,renderCell:({row:t})=>o.jsx("div",{className:"w-full h-full flex items-center justify-center",children:o.jsx(Y.Tooltip,{content:"Delete row",children:o.jsx("button",{onMouseDown:r=>r.stopPropagation(),onClick:r=>{r.stopPropagation(),q(t._id)},className:"w-7 h-7 rounded-elm-control flex items-center justify-center text-elm-text hover:bg-(--elm-surface-hover,var(--color-gray-100)) dark:hover:bg-(--elm-surface-hover,var(--color-gray-700)) transition-colors",children:o.jsx(S.Trash,{size:16})})})})}),b?e.filter(t=>t.key!=="_delete").map(t=>({...t,editable:!1})):e},[N,m.length,V,q,i,d,_,L,b,G]);h.useEffect(()=>{if(!u)return;const e=B.findIndex(r=>r._id===u);if(e===-1)return;const t=W.findIndex(r=>r.key==="_lat");t!==-1&&requestAnimationFrame(()=>{var r;(r=F.current)==null||r.selectCell({rowIdx:e,idx:t},{enableEditor:!0}),c==null||c()})},[u]),h.useEffect(()=>{var t;if(I.length===0)return;const e=B.findIndex(r=>r._id===I[0]);e!==-1&&((t=F.current)==null||t.scrollToCell({rowIdx:e}))},[I]);function H(e,{indexes:t}){var p;if(b)return;const r=e[t[0]],n={};for(const[x,D]of Object.entries(r))ce.has(x)||(n[x]=D);const s=f.find(x=>x.id===r._id),l=(s==null?void 0:s.schemaId)??((p=m[0])==null?void 0:p.id)??"";if(r._schemaId!==l){P(r._id,{schemaId:r._schemaId,properties:n});return}if((s==null?void 0:s.geometry.type)==="Point"){const x=parseFloat(r._lat),D=parseFloat(r._lng),[te,re]=s.geometry.coordinates;if(!isNaN(x)&&!isNaN(D)&&(x!==re||D!==te)){_.getState().takeSnapshot(),P(r._id,{geometry:{type:"Point",coordinates:oe.withXY(s.geometry.coordinates,[D,x])},properties:n});return}}P(r._id,{properties:n})}function R({row:e,column:t},r){const n=r.clipboardData.getData("text/plain").split(/\r?\n/)[0].split(" ")[0].trim();if(!n||b)return e;if(t.key==="_schemaName"){const l=m.find(p=>p.name===n||p.id===n);return l?{...e,_schemaId:l.id,_schemaName:l.name}:e}if(t.key==="_lat"||t.key==="_lng")return Number.isFinite(Number(n))?{...e,[t.key]:n}:e;const s=N.find(l=>l.key===t.key);if((s==null?void 0:s.type)==="boolean"){const l=k.parseBooleanText(n);return l===null?e:{...e,[t.key]:l}}return(s==null?void 0:s.type)==="number"?Number.isFinite(Number(n))?{...e,[t.key]:n}:e:(s==null?void 0:s.type)==="select"&&s.options&&!s.options.includes(n)?e:{...e,[t.key]:n}}function ee(e){if(d(e),e.size!==1)return;const t=[...e][0];y(t);const r=f.find(n=>n.id===t);if(r)if(r.geometry.type==="Point"){const[n,s]=r.geometry.coordinates;T==null||T([s,n])}else E==null||E(r.bbox||ae.getGeometryBBox(r.geometry))}return o.jsxs("div",{className:"contents",onMouseDown:e=>{e.detail>=2&&!e.target.closest("input, select, textarea")&&e.preventDefault()},children:[o.jsx(X.DataGrid,{ref:F,columns:W,rows:B,rowKeyGetter:e=>e._id,rowClass:e=>I.includes(e._id)?"elm-row-active":void 0,onRowsChange:H,renderers:{renderSortStatus:me},sortColumns:M,onSortColumnsChange:Z,selectedRows:i,onSelectedRowsChange:ee,onCellPaste:R,onCellKeyDown:({mode:e,row:t,column:r},n)=>{e!=="SELECT"||!z.has(r.key)||n.key===" "&&n.shiftKey||(n.key===" "||n.key==="Enter"?(n.preventGridDefault(),n.preventDefault(),G(t._id,r.key)):n.key.length===1&&!n.ctrlKey&&!n.metaKey&&!n.altKey&&n.preventGridDefault())},onCellDoubleClick:({column:e},t)=>{z.has(e.key)&&t.preventGridDefault()},onCellContextMenu:({row:e},t)=>{const r=f.find(n=>n.id===e._id);r&&(t.preventGridDefault(),t.preventDefault(),v.open(t.clientX,t.clientY,r))},className:$==="dark"?"rdg-dark":"rdg-light",style:{...$==="dark"?{"--rdg-color":"var(--elm-text, #e5e5e5)","--rdg-border-color":"var(--elm-border, #404040)","--rdg-selection-color":"var(--color-primary-400)"}:{"--rdg-color":"var(--elm-text, #000)","--rdg-border-color":"var(--elm-border, #ddd)","--rdg-selection-color":"var(--color-primary-500)"},"--rdg-background-color":"transparent","--rdg-header-background-color":"var(--elm-surface, var(--_elm-surface))","--elm-rdg-sticky-bg":"var(--elm-surface, var(--_elm-surface))",blockSize:"100%","--rdg-row-hover-background-color":"var(--elm-row-hover)","--rdg-row-selected-background-color":"var(--elm-row-checked)","--rdg-row-selected-hover-background-color":"var(--elm-row-checked-hover)"}}),v.state&&o.jsx(se.FeatureRowContextMenu,{x:v.state.x,y:v.state.y,feature:f.find(e=>e.id===v.state.data.id)??v.state.data,onClose:v.close,showGrouping:!1})]})}exports.default=pe;