@element-editor/ui 0.0.0-stage → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +65 -0
- package/LICENSE +21 -0
- package/README.md +46 -2
- package/dist/BooleanOperations-BRO7NHUY.js +111 -0
- package/dist/BooleanOperations-C2uOHRu3.cjs +1 -0
- package/dist/DataTable-B-2VjBEz.cjs +2 -0
- package/dist/DataTable-CS-3dIqY.js +510 -0
- package/dist/DataTablePanel-58LwzXQR.cjs +1 -0
- package/dist/DataTablePanel-DDFUmMaM.js +208 -0
- package/dist/EditToolbarBtn-Ch9HCLHq.cjs +3 -0
- package/dist/EditToolbarBtn-SR4xHd8G.js +378 -0
- package/dist/FeatureEditModal-Cc8N6vei.cjs +1 -0
- package/dist/FeatureEditModal-Dr10p3nE.js +77 -0
- package/dist/FeatureList-Bo9w9nre.js +520 -0
- package/dist/FeatureList-VRYesXCq.cjs +1 -0
- package/dist/FeatureRowContextMenu-CtBqdC1j.cjs +1 -0
- package/dist/FeatureRowContextMenu-DCUIiDwc.js +130 -0
- package/dist/GeoJSONModal-BV9Tamf4.js +886 -0
- package/dist/GeoJSONModal-Dd-nBufy.cjs +9 -0
- package/dist/SchemaEditor-B4L17K1e.cjs +1 -0
- package/dist/SchemaEditor-ryoTgaLb.js +293 -0
- package/dist/SchemaModal-DvMbWskS.js +95 -0
- package/dist/SchemaModal-gAuDkd-L.cjs +1 -0
- package/dist/SettingsModal-BScVTjpn.js +237 -0
- package/dist/SettingsModal-CqaSFxxR.cjs +1 -0
- package/dist/ShortcutsModal-D1Y2bGT8.cjs +1 -0
- package/dist/ShortcutsModal-ozuS2Ysb.js +299 -0
- package/dist/components/ActiveDrawingToolbar.d.cts +1 -0
- package/dist/components/ActiveDrawingToolbar.d.ts +1 -0
- package/dist/components/BasemapPicker.d.cts +26 -0
- package/dist/components/BasemapPicker.d.ts +26 -0
- package/dist/components/BooleanOperations.d.cts +1 -0
- package/dist/components/BooleanOperations.d.ts +1 -0
- package/dist/components/BufferPanel.d.cts +1 -0
- package/dist/components/BufferPanel.d.ts +1 -0
- package/dist/components/DataTable.d.cts +9 -0
- package/dist/components/DataTable.d.ts +9 -0
- package/dist/components/DataTablePanel.d.cts +10 -0
- package/dist/components/DataTablePanel.d.ts +10 -0
- package/dist/components/EditingToolbar.d.cts +1 -0
- package/dist/components/EditingToolbar.d.ts +1 -0
- package/dist/components/ElementEditorErrorBoundary.d.cts +28 -0
- package/dist/components/ElementEditorErrorBoundary.d.ts +28 -0
- package/dist/components/ElementEditorUIProvider.d.cts +50 -0
- package/dist/components/ElementEditorUIProvider.d.ts +50 -0
- package/dist/components/FeatureMapContextMenu.d.cts +23 -0
- package/dist/components/FeatureMapContextMenu.d.ts +23 -0
- package/dist/components/FitBoundsButton.d.cts +6 -0
- package/dist/components/FitBoundsButton.d.ts +6 -0
- package/dist/components/FloatingToolbar.d.cts +3 -0
- package/dist/components/FloatingToolbar.d.ts +3 -0
- package/dist/components/LocateButton.d.cts +11 -0
- package/dist/components/LocateButton.d.ts +11 -0
- package/dist/components/ReadonlyBanner.d.cts +1 -0
- package/dist/components/ReadonlyBanner.d.ts +1 -0
- package/dist/components/ShortcutsModal.d.cts +1 -0
- package/dist/components/ShortcutsModal.d.ts +1 -0
- package/dist/components/SimplifyPanel.d.cts +1 -0
- package/dist/components/SimplifyPanel.d.ts +1 -0
- package/dist/components/SmoothPanel.d.cts +1 -0
- package/dist/components/SmoothPanel.d.ts +1 -0
- package/dist/components/UndoRedoToolbar.d.cts +20 -0
- package/dist/components/UndoRedoToolbar.d.ts +20 -0
- package/dist/components/VertexSelectionBar.d.cts +12 -0
- package/dist/components/VertexSelectionBar.d.ts +12 -0
- package/dist/components/ZoomIndicator.d.cts +15 -0
- package/dist/components/ZoomIndicator.d.ts +15 -0
- package/dist/components/dialogs/DynamicFieldRenderer.d.cts +11 -0
- package/dist/components/dialogs/DynamicFieldRenderer.d.ts +11 -0
- package/dist/components/dialogs/SettingsModal.d.cts +1 -0
- package/dist/components/dialogs/SettingsModal.d.ts +1 -0
- package/dist/components/lazyParts.d.cts +12 -0
- package/dist/components/lazyParts.d.ts +12 -0
- package/dist/components/sidebar/FeatureEditModal.d.cts +6 -0
- package/dist/components/sidebar/FeatureEditModal.d.ts +6 -0
- package/dist/components/sidebar/FeatureList.d.cts +4 -0
- package/dist/components/sidebar/FeatureList.d.ts +4 -0
- package/dist/components/sidebar/FeatureRow.d.cts +38 -0
- package/dist/components/sidebar/FeatureRow.d.ts +38 -0
- package/dist/components/sidebar/FeatureRowContextMenu.d.cts +12 -0
- package/dist/components/sidebar/FeatureRowContextMenu.d.ts +12 -0
- package/dist/components/sidebar/FeatureSidePanel.d.cts +8 -0
- package/dist/components/sidebar/FeatureSidePanel.d.ts +8 -0
- package/dist/components/sidebar/GeoJSONModal.d.cts +5 -0
- package/dist/components/sidebar/GeoJSONModal.d.ts +5 -0
- package/dist/components/sidebar/GroupRow.d.cts +21 -0
- package/dist/components/sidebar/GroupRow.d.ts +21 -0
- package/dist/components/sidebar/HideLayersToggle.d.cts +2 -0
- package/dist/components/sidebar/HideLayersToggle.d.ts +2 -0
- package/dist/components/sidebar/LayersPanel.d.cts +5 -0
- package/dist/components/sidebar/LayersPanel.d.ts +5 -0
- package/dist/components/sidebar/PartSubRow.d.cts +9 -0
- package/dist/components/sidebar/PartSubRow.d.ts +9 -0
- package/dist/components/sidebar/SchemaEditor.d.cts +4 -0
- package/dist/components/sidebar/SchemaEditor.d.ts +4 -0
- package/dist/components/sidebar/SchemaModal.d.cts +5 -0
- package/dist/components/sidebar/SchemaModal.d.ts +5 -0
- package/dist/components/sidebar/codeDock.d.cts +21 -0
- package/dist/components/sidebar/codeDock.d.ts +21 -0
- package/dist/components/ui/Button.d.cts +9 -0
- package/dist/components/ui/Button.d.ts +9 -0
- package/dist/components/ui/CloseButton.d.cts +6 -0
- package/dist/components/ui/CloseButton.d.ts +6 -0
- package/dist/components/ui/ContextMenu.d.cts +28 -0
- package/dist/components/ui/ContextMenu.d.ts +28 -0
- package/dist/components/ui/EditToolbarBtn.d.cts +13 -0
- package/dist/components/ui/EditToolbarBtn.d.ts +13 -0
- package/dist/components/ui/ElementToaster.d.cts +3 -0
- package/dist/components/ui/ElementToaster.d.ts +3 -0
- package/dist/components/ui/GeometryTypeIcon.d.cts +7 -0
- package/dist/components/ui/GeometryTypeIcon.d.ts +7 -0
- package/dist/components/ui/IconButton.d.cts +28 -0
- package/dist/components/ui/IconButton.d.ts +28 -0
- package/dist/components/ui/Input.d.cts +14 -0
- package/dist/components/ui/Input.d.ts +14 -0
- package/dist/components/ui/JsonCode.d.cts +4 -0
- package/dist/components/ui/JsonCode.d.ts +4 -0
- package/dist/components/ui/Kbd.d.cts +16 -0
- package/dist/components/ui/Kbd.d.ts +16 -0
- package/dist/components/ui/NoFeaturesEmptyState.d.cts +1 -0
- package/dist/components/ui/NoFeaturesEmptyState.d.ts +1 -0
- package/dist/components/ui/SearchDropdown.d.cts +28 -0
- package/dist/components/ui/SearchDropdown.d.ts +28 -0
- package/dist/components/ui/ToolButton.d.cts +19 -0
- package/dist/components/ui/ToolButton.d.ts +19 -0
- package/dist/components/ui/Tooltip.d.cts +12 -0
- package/dist/components/ui/Tooltip.d.ts +12 -0
- package/dist/components/ui/panelHeader.d.cts +2 -0
- package/dist/components/ui/panelHeader.d.ts +2 -0
- package/dist/components/ui/resizeEdge.d.cts +4 -0
- package/dist/components/ui/resizeEdge.d.ts +4 -0
- package/dist/contexts/ElementEditorConfigContext.d.cts +351 -0
- package/dist/contexts/ElementEditorConfigContext.d.ts +351 -0
- package/dist/contexts/EventContext.d.cts +69 -0
- package/dist/contexts/EventContext.d.ts +69 -0
- package/dist/contexts/MapControllerContext.d.cts +24 -0
- package/dist/contexts/MapControllerContext.d.ts +24 -0
- package/dist/contexts/ShortcutConfigContext.d.cts +16 -0
- package/dist/contexts/ShortcutConfigContext.d.ts +16 -0
- package/dist/contexts/ThemeContext.d.cts +12 -0
- package/dist/contexts/ThemeContext.d.ts +12 -0
- package/dist/element-editor-ui.cjs +1 -0
- package/dist/element-editor-ui.es.js +102 -0
- package/dist/geometryWorker-CCwg4tNC.cjs +1 -0
- package/dist/geometryWorker-DgQCFSmD.js +25 -0
- package/dist/hooks/dragShield.d.cts +7 -0
- package/dist/hooks/dragShield.d.ts +7 -0
- package/dist/hooks/themeInputs.d.cts +14 -0
- package/dist/hooks/themeInputs.d.ts +14 -0
- package/dist/hooks/useAccentPalette.d.cts +15 -0
- package/dist/hooks/useAccentPalette.d.ts +15 -0
- package/dist/hooks/useAccentStyle.d.cts +39 -0
- package/dist/hooks/useAccentStyle.d.ts +39 -0
- package/dist/hooks/useAdapterControls.d.cts +280 -0
- package/dist/hooks/useAdapterControls.d.ts +280 -0
- package/dist/hooks/useBalancedWrap.d.cts +8 -0
- package/dist/hooks/useBalancedWrap.d.ts +8 -0
- package/dist/hooks/useContextMenu.d.cts +11 -0
- package/dist/hooks/useContextMenu.d.ts +11 -0
- package/dist/hooks/useDataChangeSubscription.d.cts +9 -0
- package/dist/hooks/useDataChangeSubscription.d.ts +9 -0
- package/dist/hooks/useDragWindow.d.cts +9 -0
- package/dist/hooks/useDragWindow.d.ts +9 -0
- package/dist/hooks/useFocusTrap.d.cts +7 -0
- package/dist/hooks/useFocusTrap.d.ts +7 -0
- package/dist/hooks/useGeoJSONDrop.d.cts +40 -0
- package/dist/hooks/useGeoJSONDrop.d.ts +40 -0
- package/dist/hooks/useGeoJSONExport.d.cts +69 -0
- package/dist/hooks/useGeoJSONExport.d.ts +69 -0
- package/dist/hooks/useGeoJSONFileImport.d.cts +24 -0
- package/dist/hooks/useGeoJSONFileImport.d.ts +24 -0
- package/dist/hooks/useInlineRename.d.cts +26 -0
- package/dist/hooks/useInlineRename.d.ts +26 -0
- package/dist/hooks/useJumpToFeature.d.cts +3 -0
- package/dist/hooks/useJumpToFeature.d.ts +3 -0
- package/dist/hooks/useKeyboardShortcuts.d.cts +9 -0
- package/dist/hooks/useKeyboardShortcuts.d.ts +9 -0
- package/dist/hooks/useNominatim.d.cts +24 -0
- package/dist/hooks/useNominatim.d.ts +24 -0
- package/dist/hooks/usePanelOffset.d.cts +14 -0
- package/dist/hooks/usePanelOffset.d.ts +14 -0
- package/dist/hooks/useResizablePanel.d.cts +4 -0
- package/dist/hooks/useResizablePanel.d.ts +4 -0
- package/dist/hooks/useRootTokens.d.cts +27 -0
- package/dist/hooks/useRootTokens.d.ts +27 -0
- package/dist/hooks/useSearchState.d.cts +23 -0
- package/dist/hooks/useSearchState.d.ts +23 -0
- package/dist/hooks/useServiceAttribution.d.cts +13 -0
- package/dist/hooks/useServiceAttribution.d.ts +13 -0
- package/dist/hooks/useWindowEscape.d.cts +25 -0
- package/dist/hooks/useWindowEscape.d.ts +25 -0
- package/dist/hooks/useWindowFocus.d.cts +4 -0
- package/dist/hooks/useWindowFocus.d.ts +4 -0
- package/dist/hooks/useWorkerGeometryPreview.d.cts +22 -0
- package/dist/hooks/useWorkerGeometryPreview.d.ts +22 -0
- package/dist/index-CILw1Du5.js +3165 -0
- package/dist/index-DG4wEjGj.cjs +1 -0
- package/dist/index.d.cts +89 -0
- package/dist/index.d.ts +89 -0
- package/dist/internal.cjs +1 -0
- package/dist/internal.d.cts +16 -0
- package/dist/internal.d.ts +16 -0
- package/dist/internal.es.js +42 -0
- package/dist/primitives.cjs +1 -0
- package/dist/primitives.d.cts +19 -0
- package/dist/primitives.d.ts +19 -0
- package/dist/primitives.es.js +17 -0
- package/dist/store/StoreContext.d.cts +17 -0
- package/dist/store/StoreContext.d.ts +17 -0
- package/dist/types/events.d.cts +95 -0
- package/dist/types/events.d.ts +95 -0
- package/dist/useAccentStyle-CPo2XqAn.js +412 -0
- package/dist/useAccentStyle-hsGvyHZc.cjs +1 -0
- package/dist/useAdapterControls-BBObhzVX.cjs +1 -0
- package/dist/useAdapterControls-DVjkwRZ_.js +691 -0
- package/dist/useContextMenu-DJ2Cti85.js +10 -0
- package/dist/useContextMenu-DbxMvb1s.cjs +1 -0
- package/dist/useFocusTrap-BBjPCfDR.cjs +1 -0
- package/dist/useFocusTrap-CKxKT8De.js +25 -0
- package/dist/useJumpToFeature-Bdz2hqOC.js +16 -0
- package/dist/useJumpToFeature-LwjxGzfy.cjs +1 -0
- package/dist/useWindowFocus-DuQVjnHE.js +80 -0
- package/dist/useWindowFocus-EemgNOuz.cjs +1 -0
- package/dist/utils/booleanValue.d.cts +4 -0
- package/dist/utils/booleanValue.d.ts +4 -0
- package/dist/utils/clipboardError.d.cts +3 -0
- package/dist/utils/clipboardError.d.ts +3 -0
- package/dist/utils/download.d.cts +42 -0
- package/dist/utils/download.d.ts +42 -0
- package/dist/utils/geojsonDocument.d.cts +168 -0
- package/dist/utils/geojsonDocument.d.ts +168 -0
- package/dist/utils/geometryWorkerClient.d.cts +6 -0
- package/dist/utils/geometryWorkerClient.d.ts +6 -0
- package/dist/utils/layerOrder.d.cts +9 -0
- package/dist/utils/layerOrder.d.ts +9 -0
- package/dist/utils/lazyWithPreload.d.cts +24 -0
- package/dist/utils/lazyWithPreload.d.ts +24 -0
- package/dist/utils/lineSmooth.d.cts +7 -0
- package/dist/utils/lineSmooth.d.ts +7 -0
- package/dist/utils/platform.d.cts +2 -0
- package/dist/utils/platform.d.ts +2 -0
- package/dist/workers/geometryWorker.d.cts +1 -0
- package/dist/workers/geometryWorker.d.ts +1 -0
- 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
|
-
#
|
|
1
|
+
# @element-editor/ui
|
|
2
2
|
|
|
3
|
-
|
|
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,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-SR4xHd8G.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-CILw1Du5.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 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),r=require("./useAdapterControls-BBObhzVX.cjs"),g=require("./EditToolbarBtn-Ch9HCLHq.cjs"),l=require("@phosphor-icons/react"),h=require("sonner"),I=require("@element-editor/core"),M=require("@element-editor/core/internal"),U=require("./index-DG4wEjGj.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,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-Ch9HCLHq.cjs"),se=require("./FeatureRowContextMenu-CtBqdC1j.cjs"),le=require("./useContextMenu-DbxMvb1s.cjs"),k=require("./index-DG4wEjGj.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;
|