@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.
- package/AGENTS.md +65 -0
- package/LICENSE +21 -0
- package/README.md +46 -2
- package/dist/BooleanOperations-WXcmW9Vy.cjs +1 -0
- package/dist/BooleanOperations-oF0WybQP.js +111 -0
- package/dist/DataTable-CNfB01y2.cjs +2 -0
- package/dist/DataTable-DNmjUwka.js +510 -0
- package/dist/DataTablePanel-BknCxC1K.cjs +1 -0
- package/dist/DataTablePanel-rWdaQubk.js +208 -0
- package/dist/EditToolbarBtn-SZIsnIn3.js +378 -0
- package/dist/EditToolbarBtn-dpCmKnzk.cjs +3 -0
- package/dist/FeatureEditModal-BF-fGhVD.js +77 -0
- package/dist/FeatureEditModal-CM6BObUO.cjs +1 -0
- package/dist/FeatureList-CQb2kTrV.js +520 -0
- package/dist/FeatureList-Csr-anLA.cjs +1 -0
- package/dist/FeatureRowContextMenu-BLt7VlUU.js +130 -0
- package/dist/FeatureRowContextMenu-Gwq3OMEA.cjs +1 -0
- package/dist/GeoJSONModal-BPFWeaLZ.js +886 -0
- package/dist/GeoJSONModal-iwUcvrg7.cjs +9 -0
- package/dist/SchemaEditor-BEsKUe2p.js +293 -0
- package/dist/SchemaEditor-qkoYMg0C.cjs +1 -0
- package/dist/SchemaModal-9nNrgorr.js +95 -0
- package/dist/SchemaModal-GrtgA7cH.cjs +1 -0
- package/dist/SettingsModal-6_qmRyCi.cjs +1 -0
- package/dist/SettingsModal-DTP0Xx_Z.js +237 -0
- package/dist/ShortcutsModal-CdyQlrqK.cjs +1 -0
- package/dist/ShortcutsModal-DwxZu71W.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-BKdDZ4Y9.cjs +1 -0
- package/dist/index-CtZterPc.js +3165 -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-D-_yEm_V.cjs +1 -0
- package/dist/useWindowFocus-DGAWA1au.js +80 -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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const e=require("react");function a(){const[n,t]=e.useState(null),s=e.useCallback((c,l,o)=>{t({x:c,y:l,data:o})},[]),u=e.useCallback(()=>t(null),[]);return{state:n,open:s,close:u}}exports.useContextMenu=a;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const l=require("react");function a(e,r=!0){l.useEffect(()=>{if(!e.current||!r)return;const o=document.activeElement;function c(t){if(t.key!=="Tab")return;const s=e.current;if(!s)return;const n=f(s);if(n.length===0)return;const u=n[0],i=n[n.length-1];t.shiftKey?document.activeElement===u&&(t.preventDefault(),i.focus()):document.activeElement===i&&(t.preventDefault(),u.focus())}return document.addEventListener("keydown",c),()=>{document.removeEventListener("keydown",c),o==null||o.focus()}},[e,r])}function f(e){return Array.from(e.querySelectorAll('a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])'))}exports.useFocusTrap=a;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect as l } from "react";
|
|
2
|
+
function m(e, o = !0) {
|
|
3
|
+
l(() => {
|
|
4
|
+
if (!e.current || !o) return;
|
|
5
|
+
const r = document.activeElement;
|
|
6
|
+
function c(t) {
|
|
7
|
+
if (t.key !== "Tab") return;
|
|
8
|
+
const s = e.current;
|
|
9
|
+
if (!s) return;
|
|
10
|
+
const n = a(s);
|
|
11
|
+
if (n.length === 0) return;
|
|
12
|
+
const u = n[0], i = n[n.length - 1];
|
|
13
|
+
t.shiftKey ? document.activeElement === u && (t.preventDefault(), i.focus()) : document.activeElement === i && (t.preventDefault(), u.focus());
|
|
14
|
+
}
|
|
15
|
+
return document.addEventListener("keydown", c), () => {
|
|
16
|
+
document.removeEventListener("keydown", c), r == null || r.focus();
|
|
17
|
+
};
|
|
18
|
+
}, [e, o]);
|
|
19
|
+
}
|
|
20
|
+
function a(e) {
|
|
21
|
+
return Array.from(e.querySelectorAll('a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])'));
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
m as u
|
|
25
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useCallback as s } from "react";
|
|
2
|
+
import { getGeometryBBox as a } from "@element-editor/core";
|
|
3
|
+
import { g as l } from "./useAdapterControls-DVjkwRZ_.js";
|
|
4
|
+
function i() {
|
|
5
|
+
const { panTo: e, fitBounds: o } = l();
|
|
6
|
+
return s((t) => {
|
|
7
|
+
if (t.geometry.type === "Point") {
|
|
8
|
+
const [r, m] = t.geometry.coordinates;
|
|
9
|
+
e == null || e([m, r]);
|
|
10
|
+
} else
|
|
11
|
+
o == null || o(t.bbox || a(t.geometry));
|
|
12
|
+
}, [e, o]);
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
i as u
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const u=require("react"),c=require("@element-editor/core"),n=require("./useAdapterControls-BBObhzVX.cjs");function a(){const{panTo:e,fitBounds:t}=n.useMapController();return u.useCallback(r=>{if(r.geometry.type==="Point"){const[o,s]=r.geometry.coordinates;e==null||e([s,o])}else t==null||t(r.bbox||c.getGeometryBBox(r.geometry))},[e,t])}exports.useJumpToFeature=a;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const h=require("react/jsx-runtime"),q=require("@phosphor-icons/react"),g=require("./index-BKdDZ4Y9.cjs"),i=require("react"),p=require("@element-editor/core"),D=require("./useAccentStyle-hsGvyHZc.cjs");function L({onClick:e,label:a="Close"}){return h.jsx("button",{onMouseDown:o=>o.stopPropagation(),onClick:e,"aria-label":a,className:`flex ${g.panelHeaderIconBtn}`,children:h.jsx(q.X,{size:16})})}const m=1;function R(e){return!!e&&typeof e=="object"&&typeof e.x=="number"&&typeof e.y=="number"}function w(e){return{x:Math.max(0,Math.min(window.innerWidth-120,e.x)),y:Math.max(0,Math.min(window.innerHeight-60,e.y))}}function z(e,a){const o=D.useElementEditorConfig(),[d,u]=i.useState(()=>{const n=p.readPersisted(e,m,r=>R(r)?r:null,o);return n?w(n):a}),c=i.useRef(d);c.current=d,i.useEffect(()=>{function n(){u(r=>{const l=w(r);return l.x===r.x&&l.y===r.y?r:(p.writePersisted(e,m,l,o),l)})}return window.addEventListener("resize",n),()=>window.removeEventListener("resize",n)},[e,o]);const S=i.useCallback(n=>{if(n.button!==0)return;n.preventDefault();const r=n.clientX,l=n.clientY,x=c.current.x,y=c.current.y,C=g.startDragShield("grabbing");let t=n.currentTarget;for(;t&&getComputedStyle(t).position!=="fixed";)t=t.parentElement;const M=(t==null?void 0:t.style.left)??"",P=(t==null?void 0:t.style.top)??"";function v(b){const f=w({x:x+b.clientX-r,y:y+b.clientY-l});if(c.current=f,!t){u(f);return}t.style.left=M.replace(`${x}px`,`${f.x}px`),t.style.top=P.replace(`${y}px`,`${f.y}px`)}function E(){C(),u(c.current),p.writePersisted(e,m,c.current,o),window.removeEventListener("mousemove",v),window.removeEventListener("mouseup",E)}window.addEventListener("mousemove",v),window.addEventListener("mouseup",E)},[e,o]);return{pos:d,onHandleMouseDown:S}}let s=1e3;function W(e=!0){const[a,o]=i.useState(()=>(s+=1,s));i.useEffect(()=>{e&&(s+=1,o(s))},[e]);const d=i.useCallback(()=>{o(u=>u===s?u:(s+=1,s))},[]);return{zIndex:a,focus:d}}exports.CloseButton=L;exports.useDragWindow=z;exports.useWindowFocus=W;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx as E } from "react/jsx-runtime";
|
|
2
|
+
import { X as z } from "@phosphor-icons/react";
|
|
3
|
+
import { a as D, s as X } from "./index-CtZterPc.js";
|
|
4
|
+
import { useState as b, useRef as $, useEffect as g, useCallback as M } from "react";
|
|
5
|
+
import { readPersisted as R, writePersisted as h } from "@element-editor/core";
|
|
6
|
+
import { u as Y } from "./useAccentStyle-CPo2XqAn.js";
|
|
7
|
+
function Z({ onClick: e, label: a = "Close" }) {
|
|
8
|
+
return /* @__PURE__ */ E(
|
|
9
|
+
"button",
|
|
10
|
+
{
|
|
11
|
+
onMouseDown: (o) => o.stopPropagation(),
|
|
12
|
+
onClick: e,
|
|
13
|
+
"aria-label": a,
|
|
14
|
+
className: `flex ${D}`,
|
|
15
|
+
children: /* @__PURE__ */ E(z, { size: 16 })
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
const f = 1;
|
|
20
|
+
function H(e) {
|
|
21
|
+
return !!e && typeof e == "object" && typeof e.x == "number" && typeof e.y == "number";
|
|
22
|
+
}
|
|
23
|
+
function m(e) {
|
|
24
|
+
return {
|
|
25
|
+
x: Math.max(0, Math.min(window.innerWidth - 120, e.x)),
|
|
26
|
+
y: Math.max(0, Math.min(window.innerHeight - 60, e.y))
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function k(e, a) {
|
|
30
|
+
const o = Y(), [l, i] = b(() => {
|
|
31
|
+
const n = R(e, f, (r) => H(r) ? r : null, o);
|
|
32
|
+
return n ? m(n) : a;
|
|
33
|
+
}), u = $(l);
|
|
34
|
+
u.current = l, g(() => {
|
|
35
|
+
function n() {
|
|
36
|
+
i((r) => {
|
|
37
|
+
const c = m(r);
|
|
38
|
+
return c.x === r.x && c.y === r.y ? r : (h(e, f, c, o), c);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return window.addEventListener("resize", n), () => window.removeEventListener("resize", n);
|
|
42
|
+
}, [e, o]);
|
|
43
|
+
const C = M((n) => {
|
|
44
|
+
if (n.button !== 0) return;
|
|
45
|
+
n.preventDefault();
|
|
46
|
+
const r = n.clientX, c = n.clientY, d = u.current.x, w = u.current.y, L = X("grabbing");
|
|
47
|
+
let t = n.currentTarget;
|
|
48
|
+
for (; t && getComputedStyle(t).position !== "fixed"; ) t = t.parentElement;
|
|
49
|
+
const P = (t == null ? void 0 : t.style.left) ?? "", S = (t == null ? void 0 : t.style.top) ?? "";
|
|
50
|
+
function x(y) {
|
|
51
|
+
const p = m({ x: d + y.clientX - r, y: w + y.clientY - c });
|
|
52
|
+
if (u.current = p, !t) {
|
|
53
|
+
i(p);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
t.style.left = P.replace(`${d}px`, `${p.x}px`), t.style.top = S.replace(`${w}px`, `${p.y}px`);
|
|
57
|
+
}
|
|
58
|
+
function v() {
|
|
59
|
+
L(), i(u.current), h(e, f, u.current, o), window.removeEventListener("mousemove", x), window.removeEventListener("mouseup", v);
|
|
60
|
+
}
|
|
61
|
+
window.addEventListener("mousemove", x), window.addEventListener("mouseup", v);
|
|
62
|
+
}, [e, o]);
|
|
63
|
+
return { pos: l, onHandleMouseDown: C };
|
|
64
|
+
}
|
|
65
|
+
let s = 1e3;
|
|
66
|
+
function F(e = !0) {
|
|
67
|
+
const [a, o] = b(() => (s += 1, s));
|
|
68
|
+
g(() => {
|
|
69
|
+
e && (s += 1, o(s));
|
|
70
|
+
}, [e]);
|
|
71
|
+
const l = M(() => {
|
|
72
|
+
o((i) => i === s ? i : (s += 1, s));
|
|
73
|
+
}, []);
|
|
74
|
+
return { zIndex: a, focus: l };
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
Z as C,
|
|
78
|
+
F as a,
|
|
79
|
+
k as u
|
|
80
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Text (typed or pasted) as a boolean, or `null` when it isn't one ("maybe"). */
|
|
2
|
+
export declare function parseBooleanText(text: string): boolean | null;
|
|
3
|
+
/** Whether a stored boolean field value counts as on. Missing / unknown values are off. */
|
|
4
|
+
export declare function readBooleanValue(value: unknown): boolean;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Text (typed or pasted) as a boolean, or `null` when it isn't one ("maybe"). */
|
|
2
|
+
export declare function parseBooleanText(text: string): boolean | null;
|
|
3
|
+
/** Whether a stored boolean field value counts as on. Missing / unknown values are off. */
|
|
4
|
+
export declare function readBooleanValue(value: unknown): boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trigger a browser download of a GeoJSON text payload via a synthetic
|
|
3
|
+
* `<a download>` click. Centralises the Blob → object-URL → click → revoke
|
|
4
|
+
* dance so adapter-leaflet's `ref.exportAs('geojson')`, adapter-maplibre's
|
|
5
|
+
* `ref.exportAs('geojson')`, and `useGeoJSONExport.exportToFile()` all share
|
|
6
|
+
* one implementation.
|
|
7
|
+
*
|
|
8
|
+
* Returns the resolved filename and the byte size of the downloaded blob,
|
|
9
|
+
* so callers don't have to allocate a second Blob just to measure bytes.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: completion is not observable. The browser may show a "Save As" dialog
|
|
12
|
+
* the user can cancel; this function returns immediately regardless. Use
|
|
13
|
+
* {@link saveGeoJSONFile} when you need to know whether the user actually
|
|
14
|
+
* saved (e.g. to gate a success toast).
|
|
15
|
+
*/
|
|
16
|
+
export declare function triggerGeoJSONDownload(text: string, filename?: string): {
|
|
17
|
+
name: string;
|
|
18
|
+
bytes: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Same payload as {@link triggerGeoJSONDownload}, but uses the File System
|
|
22
|
+
* Access API (`showSaveFilePicker`) when available so the caller can `await`
|
|
23
|
+
* an actual save confirmation:
|
|
24
|
+
*
|
|
25
|
+
* const result = await saveGeoJSONFile(text)
|
|
26
|
+
* if (result) toast.success(`Exported ${result.name}`) // user saved
|
|
27
|
+
* // result === null → user cancelled, OR legacy fallback (we can't tell)
|
|
28
|
+
*
|
|
29
|
+
* Resolves with `{ name, bytes }` ONLY when we know the file was written
|
|
30
|
+
* to disk (Chromium with the API). Resolves with `null` when:
|
|
31
|
+
* - the user cancelled the picker (Chromium), or
|
|
32
|
+
* - the browser doesn't support the API (Firefox / Safari) — falls back
|
|
33
|
+
* to the legacy `<a download>` flow silently, returning `null` so callers
|
|
34
|
+
* don't show pre-mature "exported!" feedback for an action the user may
|
|
35
|
+
* have aborted in the OS Save dialog.
|
|
36
|
+
*
|
|
37
|
+
* Pattern intentional: a pre-mature success toast is worse than no toast.
|
|
38
|
+
*/
|
|
39
|
+
export declare function saveGeoJSONFile(text: string, filename?: string): Promise<{
|
|
40
|
+
name: string;
|
|
41
|
+
bytes: number;
|
|
42
|
+
} | null>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trigger a browser download of a GeoJSON text payload via a synthetic
|
|
3
|
+
* `<a download>` click. Centralises the Blob → object-URL → click → revoke
|
|
4
|
+
* dance so adapter-leaflet's `ref.exportAs('geojson')`, adapter-maplibre's
|
|
5
|
+
* `ref.exportAs('geojson')`, and `useGeoJSONExport.exportToFile()` all share
|
|
6
|
+
* one implementation.
|
|
7
|
+
*
|
|
8
|
+
* Returns the resolved filename and the byte size of the downloaded blob,
|
|
9
|
+
* so callers don't have to allocate a second Blob just to measure bytes.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: completion is not observable. The browser may show a "Save As" dialog
|
|
12
|
+
* the user can cancel; this function returns immediately regardless. Use
|
|
13
|
+
* {@link saveGeoJSONFile} when you need to know whether the user actually
|
|
14
|
+
* saved (e.g. to gate a success toast).
|
|
15
|
+
*/
|
|
16
|
+
export declare function triggerGeoJSONDownload(text: string, filename?: string): {
|
|
17
|
+
name: string;
|
|
18
|
+
bytes: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Same payload as {@link triggerGeoJSONDownload}, but uses the File System
|
|
22
|
+
* Access API (`showSaveFilePicker`) when available so the caller can `await`
|
|
23
|
+
* an actual save confirmation:
|
|
24
|
+
*
|
|
25
|
+
* const result = await saveGeoJSONFile(text)
|
|
26
|
+
* if (result) toast.success(`Exported ${result.name}`) // user saved
|
|
27
|
+
* // result === null → user cancelled, OR legacy fallback (we can't tell)
|
|
28
|
+
*
|
|
29
|
+
* Resolves with `{ name, bytes }` ONLY when we know the file was written
|
|
30
|
+
* to disk (Chromium with the API). Resolves with `null` when:
|
|
31
|
+
* - the user cancelled the picker (Chromium), or
|
|
32
|
+
* - the browser doesn't support the API (Firefox / Safari) — falls back
|
|
33
|
+
* to the legacy `<a download>` flow silently, returning `null` so callers
|
|
34
|
+
* don't show pre-mature "exported!" feedback for an action the user may
|
|
35
|
+
* have aborted in the OS Save dialog.
|
|
36
|
+
*
|
|
37
|
+
* Pattern intentional: a pre-mature success toast is worse than no toast.
|
|
38
|
+
*/
|
|
39
|
+
export declare function saveGeoJSONFile(text: string, filename?: string): Promise<{
|
|
40
|
+
name: string;
|
|
41
|
+
bytes: number;
|
|
42
|
+
} | null>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { Text, ChangeSet, ChangeSpec } from '@codemirror/state';
|
|
2
|
+
import { GeoJSONFeature, Group, Schema } from '@element-editor/core';
|
|
3
|
+
/**
|
|
4
|
+
* The GeoJSON inspector's document, built feature by feature so it can be
|
|
5
|
+
* filled in slices and patched per feature. The text is byte-identical to
|
|
6
|
+
* `dataStore.exportGeoJSON()` (= `JSON.stringify(collection, null, 2)`):
|
|
7
|
+
* JSON.stringify indents by depth only, so a feature's text inside the
|
|
8
|
+
* collection is its own pretty JSON shifted right by 4 spaces.
|
|
9
|
+
*
|
|
10
|
+
* Layout (1-based lines): header (H lines, ends ` "features": [`)
|
|
11
|
+
* feature 0 … n-1 (every line but the last feature's
|
|
12
|
+
* closing ` }` carries a trailing `,`)
|
|
13
|
+
* ` ]`, `}`
|
|
14
|
+
* An empty collection is the header object as one block (`"features": []`).
|
|
15
|
+
*/
|
|
16
|
+
/** What the editor's document currently holds: one line count per feature, aligned with `features`. */
|
|
17
|
+
export interface DocMap {
|
|
18
|
+
features: readonly GeoJSONFeature[];
|
|
19
|
+
counts: number[];
|
|
20
|
+
headerLines: number;
|
|
21
|
+
schemas: Schema[];
|
|
22
|
+
groups: Group[];
|
|
23
|
+
}
|
|
24
|
+
export type LinesOf = (f: GeoJSONFeature) => string[];
|
|
25
|
+
/** A feature's lines, indented as they appear inside the collection (no trailing comma). */
|
|
26
|
+
export declare function featureLines(f: GeoJSONFeature): string[];
|
|
27
|
+
/** The header lines; for an empty collection, the whole document. */
|
|
28
|
+
export declare function headerLines(schemas: Schema[], groups: Group[], empty: boolean): string[];
|
|
29
|
+
/** Whole document as lines + its map. */
|
|
30
|
+
export declare function buildDoc(features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): {
|
|
31
|
+
text: Text;
|
|
32
|
+
map: DocMap;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* buildDoc's lines in pieces — the header, one piece per feature (separator
|
|
36
|
+
* comma included), the footer — so a large document can be serialised and
|
|
37
|
+
* shown slice by slice. Concatenated, the pieces are exactly buildDoc's lines.
|
|
38
|
+
*/
|
|
39
|
+
export declare function docPieces(features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): Generator<string[]>;
|
|
40
|
+
/** The map for a document that docPieces / buildDoc produced. */
|
|
41
|
+
export declare function docMapOf(features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): DocMap;
|
|
42
|
+
/** Line number (1-based) of each feature's first line. */
|
|
43
|
+
export declare function featureStartLines(map: DocMap): number[];
|
|
44
|
+
/** Index of the feature whose lines include `line` (1-based), or -1 (header, separators, footer). */
|
|
45
|
+
export declare function featureIndexAtLine(map: DocMap, line: number): number;
|
|
46
|
+
/**
|
|
47
|
+
* Changes that turn `doc` (described by `map`) into the document for the new
|
|
48
|
+
* state, touching only features whose object reference changed, plus the
|
|
49
|
+
* header when schemas/groups changed. Returns null when it must be rebuilt
|
|
50
|
+
* (empty ↔ non-empty).
|
|
51
|
+
*/
|
|
52
|
+
export declare function diffDoc(doc: Text, map: DocMap, features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): {
|
|
53
|
+
changes: ChangeSpec[];
|
|
54
|
+
map: DocMap;
|
|
55
|
+
} | null;
|
|
56
|
+
export type EditResult =
|
|
57
|
+
/** An edit touches the header or the footer: parse the whole document. */
|
|
58
|
+
{
|
|
59
|
+
kind: 'full';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The edited features' text doesn't parse (mid-typing): write nothing, wait
|
|
63
|
+
* for more typing. `from`…`to` is the first failing run's text in the new
|
|
64
|
+
* document (features only, no outer separators), for locating the error.
|
|
65
|
+
*/
|
|
66
|
+
| {
|
|
67
|
+
kind: 'invalid';
|
|
68
|
+
from: number;
|
|
69
|
+
to: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The new feature list: edited features re-parsed (deleted ones gone), every
|
|
73
|
+
* other one the same object. `counts` is the updated map's line counts, or
|
|
74
|
+
* null when an edit split one feature into several (the map no longer
|
|
75
|
+
* applies until `canonicalRuns` rewrites the text). `around` lists the new
|
|
76
|
+
* indices next to each edit, for `separatorFixes` to check. `runs` are the
|
|
77
|
+
* re-parsed feature runs: old indices `i`…`j` (inclusive, ascending), now
|
|
78
|
+
* `length` features.
|
|
79
|
+
*/
|
|
80
|
+
| {
|
|
81
|
+
kind: 'ok';
|
|
82
|
+
features: unknown[];
|
|
83
|
+
counts: number[] | null;
|
|
84
|
+
around: number[];
|
|
85
|
+
runs: EditRun[];
|
|
86
|
+
};
|
|
87
|
+
export interface EditRun {
|
|
88
|
+
i: number;
|
|
89
|
+
j: number;
|
|
90
|
+
length: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Whether parsed text is a feature the store takes — mirrors the guard in
|
|
94
|
+
* core's `updateFeaturesFromEditor`, so half-typed text (geometry lines
|
|
95
|
+
* deleted to retype them) reads as mid-typing instead of being refused.
|
|
96
|
+
*/
|
|
97
|
+
export declare function isFeature(f: unknown): boolean;
|
|
98
|
+
/** Why parsed text isn't a feature the store takes, in plain words (for a value `isFeature` refuses). */
|
|
99
|
+
export declare function featureIssue(f: unknown): string;
|
|
100
|
+
/**
|
|
101
|
+
* Where `text` stops being JSON as `parseLenient` reads it (the same stray
|
|
102
|
+
* commas forgiven), with the reason in plain words; null when it parses.
|
|
103
|
+
* `JSON.parse` can't tell: its message carries a position in some engines
|
|
104
|
+
* only (Safari gives none), in its own wording.
|
|
105
|
+
*/
|
|
106
|
+
export declare function jsonError(text: string): {
|
|
107
|
+
pos: number;
|
|
108
|
+
message: string;
|
|
109
|
+
} | null;
|
|
110
|
+
/**
|
|
111
|
+
* Re-parses only the features the user's edits touched. `base` is the
|
|
112
|
+
* document `map` describes, `changes` the user's edits since (base → `doc`).
|
|
113
|
+
* An edit inside one feature re-parses that feature; one spanning several
|
|
114
|
+
* (deleting whole features, or the separator between two) re-parses the run
|
|
115
|
+
* from the first to the last, as `[text]` read leniently — empty when they
|
|
116
|
+
* were all deleted. Commas left over between features are `separatorFixes`'
|
|
117
|
+
* business.
|
|
118
|
+
*/
|
|
119
|
+
export declare function parseEdits(base: Text, map: DocMap, changes: ChangeSet, doc: Text): EditResult;
|
|
120
|
+
/** The smallest single change turning `a` into `b` (common prefix and suffix kept), offset by `at`; null when equal. */
|
|
121
|
+
export declare function smallestChange(a: string, b: string, at?: number): {
|
|
122
|
+
from: number;
|
|
123
|
+
to: number;
|
|
124
|
+
insert: string;
|
|
125
|
+
} | null;
|
|
126
|
+
/**
|
|
127
|
+
* Rewrites the runs `parseEdits` re-parsed as buildDoc prints them, so the
|
|
128
|
+
* per-feature map applies again whatever the user's text looked like (one
|
|
129
|
+
* feature split into several, a pasted feature on one line, …). `features` is
|
|
130
|
+
* the committed list, aligned with the parse (the store may have added ids or
|
|
131
|
+
* empty properties). Each run's region runs from the end of the feature before
|
|
132
|
+
* it (or the header) to the start of the one after it (or the footer), so the
|
|
133
|
+
* separators are rewritten too; adjacent runs share one region. The changes
|
|
134
|
+
* apply to `doc` (= `changes` applied to `base`) and are each the smallest
|
|
135
|
+
* replacement, so text already in shape — say a feature copied from the
|
|
136
|
+
* inspector — is left alone. Returns them with the map's new line counts.
|
|
137
|
+
*/
|
|
138
|
+
export declare function canonicalRuns(base: Text, map: DocMap, changes: ChangeSet, doc: Text, runs: readonly EditRun[], features: readonly GeoJSONFeature[], linesOf: LinesOf): {
|
|
139
|
+
changes: ChangeSpec[];
|
|
140
|
+
counts: number[];
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Checks that the features at `around` sit in `doc` exactly where `counts`
|
|
144
|
+
* says, in buildDoc's shape (` {` … ` },`, the last one ` }` before
|
|
145
|
+
* ` ]`). Returns the edits that restore it — only ever dropping the comma a
|
|
146
|
+
* deleted last feature leaves on the new last one — or null when the text is
|
|
147
|
+
* otherwise off (the caller then parses the whole document).
|
|
148
|
+
*/
|
|
149
|
+
export declare function separatorFixes(doc: Text, headerLines: number, counts: readonly number[], around: Iterable<number>): ChangeSpec[] | null;
|
|
150
|
+
/** Whether two change sets over the same document touch overlapping (or adjacent) ranges. */
|
|
151
|
+
export declare function changesOverlap(a: ChangeSet, b: ChangeSet): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Feature line ranges found by scanning the document, for when the user has
|
|
154
|
+
* typed into it and the map no longer applies. A feature starts at a line that
|
|
155
|
+
* is exactly ` {`; stops once feature `index` is found. Counting starts
|
|
156
|
+
* at `fromLine`.
|
|
157
|
+
*/
|
|
158
|
+
export declare function scanFeatureRange(doc: Text, index: number, fromLine?: number): {
|
|
159
|
+
start: number;
|
|
160
|
+
end: number;
|
|
161
|
+
} | null;
|
|
162
|
+
/**
|
|
163
|
+
* Parses the inspector's text, forgiving what deleting whole lines leaves
|
|
164
|
+
* behind: an empty document (an empty collection) and stray commas — trailing
|
|
165
|
+
* (`},\n ]`), leading (`[,`) or doubled (`},,{`). Commas inside strings are
|
|
166
|
+
* left alone. Null when it still isn't JSON.
|
|
167
|
+
*/
|
|
168
|
+
export declare function parseLenient(text: string): unknown;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { Text, ChangeSet, ChangeSpec } from '@codemirror/state';
|
|
2
|
+
import { GeoJSONFeature, Group, Schema } from '@element-editor/core';
|
|
3
|
+
/**
|
|
4
|
+
* The GeoJSON inspector's document, built feature by feature so it can be
|
|
5
|
+
* filled in slices and patched per feature. The text is byte-identical to
|
|
6
|
+
* `dataStore.exportGeoJSON()` (= `JSON.stringify(collection, null, 2)`):
|
|
7
|
+
* JSON.stringify indents by depth only, so a feature's text inside the
|
|
8
|
+
* collection is its own pretty JSON shifted right by 4 spaces.
|
|
9
|
+
*
|
|
10
|
+
* Layout (1-based lines): header (H lines, ends ` "features": [`)
|
|
11
|
+
* feature 0 … n-1 (every line but the last feature's
|
|
12
|
+
* closing ` }` carries a trailing `,`)
|
|
13
|
+
* ` ]`, `}`
|
|
14
|
+
* An empty collection is the header object as one block (`"features": []`).
|
|
15
|
+
*/
|
|
16
|
+
/** What the editor's document currently holds: one line count per feature, aligned with `features`. */
|
|
17
|
+
export interface DocMap {
|
|
18
|
+
features: readonly GeoJSONFeature[];
|
|
19
|
+
counts: number[];
|
|
20
|
+
headerLines: number;
|
|
21
|
+
schemas: Schema[];
|
|
22
|
+
groups: Group[];
|
|
23
|
+
}
|
|
24
|
+
export type LinesOf = (f: GeoJSONFeature) => string[];
|
|
25
|
+
/** A feature's lines, indented as they appear inside the collection (no trailing comma). */
|
|
26
|
+
export declare function featureLines(f: GeoJSONFeature): string[];
|
|
27
|
+
/** The header lines; for an empty collection, the whole document. */
|
|
28
|
+
export declare function headerLines(schemas: Schema[], groups: Group[], empty: boolean): string[];
|
|
29
|
+
/** Whole document as lines + its map. */
|
|
30
|
+
export declare function buildDoc(features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): {
|
|
31
|
+
text: Text;
|
|
32
|
+
map: DocMap;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* buildDoc's lines in pieces — the header, one piece per feature (separator
|
|
36
|
+
* comma included), the footer — so a large document can be serialised and
|
|
37
|
+
* shown slice by slice. Concatenated, the pieces are exactly buildDoc's lines.
|
|
38
|
+
*/
|
|
39
|
+
export declare function docPieces(features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): Generator<string[]>;
|
|
40
|
+
/** The map for a document that docPieces / buildDoc produced. */
|
|
41
|
+
export declare function docMapOf(features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): DocMap;
|
|
42
|
+
/** Line number (1-based) of each feature's first line. */
|
|
43
|
+
export declare function featureStartLines(map: DocMap): number[];
|
|
44
|
+
/** Index of the feature whose lines include `line` (1-based), or -1 (header, separators, footer). */
|
|
45
|
+
export declare function featureIndexAtLine(map: DocMap, line: number): number;
|
|
46
|
+
/**
|
|
47
|
+
* Changes that turn `doc` (described by `map`) into the document for the new
|
|
48
|
+
* state, touching only features whose object reference changed, plus the
|
|
49
|
+
* header when schemas/groups changed. Returns null when it must be rebuilt
|
|
50
|
+
* (empty ↔ non-empty).
|
|
51
|
+
*/
|
|
52
|
+
export declare function diffDoc(doc: Text, map: DocMap, features: readonly GeoJSONFeature[], schemas: Schema[], groups: Group[], linesOf: LinesOf): {
|
|
53
|
+
changes: ChangeSpec[];
|
|
54
|
+
map: DocMap;
|
|
55
|
+
} | null;
|
|
56
|
+
export type EditResult =
|
|
57
|
+
/** An edit touches the header or the footer: parse the whole document. */
|
|
58
|
+
{
|
|
59
|
+
kind: 'full';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The edited features' text doesn't parse (mid-typing): write nothing, wait
|
|
63
|
+
* for more typing. `from`…`to` is the first failing run's text in the new
|
|
64
|
+
* document (features only, no outer separators), for locating the error.
|
|
65
|
+
*/
|
|
66
|
+
| {
|
|
67
|
+
kind: 'invalid';
|
|
68
|
+
from: number;
|
|
69
|
+
to: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The new feature list: edited features re-parsed (deleted ones gone), every
|
|
73
|
+
* other one the same object. `counts` is the updated map's line counts, or
|
|
74
|
+
* null when an edit split one feature into several (the map no longer
|
|
75
|
+
* applies until `canonicalRuns` rewrites the text). `around` lists the new
|
|
76
|
+
* indices next to each edit, for `separatorFixes` to check. `runs` are the
|
|
77
|
+
* re-parsed feature runs: old indices `i`…`j` (inclusive, ascending), now
|
|
78
|
+
* `length` features.
|
|
79
|
+
*/
|
|
80
|
+
| {
|
|
81
|
+
kind: 'ok';
|
|
82
|
+
features: unknown[];
|
|
83
|
+
counts: number[] | null;
|
|
84
|
+
around: number[];
|
|
85
|
+
runs: EditRun[];
|
|
86
|
+
};
|
|
87
|
+
export interface EditRun {
|
|
88
|
+
i: number;
|
|
89
|
+
j: number;
|
|
90
|
+
length: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Whether parsed text is a feature the store takes — mirrors the guard in
|
|
94
|
+
* core's `updateFeaturesFromEditor`, so half-typed text (geometry lines
|
|
95
|
+
* deleted to retype them) reads as mid-typing instead of being refused.
|
|
96
|
+
*/
|
|
97
|
+
export declare function isFeature(f: unknown): boolean;
|
|
98
|
+
/** Why parsed text isn't a feature the store takes, in plain words (for a value `isFeature` refuses). */
|
|
99
|
+
export declare function featureIssue(f: unknown): string;
|
|
100
|
+
/**
|
|
101
|
+
* Where `text` stops being JSON as `parseLenient` reads it (the same stray
|
|
102
|
+
* commas forgiven), with the reason in plain words; null when it parses.
|
|
103
|
+
* `JSON.parse` can't tell: its message carries a position in some engines
|
|
104
|
+
* only (Safari gives none), in its own wording.
|
|
105
|
+
*/
|
|
106
|
+
export declare function jsonError(text: string): {
|
|
107
|
+
pos: number;
|
|
108
|
+
message: string;
|
|
109
|
+
} | null;
|
|
110
|
+
/**
|
|
111
|
+
* Re-parses only the features the user's edits touched. `base` is the
|
|
112
|
+
* document `map` describes, `changes` the user's edits since (base → `doc`).
|
|
113
|
+
* An edit inside one feature re-parses that feature; one spanning several
|
|
114
|
+
* (deleting whole features, or the separator between two) re-parses the run
|
|
115
|
+
* from the first to the last, as `[text]` read leniently — empty when they
|
|
116
|
+
* were all deleted. Commas left over between features are `separatorFixes`'
|
|
117
|
+
* business.
|
|
118
|
+
*/
|
|
119
|
+
export declare function parseEdits(base: Text, map: DocMap, changes: ChangeSet, doc: Text): EditResult;
|
|
120
|
+
/** The smallest single change turning `a` into `b` (common prefix and suffix kept), offset by `at`; null when equal. */
|
|
121
|
+
export declare function smallestChange(a: string, b: string, at?: number): {
|
|
122
|
+
from: number;
|
|
123
|
+
to: number;
|
|
124
|
+
insert: string;
|
|
125
|
+
} | null;
|
|
126
|
+
/**
|
|
127
|
+
* Rewrites the runs `parseEdits` re-parsed as buildDoc prints them, so the
|
|
128
|
+
* per-feature map applies again whatever the user's text looked like (one
|
|
129
|
+
* feature split into several, a pasted feature on one line, …). `features` is
|
|
130
|
+
* the committed list, aligned with the parse (the store may have added ids or
|
|
131
|
+
* empty properties). Each run's region runs from the end of the feature before
|
|
132
|
+
* it (or the header) to the start of the one after it (or the footer), so the
|
|
133
|
+
* separators are rewritten too; adjacent runs share one region. The changes
|
|
134
|
+
* apply to `doc` (= `changes` applied to `base`) and are each the smallest
|
|
135
|
+
* replacement, so text already in shape — say a feature copied from the
|
|
136
|
+
* inspector — is left alone. Returns them with the map's new line counts.
|
|
137
|
+
*/
|
|
138
|
+
export declare function canonicalRuns(base: Text, map: DocMap, changes: ChangeSet, doc: Text, runs: readonly EditRun[], features: readonly GeoJSONFeature[], linesOf: LinesOf): {
|
|
139
|
+
changes: ChangeSpec[];
|
|
140
|
+
counts: number[];
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Checks that the features at `around` sit in `doc` exactly where `counts`
|
|
144
|
+
* says, in buildDoc's shape (` {` … ` },`, the last one ` }` before
|
|
145
|
+
* ` ]`). Returns the edits that restore it — only ever dropping the comma a
|
|
146
|
+
* deleted last feature leaves on the new last one — or null when the text is
|
|
147
|
+
* otherwise off (the caller then parses the whole document).
|
|
148
|
+
*/
|
|
149
|
+
export declare function separatorFixes(doc: Text, headerLines: number, counts: readonly number[], around: Iterable<number>): ChangeSpec[] | null;
|
|
150
|
+
/** Whether two change sets over the same document touch overlapping (or adjacent) ranges. */
|
|
151
|
+
export declare function changesOverlap(a: ChangeSet, b: ChangeSet): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Feature line ranges found by scanning the document, for when the user has
|
|
154
|
+
* typed into it and the map no longer applies. A feature starts at a line that
|
|
155
|
+
* is exactly ` {`; stops once feature `index` is found. Counting starts
|
|
156
|
+
* at `fromLine`.
|
|
157
|
+
*/
|
|
158
|
+
export declare function scanFeatureRange(doc: Text, index: number, fromLine?: number): {
|
|
159
|
+
start: number;
|
|
160
|
+
end: number;
|
|
161
|
+
} | null;
|
|
162
|
+
/**
|
|
163
|
+
* Parses the inspector's text, forgiving what deleting whole lines leaves
|
|
164
|
+
* behind: an empty document (an empty collection) and stray commas — trailing
|
|
165
|
+
* (`},\n ]`), leading (`[,`) or doubled (`},,{`). Commas inside strings are
|
|
166
|
+
* left alone. Null when it still isn't JSON.
|
|
167
|
+
*/
|
|
168
|
+
export declare function parseLenient(text: string): unknown;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Geometry } from 'geojson';
|
|
2
|
+
import { GeometryWorkerRequest } from '@element-editor/core/internal';
|
|
3
|
+
export declare function runGeometryWorkerOperation(payload: GeometryWorkerRequest['payload'], { timeoutMs }?: {
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
}): Promise<Geometry>;
|
|
6
|
+
export declare function disposeGeometryWorker(): void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Geometry } from 'geojson';
|
|
2
|
+
import { GeometryWorkerRequest } from '@element-editor/core/internal';
|
|
3
|
+
export declare function runGeometryWorkerOperation(payload: GeometryWorkerRequest['payload'], { timeoutMs }?: {
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
}): Promise<Geometry>;
|
|
6
|
+
export declare function disposeGeometryWorker(): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GeoJSONFeature, Group } from '@element-editor/core';
|
|
2
|
+
/** Returns feature IDs in the visual order they appear in the layer list. */
|
|
3
|
+
export declare function getVisualFeatureOrder(features: GeoJSONFeature[], groups: Group[]): string[];
|
|
4
|
+
/**
|
|
5
|
+
* Like `getVisualFeatureOrder` but skips features inside collapsed groups
|
|
6
|
+
* (they aren't rendered, so they shouldn't receive keyboard focus when tabbing
|
|
7
|
+
* through inline rename inputs).
|
|
8
|
+
*/
|
|
9
|
+
export declare function getTabbableFeatureIds(features: GeoJSONFeature[], groups: Group[]): string[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GeoJSONFeature, Group } from '@element-editor/core';
|
|
2
|
+
/** Returns feature IDs in the visual order they appear in the layer list. */
|
|
3
|
+
export declare function getVisualFeatureOrder(features: GeoJSONFeature[], groups: Group[]): string[];
|
|
4
|
+
/**
|
|
5
|
+
* Like `getVisualFeatureOrder` but skips features inside collapsed groups
|
|
6
|
+
* (they aren't rendered, so they shouldn't receive keyboard focus when tabbing
|
|
7
|
+
* through inline rename inputs).
|
|
8
|
+
*/
|
|
9
|
+
export declare function getTabbableFeatureIds(features: GeoJSONFeature[], groups: Group[]): string[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
type Loader<T extends ComponentType<any>> = () => Promise<{
|
|
3
|
+
default: T;
|
|
4
|
+
}>;
|
|
5
|
+
/**
|
|
6
|
+
* `React.lazy` plus `.preload()` — start fetching the chunk before first render.
|
|
7
|
+
* Once the chunk is in, it renders the component directly: React.lazy would
|
|
8
|
+
* still suspend on its first render (the resolved promise is only read a
|
|
9
|
+
* microtask later), and React 19 holds back revealing a suspended boundary's
|
|
10
|
+
* content for ~300 ms — the GeoJSON inspector opened ~280 ms late because of it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function lazyWithPreload<T extends ComponentType<any>>(load: Loader<T>): T & {
|
|
13
|
+
preload: () => Promise<unknown>;
|
|
14
|
+
};
|
|
15
|
+
export declare function registerPreload(...items: Array<{
|
|
16
|
+
preload: () => Promise<unknown>;
|
|
17
|
+
}>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Fetch every lazy editor panel (GeoJSON inspector, data table, modals…) once
|
|
20
|
+
* the browser is idle, so their first open is instant instead of waiting on a
|
|
21
|
+
* chunk download. Idle-time only: never competes with the initial render.
|
|
22
|
+
*/
|
|
23
|
+
export declare function preloadEditorPanelsWhenIdle(): void;
|
|
24
|
+
export {};
|