@honua/app-platform 0.1.2-beta.0 → 0.1.7-beta.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/app/index.d.ts.map +1 -1
- package/app/index.js +4 -0
- package/collaboration/client.d.ts.map +1 -1
- package/connect-url-safety.d.ts +53 -0
- package/connect-url-safety.js +189 -0
- package/contract/discovery.d.ts +34 -0
- package/contract/discovery.d.ts.map +1 -1
- package/contract/index.d.ts +7 -5
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +3 -2
- package/contract/pmtiles.d.ts +10 -1
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +10 -2
- package/contract/protocol-module.d.ts +84 -9
- package/contract/protocol-module.d.ts.map +1 -1
- package/contract/query-filter-fes.d.ts +18 -0
- package/contract/query-filter-fes.d.ts.map +1 -0
- package/contract/query-filter-fes.js +122 -0
- package/contract/query-filter.d.ts +300 -0
- package/contract/query-filter.d.ts.map +1 -0
- package/contract/query-filter.js +883 -0
- package/contract/schema.d.ts +12 -0
- package/contract/schema.d.ts.map +1 -1
- package/contract/schema.js +34 -0
- package/contract/source-capability-support.d.ts.map +1 -1
- package/contract/source-capability-support.js +15 -3
- package/contract/source.d.ts +45 -25
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +719 -479
- package/contract/types.d.ts +88 -19
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +4 -0
- package/contract/widget-source.d.ts.map +1 -1
- package/controls/basemap-switcher.d.ts +19 -11
- package/controls/basemap-switcher.d.ts.map +1 -1
- package/controls/basemap-switcher.js +58 -25
- package/controls/catalog.d.ts +105 -0
- package/controls/catalog.d.ts.map +1 -0
- package/controls/catalog.js +341 -0
- package/controls/element-utils.d.ts +9 -0
- package/controls/element-utils.d.ts.map +1 -1
- package/controls/element-utils.js +17 -0
- package/controls/index.d.ts +29 -8
- package/controls/index.d.ts.map +1 -1
- package/controls/index.js +26 -8
- package/controls/layer-list.d.ts +13 -5
- package/controls/layer-list.d.ts.map +1 -1
- package/controls/layer-list.js +72 -15
- package/controls/legend.d.ts +32 -5
- package/controls/legend.d.ts.map +1 -1
- package/controls/legend.js +95 -25
- package/controls/qualification.d.ts +152 -0
- package/controls/qualification.d.ts.map +1 -0
- package/controls/qualification.js +1265 -0
- package/controls/registry.d.ts +104 -0
- package/controls/registry.d.ts.map +1 -0
- package/controls/registry.js +150 -0
- package/controls/swipe-control.d.ts +6 -1
- package/controls/swipe-control.d.ts.map +1 -1
- package/controls/swipe-control.js +82 -20
- package/core/client.d.ts +51 -21
- package/core/client.d.ts.map +1 -1
- package/core/client.js +234 -54
- package/core/error-classifications.d.ts +23 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +23 -0
- package/core/error-code-registry.d.ts +24 -1
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +23 -0
- package/core/error-envelope.js +2 -0
- package/core/errors.d.ts +2 -2
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +1 -1
- package/core/geoparquet-sql.d.ts +69 -5
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +327 -10
- package/core/odata-write-codec.d.ts.map +1 -1
- package/core/odata-write-codec.js +0 -1
- package/core/odata.d.ts +6 -0
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +6 -1
- package/core/ogc-processes.d.ts +182 -25
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +602 -30
- package/core/process-runner.d.ts +8 -1
- package/core/process-runner.d.ts.map +1 -1
- package/core/process-runner.js +1 -0
- package/core/protocol-transport.d.ts +2 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/stac.d.ts +32 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +158 -23
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +273 -68
- package/core/types.d.ts +138 -11
- package/core/types.d.ts.map +1 -1
- package/core/wfs-axis-order.d.ts +18 -0
- package/core/wfs-axis-order.d.ts.map +1 -0
- package/core/wfs-axis-order.js +108 -0
- package/core/wfs-capabilities.d.ts +65 -24
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +237 -27
- package/core/wfs-filter.d.ts +26 -3
- package/core/wfs-filter.d.ts.map +1 -1
- package/core/wfs-filter.js +48 -53
- package/core/wfs-protocol-error.d.ts +12 -0
- package/core/wfs-protocol-error.d.ts.map +1 -0
- package/core/wfs-protocol-error.js +13 -0
- package/core/wfs.d.ts +53 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +251 -29
- package/core/wms-feature-info.d.ts +92 -0
- package/core/wms-feature-info.d.ts.map +1 -0
- package/core/wms-feature-info.js +285 -0
- package/core/wms.d.ts +9 -0
- package/core/wms.d.ts.map +1 -1
- package/core/wms.js +17 -5
- package/esri-compat/event-bus.d.ts +20 -0
- package/esri-compat/event-bus.d.ts.map +1 -1
- package/esri-compat/feature-filter.d.ts +46 -1
- package/esri-compat/feature-filter.d.ts.map +1 -1
- package/esri-compat/feature-filter.js +49 -0
- package/esri-compat/geojson-layer.d.ts +4 -2
- package/esri-compat/geojson-layer.d.ts.map +1 -1
- package/esri-compat/geojson-layer.js +4 -2
- package/esri-compat/identity-manager.js +2 -2
- package/esri-compat/imagery-layer.d.ts +2 -1
- package/esri-compat/imagery-layer.d.ts.map +1 -1
- package/esri-compat/imagery-layer.js +2 -1
- package/esri-compat/layer-list.d.ts +8 -1
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +11 -4
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +1 -1
- package/esri-compat/locator.d.ts +297 -0
- package/esri-compat/locator.d.ts.map +1 -0
- package/esri-compat/locator.js +579 -0
- package/esri-compat/map-image-layer.d.ts.map +1 -1
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +1 -1
- package/esri-compat/scene-view.d.ts.map +1 -1
- package/esri-compat/time-slider.d.ts +29 -0
- package/esri-compat/time-slider.d.ts.map +1 -1
- package/esri-compat/time-slider.js +117 -0
- package/esri-compat/wfs-layer.d.ts +2 -1
- package/esri-compat/wfs-layer.d.ts.map +1 -1
- package/esri-compat/wfs-layer.js +2 -1
- package/esri-compat/widget-host.d.ts +42 -6
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +99 -10
- package/generated-app/projection.d.ts.map +1 -1
- package/generated-app/runtime.d.ts.map +1 -1
- package/interactions/declarative-contract.d.ts +149 -0
- package/interactions/declarative-contract.d.ts.map +1 -0
- package/interactions/declarative-contract.js +293 -0
- package/interactions/declarative.d.ts +198 -0
- package/interactions/declarative.d.ts.map +1 -0
- package/interactions/declarative.js +470 -0
- package/interactions/feature-state.d.ts +7 -0
- package/interactions/feature-state.d.ts.map +1 -1
- package/interactions/feature-state.js +10 -2
- package/map/data-to-map-bridge.d.ts +1 -1
- package/map/data-to-map-bridge.d.ts.map +1 -1
- package/map/data-to-map-bridge.js +1 -2
- package/map/honua-map.d.ts.map +1 -1
- package/map/honua-map.js +1 -1
- package/map/index.d.ts +2 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +2 -0
- package/map/maplibre-target.js +1 -1
- package/map/realtime-reconciliation-adapter.d.ts +98 -0
- package/map/realtime-reconciliation-adapter.d.ts.map +1 -0
- package/map/realtime-reconciliation-adapter.js +84 -0
- package/map/temporal-playback.d.ts +25 -0
- package/map/temporal-playback.d.ts.map +1 -1
- package/map/temporal-playback.js +29 -1
- package/operator/workspace/workspace.d.ts.map +1 -1
- package/operator/workspace/workspace.js +0 -2
- package/package.json +4 -3
- package/query-planner/canonical-filter.d.ts +30 -0
- package/query-planner/canonical-filter.d.ts.map +1 -0
- package/query-planner/canonical-filter.js +30 -0
- package/query-planner/columnar-plan.d.ts +63 -0
- package/query-planner/columnar-plan.d.ts.map +1 -0
- package/query-planner/columnar-plan.js +94 -0
- package/query-planner/diagnostics.d.ts +3 -3
- package/query-planner/diagnostics.d.ts.map +1 -1
- package/query-planner/diagnostics.js +17 -4
- package/query-planner/duckdb.d.ts.map +1 -1
- package/query-planner/duckdb.js +16 -2
- package/query-planner/execution-context.d.ts.map +1 -1
- package/query-planner/execution-context.js +3 -1
- package/query-planner/executor.d.ts.map +1 -1
- package/query-planner/executor.js +7 -1
- package/query-planner/geoservices.d.ts.map +1 -1
- package/query-planner/geoservices.js +24 -5
- package/query-planner/grpc.d.ts.map +1 -1
- package/query-planner/grpc.js +29 -5
- package/query-planner/index.d.ts +20 -5
- package/query-planner/index.d.ts.map +1 -1
- package/query-planner/index.js +16 -3
- package/query-planner/ir.d.ts +6 -1
- package/query-planner/ir.d.ts.map +1 -1
- package/query-planner/ir.js +63 -1
- package/query-planner/odata-protocol-module.d.ts +54 -0
- package/query-planner/odata-protocol-module.d.ts.map +1 -0
- package/query-planner/odata-protocol-module.js +199 -0
- package/query-planner/odata-v1.d.ts +23 -0
- package/query-planner/odata-v1.d.ts.map +1 -0
- package/query-planner/odata-v1.js +202 -0
- package/query-planner/odata.d.ts +0 -3
- package/query-planner/odata.d.ts.map +1 -1
- package/query-planner/odata.js +0 -143
- package/query-planner/ogc-features.d.ts.map +1 -1
- package/query-planner/ogc-features.js +23 -1
- package/query-planner/planner.d.ts +2 -2
- package/query-planner/planner.d.ts.map +1 -1
- package/query-planner/planner.js +146 -27
- package/query-planner/representation.d.ts +59 -0
- package/query-planner/representation.d.ts.map +1 -0
- package/query-planner/representation.js +140 -0
- package/query-planner/types.d.ts +153 -3
- package/query-planner/types.d.ts.map +1 -1
- package/query-planner/wfs-protocol-module.d.ts +57 -0
- package/query-planner/wfs-protocol-module.d.ts.map +1 -0
- package/query-planner/wfs-protocol-module.js +731 -0
- package/query-planner/wfs-v1.d.ts +41 -0
- package/query-planner/wfs-v1.d.ts.map +1 -0
- package/query-planner/wfs-v1.js +366 -0
- package/query-planner/wfs.d.ts +1 -3
- package/query-planner/wfs.d.ts.map +1 -1
- package/query-planner/wfs.js +1 -70
- package/realtime/checkpoint-store.d.ts +206 -0
- package/realtime/checkpoint-store.d.ts.map +1 -0
- package/realtime/checkpoint-store.js +504 -0
- package/realtime/honua-server.d.ts +8 -0
- package/realtime/honua-server.d.ts.map +1 -1
- package/realtime/honua-server.js +123 -14
- package/realtime/index.d.ts +4 -0
- package/realtime/index.d.ts.map +1 -1
- package/realtime/index.js +2 -0
- package/realtime/reconciliation.d.ts +245 -0
- package/realtime/reconciliation.d.ts.map +1 -0
- package/realtime/reconciliation.js +377 -0
- package/realtime/resumable-transport.d.ts.map +1 -1
- package/realtime/sse.d.ts.map +1 -1
- package/realtime/sse.js +7 -1
- package/realtime/websocket.d.ts.map +1 -1
- package/realtime/wire.d.ts +2 -1
- package/realtime/wire.d.ts.map +1 -1
- package/realtime/wire.js +24 -8
- package/replica-sync/errors.d.ts +19 -1
- package/replica-sync/errors.d.ts.map +1 -1
- package/replica-sync/errors.js +16 -0
- package/replica-sync/geoservices.d.ts +260 -0
- package/replica-sync/geoservices.d.ts.map +1 -0
- package/replica-sync/geoservices.js +1093 -0
- package/replica-sync/index.d.ts +5 -1
- package/replica-sync/index.d.ts.map +1 -1
- package/replica-sync/index.js +3 -1
- package/replica-sync/transport-conformance.d.ts +58 -0
- package/replica-sync/transport-conformance.d.ts.map +1 -0
- package/replica-sync/transport-conformance.js +265 -0
- package/replica-sync/types.d.ts +22 -0
- package/replica-sync/types.d.ts.map +1 -1
- package/runtime/index.d.ts +6 -2
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -1
- package/runtime/load-package.d.ts +24 -0
- package/runtime/load-package.d.ts.map +1 -1
- package/runtime/load-package.js +45 -1
- package/runtime/maplibre-renderer.d.ts +11 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -1
- package/runtime/maplibre-renderer.js +32 -7
- package/runtime/offline-region-protocol.d.ts +73 -0
- package/runtime/offline-region-protocol.d.ts.map +1 -0
- package/runtime/offline-region-protocol.js +63 -0
- package/runtime/offline-region-style.d.ts +78 -0
- package/runtime/offline-region-style.d.ts.map +1 -0
- package/runtime/offline-region-style.js +147 -0
- package/runtime/pmtiles-protocol.d.ts +7 -8
- package/runtime/pmtiles-protocol.d.ts.map +1 -1
- package/runtime/pmtiles-protocol.js +19 -66
- package/runtime/protocol-registry.d.ts +55 -0
- package/runtime/protocol-registry.d.ts.map +1 -0
- package/runtime/protocol-registry.js +103 -0
- package/runtime/runtime.d.ts +2 -0
- package/runtime/runtime.d.ts.map +1 -1
- package/runtime/runtime.js +6 -1
- package/runtime/style-compose.d.ts.map +1 -1
- package/runtime/style-compose.js +78 -9
- package/scene-workspace/analysis-widgets.d.ts +4 -2
- package/scene-workspace/analysis-widgets.d.ts.map +1 -1
- package/scene-workspace/analysis-widgets.js +4 -2
- package/scene-workspace/camera-correspondence.d.ts +151 -0
- package/scene-workspace/camera-correspondence.d.ts.map +1 -0
- package/scene-workspace/camera-correspondence.js +220 -0
- package/scene-workspace/cesium-adapter.d.ts +230 -29
- package/scene-workspace/cesium-adapter.d.ts.map +1 -1
- package/scene-workspace/cesium-adapter.js +741 -56
- package/scene-workspace/cesium-mount.d.ts +205 -0
- package/scene-workspace/cesium-mount.d.ts.map +1 -0
- package/scene-workspace/cesium-mount.js +392 -0
- package/scene-workspace/cesium-scene-owner.d.ts +160 -0
- package/scene-workspace/cesium-scene-owner.d.ts.map +1 -0
- package/scene-workspace/cesium-scene-owner.js +205 -0
- package/scene-workspace/cesium-state-sync.d.ts +101 -0
- package/scene-workspace/cesium-state-sync.d.ts.map +1 -0
- package/scene-workspace/cesium-state-sync.js +432 -0
- package/scene-workspace/cesium-time.d.ts +346 -0
- package/scene-workspace/cesium-time.d.ts.map +1 -0
- package/scene-workspace/cesium-time.js +403 -0
- package/scene-workspace/index.d.ts +42 -10
- package/scene-workspace/index.d.ts.map +1 -1
- package/scene-workspace/index.js +32 -7
- package/scene-workspace/maplibre-state-sync.d.ts +112 -0
- package/scene-workspace/maplibre-state-sync.d.ts.map +1 -0
- package/scene-workspace/maplibre-state-sync.js +400 -0
- package/scene-workspace/primitives.d.ts +237 -3
- package/scene-workspace/primitives.d.ts.map +1 -1
- package/scene-workspace/primitives.js +1087 -17
- package/scene-workspace/scene-discovery.d.ts +5 -2
- package/scene-workspace/scene-discovery.d.ts.map +1 -1
- package/scene-workspace/scene-discovery.js +5 -2
- package/scene-workspace/scene-view.d.ts +5 -2
- package/scene-workspace/scene-view.d.ts.map +1 -1
- package/scene-workspace/scene-view.js +5 -2
- package/scene-workspace/source-to-cesium.d.ts +141 -8
- package/scene-workspace/source-to-cesium.d.ts.map +1 -1
- package/scene-workspace/source-to-cesium.js +497 -72
- package/scene-workspace/state-sync-port-kit.d.ts +156 -0
- package/scene-workspace/state-sync-port-kit.d.ts.map +1 -0
- package/scene-workspace/state-sync-port-kit.js +319 -0
- package/scene-workspace/state-sync.d.ts +34 -1
- package/scene-workspace/state-sync.d.ts.map +1 -1
- package/scene-workspace/state-sync.js +48 -0
- package/scene-workspace/types.d.ts +8 -0
- package/scene-workspace/types.d.ts.map +1 -1
- package/scene-workspace/types.js +2 -0
- package/scene-workspace/workspace.d.ts +12 -1
- package/scene-workspace/workspace.d.ts.map +1 -1
- package/scene-workspace/workspace.js +13 -0
- package/studio/index.d.ts +24 -7
- package/studio/index.d.ts.map +1 -1
- package/studio/index.js +21 -7
- package/studio/lifecycle-client.d.ts +164 -0
- package/studio/lifecycle-client.d.ts.map +1 -0
- package/studio/lifecycle-client.js +299 -0
- package/studio/lifecycle-errors.d.ts +91 -0
- package/studio/lifecycle-errors.d.ts.map +1 -0
- package/studio/lifecycle-errors.js +77 -0
- package/studio/lifecycle-types.d.ts +321 -0
- package/studio/lifecycle-types.d.ts.map +1 -0
- package/studio/lifecycle-types.js +22 -0
- package/web-components/controller.d.ts.map +1 -1
- package/web-components/csp-styles.d.ts +6 -0
- package/web-components/csp-styles.d.ts.map +1 -0
- package/web-components/csp-styles.js +53 -0
- package/web-components/elements.d.ts +158 -2
- package/web-components/elements.d.ts.map +1 -1
- package/web-components/elements.js +1302 -215
- package/web-components/export-redaction.d.ts +252 -0
- package/web-components/export-redaction.d.ts.map +1 -0
- package/web-components/export-redaction.js +588 -0
- package/web-components/export.d.ts +417 -0
- package/web-components/export.d.ts.map +1 -0
- package/web-components/export.js +719 -0
- package/web-components/feature-editor-model.d.ts +265 -0
- package/web-components/feature-editor-model.d.ts.map +1 -0
- package/web-components/feature-editor-model.js +438 -0
- package/web-components/feature-editor-sketch.d.ts +125 -0
- package/web-components/feature-editor-sketch.d.ts.map +1 -0
- package/web-components/feature-editor-sketch.js +194 -0
- package/web-components/feature-editor-workflow.d.ts +286 -0
- package/web-components/feature-editor-workflow.d.ts.map +1 -0
- package/web-components/feature-editor-workflow.js +889 -0
- package/web-components/feature-editor.d.ts +83 -0
- package/web-components/feature-editor.d.ts.map +1 -0
- package/web-components/feature-editor.js +829 -0
- package/web-components/feature-table-engine.d.ts +465 -0
- package/web-components/feature-table-engine.d.ts.map +1 -0
- package/web-components/feature-table-engine.js +1360 -0
- package/web-components/feature-table-view.d.ts +95 -0
- package/web-components/feature-table-view.d.ts.map +1 -0
- package/web-components/feature-table-view.js +343 -0
- package/web-components/index.d.ts +34 -3
- package/web-components/index.d.ts.map +1 -1
- package/web-components/index.js +35 -2
- package/web-components/maplibre-renderer.d.ts.map +1 -1
- package/web-components/maplibre-renderer.js +13 -4
- package/web-components/measurement.d.ts +3 -1
- package/web-components/measurement.d.ts.map +1 -1
- package/web-components/measurement.js +62 -18
- package/web-components/time-slider.d.ts +122 -0
- package/web-components/time-slider.d.ts.map +1 -0
- package/web-components/time-slider.js +740 -0
- package/web-components/types.d.ts +310 -0
- package/web-components/types.d.ts.map +1 -1
- package/webmap/convert-label.js +0 -1
- package/webmap/convert-symbol.d.ts.map +1 -1
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM-free presentation model behind `<honua-feature-editor>` — the
|
|
3
|
+
* production-tier capability-aware editing surface (issue #680, parent epic
|
|
4
|
+
* #678).
|
|
5
|
+
*
|
|
6
|
+
* Everything here is a *derivation* over the public contract editing
|
|
7
|
+
* primitives (`EditWorkflowField` / `EditFieldDomain` /
|
|
8
|
+
* `EditWorkflowCapabilitySummary` / `EditWorkflowValidationResult` from
|
|
9
|
+
* `@honua/sdk-js/contract`) plus the public source descriptor. No protocol
|
|
10
|
+
* adapter is imported, no service field name is hard-coded, and no transport
|
|
11
|
+
* happens: this module turns metadata into renderable controls, turns raw
|
|
12
|
+
* control input back into typed attribute values, and answers "which
|
|
13
|
+
* operations are truthfully available right now, and why not".
|
|
14
|
+
*
|
|
15
|
+
* Three things the protocol layer deliberately does not model, derived here
|
|
16
|
+
* because they are presentation concerns:
|
|
17
|
+
*
|
|
18
|
+
* 1. **Coded-value / range domains from native schema.** The contract's
|
|
19
|
+
* `resolveEditWorkflowMetadata` carries `name`/`type`/`length`/`nullable`/
|
|
20
|
+
* `editable`/`defaultValue` across from `SourceSchema.fields` but not the
|
|
21
|
+
* native `domain` block. {@link editorFieldsFromSchema} closes that gap
|
|
22
|
+
* over a structural (adapter-free) field shape so the contract's own
|
|
23
|
+
* `validate()` rejects out-of-domain values *before* transport.
|
|
24
|
+
* 2. **Subtypes.** There is no subtype primitive in the contract. A subtype is
|
|
25
|
+
* modeled here as a coded-value domain on one field plus per-subtype field
|
|
26
|
+
* overrides ({@link HonuaEditorSubtypeConfig}); {@link resolveEditorFields}
|
|
27
|
+
* folds the active subtype's overrides into the field list handed to the
|
|
28
|
+
* edit session, so switching subtype changes the valid choices *and* what
|
|
29
|
+
* the contract validator accepts.
|
|
30
|
+
* 3. **Per-operation availability.** The contract exposes one coarse
|
|
31
|
+
* `applyEdits` capability. {@link resolveEditorOperations} splits it into
|
|
32
|
+
* truthful per-operation state, folding in the capability profile's
|
|
33
|
+
* `authorization-required` / `authorization-denied` / `policy-disabled`
|
|
34
|
+
* verdicts, structural facts (an update or delete needs a feature
|
|
35
|
+
* identity), and host-supplied per-operation denials. It only ever
|
|
36
|
+
* *narrows* — a host override can never grant an operation the source does
|
|
37
|
+
* not support (fail closed).
|
|
38
|
+
*
|
|
39
|
+
* @module
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* Projects public schema fields onto contract {@link EditWorkflowField}s,
|
|
43
|
+
* including the coded-value / range domain the contract's own schema
|
|
44
|
+
* projection drops. Feed the result to `createEditSession`/
|
|
45
|
+
* `createEditSketchWorkflow` as `metadata.fields` so domain violations fail
|
|
46
|
+
* validation before any transport happens (REQ-001).
|
|
47
|
+
*/
|
|
48
|
+
export function editorFieldsFromSchema(fields) {
|
|
49
|
+
return (fields ?? []).map((field) => {
|
|
50
|
+
const domain = editorDomainFromSchema(field.domain);
|
|
51
|
+
return {
|
|
52
|
+
name: field.name,
|
|
53
|
+
...(field.type !== undefined ? { type: field.type } : {}),
|
|
54
|
+
...(field.alias !== undefined ? { alias: field.alias } : {}),
|
|
55
|
+
...(field.length !== undefined ? { length: field.length } : {}),
|
|
56
|
+
...(field.nullable !== undefined ? { nullable: field.nullable } : {}),
|
|
57
|
+
...(field.editable !== undefined ? { editable: field.editable } : {}),
|
|
58
|
+
...(field.defaultValue !== undefined ? { defaultValue: field.defaultValue } : {}),
|
|
59
|
+
...(domain ? { domain } : {}),
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** Normalizes a native domain block to the contract's {@link EditFieldDomain}. */
|
|
64
|
+
export function editorDomainFromSchema(domain) {
|
|
65
|
+
if (!domain)
|
|
66
|
+
return undefined;
|
|
67
|
+
const type = (domain.type ?? "").toLowerCase();
|
|
68
|
+
if (type === "codedvalue" || type === "coded-value" || type === "coded_value" || domain.codedValues) {
|
|
69
|
+
const codedValues = (domain.codedValues ?? []).map((coded) => ({ name: coded.name ?? String(coded.code), code: coded.code }));
|
|
70
|
+
if (codedValues.length === 0)
|
|
71
|
+
return undefined;
|
|
72
|
+
return { type: "coded-value", ...(domain.name ? { name: domain.name } : {}), codedValues };
|
|
73
|
+
}
|
|
74
|
+
if (type === "range" || domain.range) {
|
|
75
|
+
const min = Number(domain.range?.[0]);
|
|
76
|
+
const max = Number(domain.range?.[1]);
|
|
77
|
+
if (!Number.isFinite(min) || !Number.isFinite(max))
|
|
78
|
+
return undefined;
|
|
79
|
+
return { type: "range", ...(domain.name ? { name: domain.name } : {}), range: [min, max] };
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
/** The subtype in effect for a set of attribute values, if any. */
|
|
84
|
+
export function resolveActiveEditorSubtype(config, values) {
|
|
85
|
+
if (!config)
|
|
86
|
+
return undefined;
|
|
87
|
+
const raw = values[config.field];
|
|
88
|
+
const code = raw === undefined || raw === null || raw === "" ? config.defaultCode : raw;
|
|
89
|
+
if (code === undefined)
|
|
90
|
+
return undefined;
|
|
91
|
+
return config.subtypes.find((subtype) => sameCode(subtype.code, code));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Folds subtype state into the field list handed to the edit session: the
|
|
95
|
+
* subtype field gains a coded-value domain built from the configured
|
|
96
|
+
* subtypes, and the active subtype's per-field overrides (domain, required,
|
|
97
|
+
* editable, default, hidden) are applied on top of the base metadata.
|
|
98
|
+
*
|
|
99
|
+
* Because the result is what `createEditSession`'s `metadata.fields` receives,
|
|
100
|
+
* a subtype change immediately changes both the rendered choices and what the
|
|
101
|
+
* contract validator accepts — an invalid combination is rejected before
|
|
102
|
+
* transport (REQ-001).
|
|
103
|
+
*/
|
|
104
|
+
export function resolveEditorFields(fields, config, values) {
|
|
105
|
+
if (!config)
|
|
106
|
+
return fields;
|
|
107
|
+
const active = resolveActiveEditorSubtype(config, values);
|
|
108
|
+
const subtypeDomain = {
|
|
109
|
+
type: "coded-value",
|
|
110
|
+
codedValues: config.subtypes.map((subtype) => ({ name: subtype.name, code: subtype.code })),
|
|
111
|
+
};
|
|
112
|
+
const known = new Set(fields.map((field) => field.name));
|
|
113
|
+
const resolved = fields.map((field) => {
|
|
114
|
+
const base = field.name === config.field ? { ...field, domain: subtypeDomain, required: true } : { ...field };
|
|
115
|
+
return applySubtypeOverride(base, active?.fieldOverrides?.[field.name]);
|
|
116
|
+
});
|
|
117
|
+
// A subtype field absent from the source schema still needs a control and a
|
|
118
|
+
// domain, otherwise a create draft could never pick a subtype at all.
|
|
119
|
+
if (!known.has(config.field)) {
|
|
120
|
+
resolved.unshift(applySubtypeOverride({ name: config.field, type: subtypeCodeType(config), domain: subtypeDomain, required: true }, active?.fieldOverrides?.[config.field]));
|
|
121
|
+
}
|
|
122
|
+
return resolved;
|
|
123
|
+
}
|
|
124
|
+
function applySubtypeOverride(field, override) {
|
|
125
|
+
if (!override)
|
|
126
|
+
return field;
|
|
127
|
+
const next = { ...field };
|
|
128
|
+
if (override.domain === null)
|
|
129
|
+
delete next.domain;
|
|
130
|
+
else if (override.domain !== undefined)
|
|
131
|
+
next.domain = override.domain;
|
|
132
|
+
if (override.editable !== undefined)
|
|
133
|
+
next.editable = override.editable;
|
|
134
|
+
if (override.defaultValue !== undefined)
|
|
135
|
+
next.defaultValue = override.defaultValue;
|
|
136
|
+
if (override.hidden === true) {
|
|
137
|
+
next.required = false;
|
|
138
|
+
next.nullable = true;
|
|
139
|
+
}
|
|
140
|
+
else if (override.required !== undefined) {
|
|
141
|
+
next.required = override.required;
|
|
142
|
+
}
|
|
143
|
+
return next;
|
|
144
|
+
}
|
|
145
|
+
function subtypeCodeType(config) {
|
|
146
|
+
return config.subtypes.every((subtype) => typeof subtype.code === "number") ? "integer" : "string";
|
|
147
|
+
}
|
|
148
|
+
/** Field names the active subtype hides from the form. */
|
|
149
|
+
export function hiddenEditorFieldNames(config, values) {
|
|
150
|
+
const active = resolveActiveEditorSubtype(config, values);
|
|
151
|
+
const hidden = new Set();
|
|
152
|
+
for (const [name, override] of Object.entries(active?.fieldOverrides ?? {})) {
|
|
153
|
+
if (override.hidden === true)
|
|
154
|
+
hidden.add(name);
|
|
155
|
+
}
|
|
156
|
+
return hidden;
|
|
157
|
+
}
|
|
158
|
+
const EDITOR_OPERATIONS = ["create", "update", "delete"];
|
|
159
|
+
/**
|
|
160
|
+
* Derives truthful per-operation availability. Precedence, most authoritative
|
|
161
|
+
* first: capability profile verdict → coarse `applyEdits` capability → host
|
|
162
|
+
* override → structural preconditions. Every layer can only deny.
|
|
163
|
+
*/
|
|
164
|
+
export function resolveEditorOperations(input) {
|
|
165
|
+
const gate = capabilityGate(input);
|
|
166
|
+
return EDITOR_OPERATIONS.map((operation) => {
|
|
167
|
+
if (gate)
|
|
168
|
+
return { operation, available: false, ...gate };
|
|
169
|
+
const override = normalizeOverride(input.overrides?.[operation]);
|
|
170
|
+
if (override && !override.available) {
|
|
171
|
+
return {
|
|
172
|
+
operation,
|
|
173
|
+
available: false,
|
|
174
|
+
code: "host-denied",
|
|
175
|
+
reason: override.reason ?? `The host disabled ${operation} for this source.`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (operation !== "create" && !input.hasFeatureIdentity) {
|
|
179
|
+
return {
|
|
180
|
+
operation,
|
|
181
|
+
available: false,
|
|
182
|
+
code: "no-feature-identity",
|
|
183
|
+
reason: `Select a feature with an identity to ${operation} it.`,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (operation !== "delete" && input.fields && input.fields.length > 0 && !hasEditableField(input.fields)) {
|
|
187
|
+
return {
|
|
188
|
+
operation,
|
|
189
|
+
available: false,
|
|
190
|
+
code: "no-editable-fields",
|
|
191
|
+
reason: "Every field in this source is read-only.",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return { operation, available: true };
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function capabilityGate(input) {
|
|
198
|
+
const decision = input.decisions?.find((entry) => entry.id === "applyEdits");
|
|
199
|
+
if (decision && decision.effective !== "supported") {
|
|
200
|
+
const code = UNAVAILABLE_BY_EFFECTIVE[decision.effective] ?? "capability-unknown";
|
|
201
|
+
const detail = decision.reasons && decision.reasons.length > 0 ? ` (${decision.reasons.join(", ")})` : "";
|
|
202
|
+
return { code, reason: `${EFFECTIVE_MESSAGE[code]}${detail}` };
|
|
203
|
+
}
|
|
204
|
+
if (input.capabilities.applyEdits !== "supported") {
|
|
205
|
+
return { code: "capability-unsupported", reason: EFFECTIVE_MESSAGE["capability-unsupported"] };
|
|
206
|
+
}
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
const UNAVAILABLE_BY_EFFECTIVE = {
|
|
210
|
+
unsupported: "capability-unsupported",
|
|
211
|
+
unknown: "capability-unknown",
|
|
212
|
+
"policy-disabled": "policy-disabled",
|
|
213
|
+
"peer-unavailable": "peer-unavailable",
|
|
214
|
+
"authorization-required": "authorization-required",
|
|
215
|
+
"authorization-denied": "authorization-denied",
|
|
216
|
+
};
|
|
217
|
+
const EFFECTIVE_MESSAGE = {
|
|
218
|
+
"capability-unsupported": "This source does not support editing.",
|
|
219
|
+
"capability-unknown": "Editing support for this source could not be established.",
|
|
220
|
+
"authorization-required": "Sign in with edit permission to edit this source.",
|
|
221
|
+
"authorization-denied": "Your account is not permitted to edit this source.",
|
|
222
|
+
"policy-disabled": "Editing is disabled for this source by policy.",
|
|
223
|
+
"peer-unavailable": "The service that applies edits is unavailable.",
|
|
224
|
+
"host-denied": "The host disabled this operation.",
|
|
225
|
+
"no-feature-identity": "Select a feature with an identity first.",
|
|
226
|
+
"no-editable-fields": "Every field in this source is read-only.",
|
|
227
|
+
};
|
|
228
|
+
function normalizeOverride(override) {
|
|
229
|
+
if (override === undefined)
|
|
230
|
+
return undefined;
|
|
231
|
+
if (typeof override === "boolean")
|
|
232
|
+
return { available: override };
|
|
233
|
+
return { available: override.available, ...(override.reason ? { reason: override.reason } : {}) };
|
|
234
|
+
}
|
|
235
|
+
function hasEditableField(fields) {
|
|
236
|
+
return fields.some((field) => field.editable !== false);
|
|
237
|
+
}
|
|
238
|
+
/** Looks one operation's availability up out of a resolved list. */
|
|
239
|
+
export function editorOperationAvailability(availability, operation) {
|
|
240
|
+
return (availability.find((entry) => entry.operation === operation) ?? {
|
|
241
|
+
operation,
|
|
242
|
+
available: false,
|
|
243
|
+
code: "capability-unknown",
|
|
244
|
+
reason: EFFECTIVE_MESSAGE["capability-unknown"],
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Builds the renderable form from resolved field metadata plus the contract's
|
|
249
|
+
* own validation result — no service field names, no protocol branching
|
|
250
|
+
* (REQ-001).
|
|
251
|
+
*/
|
|
252
|
+
export function buildEditorFormModel(input) {
|
|
253
|
+
const hidden = hiddenEditorFieldNames(input.subtypes, input.values);
|
|
254
|
+
const errorsByField = new Map();
|
|
255
|
+
const formErrors = [];
|
|
256
|
+
for (const error of input.validation.errors) {
|
|
257
|
+
if (error.fieldName === undefined) {
|
|
258
|
+
formErrors.push(error.message);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const bucket = errorsByField.get(error.fieldName) ?? [];
|
|
262
|
+
bucket.push(error.message);
|
|
263
|
+
errorsByField.set(error.fieldName, bucket);
|
|
264
|
+
}
|
|
265
|
+
const controls = input.fields
|
|
266
|
+
.filter((field) => !hidden.has(field.name))
|
|
267
|
+
.map((field) => buildControl(field, input, errorsByField.get(field.name) ?? [], field.name === input.subtypes?.field));
|
|
268
|
+
// Field-scoped errors for hidden fields would otherwise be invisible.
|
|
269
|
+
for (const [name, messages] of errorsByField) {
|
|
270
|
+
if (hidden.has(name))
|
|
271
|
+
formErrors.push(...messages);
|
|
272
|
+
}
|
|
273
|
+
const active = resolveActiveEditorSubtype(input.subtypes, input.values);
|
|
274
|
+
return {
|
|
275
|
+
operation: input.operation,
|
|
276
|
+
controls,
|
|
277
|
+
valid: input.validation.valid,
|
|
278
|
+
formErrors,
|
|
279
|
+
errors: input.validation.errors,
|
|
280
|
+
...(input.subtypes
|
|
281
|
+
? {
|
|
282
|
+
subtype: {
|
|
283
|
+
field: input.subtypes.field,
|
|
284
|
+
code: active?.code ?? subtypeCodeOf(input.values[input.subtypes.field]),
|
|
285
|
+
...(active?.name ? { name: active.name } : {}),
|
|
286
|
+
choices: input.subtypes.subtypes.map((subtype) => ({
|
|
287
|
+
value: String(subtype.code),
|
|
288
|
+
label: subtype.name,
|
|
289
|
+
})),
|
|
290
|
+
},
|
|
291
|
+
}
|
|
292
|
+
: {}),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function buildControl(field, input, errors, subtypeField) {
|
|
296
|
+
const kind = editorControlKind(field);
|
|
297
|
+
const raw = input.values[field.name];
|
|
298
|
+
const value = raw === undefined ? field.defaultValue : raw;
|
|
299
|
+
// A server-assigned field is read-only in the form, but on a create draft
|
|
300
|
+
// the contract deliberately does not *require* it — mirror that here so the
|
|
301
|
+
// form never demands a value the service supplies.
|
|
302
|
+
const serverAssignedOnCreate = input.operation === "create" && field.editable === false;
|
|
303
|
+
const range = field.domain?.type === "range" ? field.domain.range : undefined;
|
|
304
|
+
return {
|
|
305
|
+
name: field.name,
|
|
306
|
+
label: field.alias ?? field.name,
|
|
307
|
+
kind,
|
|
308
|
+
value: value ?? null,
|
|
309
|
+
required: (field.required === true || field.nullable === false) && !serverAssignedOnCreate,
|
|
310
|
+
readOnly: field.editable === false || input.operation === "delete",
|
|
311
|
+
nullable: field.nullable !== false,
|
|
312
|
+
...(typeof field.length === "number" && kind !== "number" ? { maxLength: field.length } : {}),
|
|
313
|
+
...(range ? { min: range[0], max: range[1] } : {}),
|
|
314
|
+
...(kind === "select" ? { choices: editorChoices(field) } : {}),
|
|
315
|
+
subtypeField,
|
|
316
|
+
errors,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/** Control kind for a field: coded-value domains select, otherwise by type. */
|
|
320
|
+
export function editorControlKind(field) {
|
|
321
|
+
if (field.domain?.type === "coded-value" && (field.domain.codedValues?.length ?? 0) > 0)
|
|
322
|
+
return "select";
|
|
323
|
+
const type = (field.type ?? "").toLowerCase();
|
|
324
|
+
if (type.includes("bool"))
|
|
325
|
+
return "checkbox";
|
|
326
|
+
if (type.includes("datetime") || type.includes("timestamp"))
|
|
327
|
+
return "datetime";
|
|
328
|
+
if (type.includes("date"))
|
|
329
|
+
return "date";
|
|
330
|
+
if (type.includes("int") ||
|
|
331
|
+
type.includes("double") ||
|
|
332
|
+
type.includes("single") ||
|
|
333
|
+
type.includes("float") ||
|
|
334
|
+
type.includes("decimal") ||
|
|
335
|
+
type.includes("number") ||
|
|
336
|
+
field.domain?.type === "range") {
|
|
337
|
+
return "number";
|
|
338
|
+
}
|
|
339
|
+
if (typeof field.length === "number" && field.length > 255)
|
|
340
|
+
return "textarea";
|
|
341
|
+
return "text";
|
|
342
|
+
}
|
|
343
|
+
function editorChoices(field) {
|
|
344
|
+
return (field.domain?.codedValues ?? []).map((coded) => ({
|
|
345
|
+
value: String(coded.code),
|
|
346
|
+
label: coded.name || String(coded.code),
|
|
347
|
+
}));
|
|
348
|
+
}
|
|
349
|
+
// ── raw control input → typed attribute value ────────────────────────────
|
|
350
|
+
/**
|
|
351
|
+
* Coerces raw control input (always a string from a DOM `value`, or a boolean
|
|
352
|
+
* from a checkbox) to the typed attribute value the source expects.
|
|
353
|
+
*
|
|
354
|
+
* Coded-value fields resolve back to the domain code's own type, so a numeric
|
|
355
|
+
* subtype or status code round-trips as a number rather than the `"3"` an
|
|
356
|
+
* `<option value>` carries — otherwise every coded-value edit would fail the
|
|
357
|
+
* contract's own domain check.
|
|
358
|
+
*/
|
|
359
|
+
export function coerceEditorFieldValue(field, raw) {
|
|
360
|
+
if (typeof raw === "boolean")
|
|
361
|
+
return raw;
|
|
362
|
+
if (raw === null)
|
|
363
|
+
return null;
|
|
364
|
+
const kind = editorControlKind(field);
|
|
365
|
+
if (kind === "select") {
|
|
366
|
+
const coded = (field.domain?.codedValues ?? []).find((entry) => String(entry.code) === raw);
|
|
367
|
+
if (coded)
|
|
368
|
+
return coded.code;
|
|
369
|
+
return raw === "" ? emptyValueFor(field) : raw;
|
|
370
|
+
}
|
|
371
|
+
if (raw === "")
|
|
372
|
+
return emptyValueFor(field);
|
|
373
|
+
if (kind === "checkbox")
|
|
374
|
+
return raw === "true" || raw === "on";
|
|
375
|
+
if (kind === "number") {
|
|
376
|
+
const parsed = Number(raw);
|
|
377
|
+
return Number.isFinite(parsed) ? parsed : raw;
|
|
378
|
+
}
|
|
379
|
+
return raw;
|
|
380
|
+
}
|
|
381
|
+
function emptyValueFor(field) {
|
|
382
|
+
return field.nullable === false ? "" : null;
|
|
383
|
+
}
|
|
384
|
+
/** Renders a typed attribute value as the string a DOM control carries. */
|
|
385
|
+
export function editorFieldInputValue(field, value) {
|
|
386
|
+
if (value === undefined || value === null)
|
|
387
|
+
return "";
|
|
388
|
+
if (typeof value === "boolean")
|
|
389
|
+
return String(value);
|
|
390
|
+
if (value instanceof Date)
|
|
391
|
+
return isoForControl(editorControlKind(field), value);
|
|
392
|
+
if (typeof value === "number" && (editorControlKind(field) === "date" || editorControlKind(field) === "datetime")) {
|
|
393
|
+
return isoForControl(editorControlKind(field), new Date(value));
|
|
394
|
+
}
|
|
395
|
+
if (typeof value === "object")
|
|
396
|
+
return JSON.stringify(value);
|
|
397
|
+
return String(value);
|
|
398
|
+
}
|
|
399
|
+
function isoForControl(kind, date) {
|
|
400
|
+
if (Number.isNaN(date.getTime()))
|
|
401
|
+
return "";
|
|
402
|
+
const iso = date.toISOString();
|
|
403
|
+
return kind === "datetime" ? iso.slice(0, 16) : iso.slice(0, 10);
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Redacts a staged attachment mutation down to safe descriptive metadata.
|
|
407
|
+
* String payloads (potentially credential-bearing URLs) never survive: only a
|
|
408
|
+
* `name`, which falls back to a neutral placeholder rather than the payload.
|
|
409
|
+
*/
|
|
410
|
+
export function redactEditorAttachment(mutation, index, status = "staged", error) {
|
|
411
|
+
const payload = mutation.attachment;
|
|
412
|
+
const blobLike = payload;
|
|
413
|
+
const name = mutation.name ??
|
|
414
|
+
(typeof blobLike?.name === "string" ? blobLike.name : undefined) ??
|
|
415
|
+
(mutation.operation === "delete" ? `${mutation.attachmentIds?.length ?? 0} attachment(s)` : "attachment");
|
|
416
|
+
return {
|
|
417
|
+
index,
|
|
418
|
+
operation: mutation.operation,
|
|
419
|
+
name,
|
|
420
|
+
...((mutation.contentType ?? (typeof blobLike?.type === "string" && blobLike.type))
|
|
421
|
+
? { contentType: mutation.contentType ?? blobLike?.type }
|
|
422
|
+
: {}),
|
|
423
|
+
...(typeof blobLike?.size === "number" ? { size: blobLike.size } : {}),
|
|
424
|
+
status,
|
|
425
|
+
...(error ? { error } : {}),
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
// ── helpers ──────────────────────────────────────────────────────────────
|
|
429
|
+
function sameCode(left, right) {
|
|
430
|
+
if (left === right)
|
|
431
|
+
return true;
|
|
432
|
+
return String(left) === String(right);
|
|
433
|
+
}
|
|
434
|
+
function subtypeCodeOf(value) {
|
|
435
|
+
if (typeof value === "number" || typeof value === "string")
|
|
436
|
+
return value;
|
|
437
|
+
return undefined;
|
|
438
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app-platform sketch default for `<honua-feature-editor>` (issue #680,
|
|
3
|
+
* REQ-002): a terra-draw-backed geometry adapter that stays bound across the
|
|
4
|
+
* editor's draft lifecycle.
|
|
5
|
+
*
|
|
6
|
+
* The SDK already ships the renderer-neutral sketch/snapping seam
|
|
7
|
+
* (`bindTerraDrawSketch`, `createTerraDrawSketch`, `createTerraDrawSnapping`,
|
|
8
|
+
* `terraDrawSketchToolCapabilities` on `@honua/sdk-js/runtime`). What
|
|
9
|
+
* app-platform adds here is *lifecycle composition*: a
|
|
10
|
+
* {@link HonuaFeatureEditorWorkflow} builds a fresh contract sketch workflow
|
|
11
|
+
* every time a draft opens, so a one-shot binding would silently stop driving
|
|
12
|
+
* the editor after the first submit. {@link bindEditorSketch} watches the
|
|
13
|
+
* workflow and re-binds terra-draw to each new draft's model, and reports
|
|
14
|
+
* terra-draw's true tool support (which upgrades `rectangle` / `circle` from
|
|
15
|
+
* the contract's renderer-support-required defaults) into the workflow so the
|
|
16
|
+
* editor's tool buttons are truthful.
|
|
17
|
+
*
|
|
18
|
+
* terra-draw itself stays an optional peer: {@link bindEditorSketch} takes a
|
|
19
|
+
* duck-typed instance the app already constructed, and only
|
|
20
|
+
* {@link createTerraDrawEditorSketch} — the one-call default — pulls the peer
|
|
21
|
+
* in, through the runtime module's own lazy `import()`.
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import type { EditSketchTool, EditSketchToolCapability } from "../contract/edit-sketch.js";
|
|
26
|
+
import { type SnapIndex, type SnappingConfig } from "../contract/edit-snapping.js";
|
|
27
|
+
import { type BindTerraDrawSketchOptions, type CreateTerraDrawSnappingOptions, type TerraDrawSketchInstance } from "../runtime/terra-draw-sketch.js";
|
|
28
|
+
import type { HonuaFeatureEditorWorkflow } from "./feature-editor-workflow.js";
|
|
29
|
+
/**
|
|
30
|
+
* The geometry seam `<honua-feature-editor>` composes with. Every method is a
|
|
31
|
+
* no-op-with-a-reason while no draft is open, so a host never has to branch on
|
|
32
|
+
* the editor's lifecycle.
|
|
33
|
+
*/
|
|
34
|
+
export interface HonuaEditorSketchAdapter {
|
|
35
|
+
/** Arms a drawing tool in both the sketch backend and the workflow. */
|
|
36
|
+
setTool(tool: EditSketchTool): EditSketchToolCapability;
|
|
37
|
+
/** Switches the backend to reshape/select mode for updating existing geometry. */
|
|
38
|
+
select(): void;
|
|
39
|
+
/** Leaves any drawing or select mode. */
|
|
40
|
+
cancel(): void;
|
|
41
|
+
/** Undo through the workflow, then re-sync the backend. */
|
|
42
|
+
undo(): boolean;
|
|
43
|
+
/** Redo through the workflow, then re-sync the backend. */
|
|
44
|
+
redo(): boolean;
|
|
45
|
+
/** Pushes the workflow's current geometry back into the backend. */
|
|
46
|
+
syncFromModel(): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Resolves once the adapter has finished (re)binding to the workflow's
|
|
49
|
+
* current draft. Deterministic hook for hosts and tests after `begin()`.
|
|
50
|
+
*/
|
|
51
|
+
ready(): Promise<void>;
|
|
52
|
+
/** Detaches from the workflow and the sketch backend. */
|
|
53
|
+
remove(): void;
|
|
54
|
+
}
|
|
55
|
+
/** Options shared by both adapter factories. */
|
|
56
|
+
export interface HonuaEditorSketchOptions<T = Record<string, unknown>> extends Pick<BindTerraDrawSketchOptions<T>, "transformGeometry" | "restoreGeometry" | "featureFilter" | "toolForMode" | "onFinish" | "onDelete"> {
|
|
57
|
+
/** Editor workflow whose drafts drive (and are driven by) the sketch backend. */
|
|
58
|
+
readonly workflow: HonuaFeatureEditorWorkflow<T>;
|
|
59
|
+
/**
|
|
60
|
+
* terra-draw modes actually registered on the instance. Defaults to every
|
|
61
|
+
* canonical drawing mode; used to report truthful tool support.
|
|
62
|
+
*/
|
|
63
|
+
readonly modes?: readonly string[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Binds an already-constructed terra-draw instance to an editor workflow, and
|
|
67
|
+
* keeps it bound as drafts open and close.
|
|
68
|
+
*
|
|
69
|
+
* Also reports terra-draw's real tool support into the workflow, so the
|
|
70
|
+
* editor's `rectangle` / `circle` buttons become enabled instead of showing
|
|
71
|
+
* the contract's "requires renderer support" reason.
|
|
72
|
+
*/
|
|
73
|
+
export declare function bindEditorSketch<T = Record<string, unknown>>(draw: TerraDrawSketchInstance, options: HonuaEditorSketchOptions<T>): HonuaEditorSketchAdapter;
|
|
74
|
+
/** SDK snapping inputs for a terra-draw-backed editor. */
|
|
75
|
+
export interface HonuaEditorSnappingOptions {
|
|
76
|
+
/** Snap index over the loaded snap-source features. */
|
|
77
|
+
readonly index: SnapIndex;
|
|
78
|
+
/** Fallback configuration used while no draft is open. */
|
|
79
|
+
readonly config?: Partial<SnappingConfig>;
|
|
80
|
+
}
|
|
81
|
+
/** Options for the one-call terra-draw default. */
|
|
82
|
+
export interface CreateTerraDrawEditorSketchOptions<T = Record<string, unknown>> extends HonuaEditorSketchOptions<T> {
|
|
83
|
+
/**
|
|
84
|
+
* Wire SDK snapping into the terra-draw modes that expose a custom snapping
|
|
85
|
+
* hook (linestring / polygon). terra-draw resolves its snapping options once,
|
|
86
|
+
* when the instance is constructed, so these are routed through
|
|
87
|
+
* {@link editorSnappingOptions} to stay live across draft re-binds.
|
|
88
|
+
*/
|
|
89
|
+
readonly snapping?: HonuaEditorSnappingOptions;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Snapping options to hand terra-draw for an editor workflow.
|
|
93
|
+
*
|
|
94
|
+
* terra-draw resolves `snapping.toCustom` once per mode, at construction, and
|
|
95
|
+
* `createTerraDrawSnapping` captures the `model` it is given — but the editor
|
|
96
|
+
* builds a *new* contract sketch model for every draft. Passing the model
|
|
97
|
+
* directly would pin snapping to the first draft forever, so
|
|
98
|
+
* `setSnapping(...)` on any later draft would silently do nothing.
|
|
99
|
+
*
|
|
100
|
+
* This returns a stable options object whose `model` is a thin live view that
|
|
101
|
+
* resolves the workflow's *current* model on each pointer event, falling back
|
|
102
|
+
* to `config` (or disabled snapping) while no draft is open.
|
|
103
|
+
*
|
|
104
|
+
* Use it when constructing terra-draw yourself alongside
|
|
105
|
+
* {@link bindEditorSketch}; {@link createTerraDrawEditorSketch} applies it for
|
|
106
|
+
* you.
|
|
107
|
+
*/
|
|
108
|
+
export declare function editorSnappingOptions<T = Record<string, unknown>>(workflow: HonuaFeatureEditorWorkflow<T>, snapping: HonuaEditorSnappingOptions): CreateTerraDrawSnappingOptions<T>;
|
|
109
|
+
/**
|
|
110
|
+
* The app-platform terra-draw default: constructs terra-draw for a MapLibre
|
|
111
|
+
* map (pulling the optional `terra-draw` peers lazily through the runtime
|
|
112
|
+
* module), wires SDK snapping, and binds it to the editor workflow for the
|
|
113
|
+
* lifetime of the adapter.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const workflow = createFeatureEditorWorkflow({ source });
|
|
118
|
+
* const sketch = await createTerraDrawEditorSketch(map, { workflow });
|
|
119
|
+
* editor.workflow = workflow; // <honua-feature-editor>
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export declare function createTerraDrawEditorSketch<T = Record<string, unknown>>(map: unknown, options: CreateTerraDrawEditorSketchOptions<T>): Promise<HonuaEditorSketchAdapter & {
|
|
123
|
+
stop(): void;
|
|
124
|
+
}>;
|
|
125
|
+
//# sourceMappingURL=feature-editor-sketch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-editor-sketch.d.ts","sourceRoot":"","sources":["../../../src/web-components/feature-editor-sketch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAA2B,MAAM,4BAA4B,CAAC;AACpH,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAyB,MAAM,8BAA8B,CAAC;AAC1G,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,8BAA8B,EAEnC,KAAK,uBAAuB,EAI7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,wBAAwB,CAAC;IACxD,kFAAkF;IAClF,MAAM,IAAI,IAAI,CAAC;IACf,yCAAyC;IACzC,MAAM,IAAI,IAAI,CAAC;IACf,2DAA2D;IAC3D,IAAI,IAAI,OAAO,CAAC;IAChB,2DAA2D;IAC3D,IAAI,IAAI,OAAO,CAAC;IAChB,oEAAoE;IACpE,aAAa,IAAI,OAAO,CAAC;IACzB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,yDAAyD;IACzD,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,gDAAgD;AAChD,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACnE,SAAQ,IAAI,CACV,0BAA0B,CAAC,CAAC,CAAC,EAC7B,mBAAmB,GAAG,iBAAiB,GAAG,eAAe,GAAG,aAAa,GAAG,UAAU,GAAG,UAAU,CACpG;IACD,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC,CAAC,CAAC,CAAC;IACjD;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1D,IAAI,EAAE,uBAAuB,EAC7B,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACnC,wBAAwB,CAE1B;AAED,0DAA0D;AAC1D,MAAM,WAAW,0BAA0B;IACzC,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CAC3C;AAED,mDAAmD;AACnD,MAAM,WAAW,kCAAkC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,wBAAwB,CAAC,CAAC,CAAC;IAClH;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,0BAA0B,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/D,QAAQ,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACvC,QAAQ,EAAE,0BAA0B,GACnC,8BAA8B,CAAC,CAAC,CAAC,CAQnC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,2BAA2B,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3E,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,kCAAkC,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,wBAAwB,GAAG;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,CAAC,CA6BtD"}
|