@open-pioneer/feature-editing 1.3.0-dev.20260512095810 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +5 -1
  2. package/api/editor/context.d.ts +16 -18
  3. package/api/editor/context.js +3 -3
  4. package/api/editor/context.js.map +1 -1
  5. package/api/fields/standardFieldConfigs.d.ts +2 -1
  6. package/api/model/FeatureTemplate.d.ts +2 -2
  7. package/i18n/de.yaml +13 -0
  8. package/i18n/en.yaml +15 -2
  9. package/implementation/FeatureEditor.js +6 -6
  10. package/implementation/FeatureEditor.js.map +1 -1
  11. package/implementation/components/action-selector/SelectButton.js +1 -1
  12. package/implementation/components/action-selector/SelectButton.js.map +1 -1
  13. package/implementation/components/controls/NumberFieldControl.js +1 -0
  14. package/implementation/components/controls/NumberFieldControl.js.map +1 -1
  15. package/implementation/components/property-editor/CancelConfirmationDialog.d.ts +8 -0
  16. package/implementation/components/property-editor/CancelConfirmationDialog.js +51 -0
  17. package/implementation/components/property-editor/CancelConfirmationDialog.js.map +1 -0
  18. package/implementation/components/property-editor/PropertyEditor.d.ts +10 -5
  19. package/implementation/components/property-editor/PropertyEditor.js +99 -21
  20. package/implementation/components/property-editor/PropertyEditor.js.map +1 -1
  21. package/implementation/components/property-editor/PropertyField.js +30 -4
  22. package/implementation/components/property-editor/PropertyField.js.map +1 -1
  23. package/implementation/components/property-editor/PropertyForm.d.ts +4 -7
  24. package/implementation/components/property-editor/PropertyForm.js +49 -67
  25. package/implementation/components/property-editor/PropertyForm.js.map +1 -1
  26. package/implementation/context/PropertyFormContext.d.ts +26 -10
  27. package/implementation/context/PropertyFormContext.js +96 -21
  28. package/implementation/context/PropertyFormContext.js.map +1 -1
  29. package/implementation/context/usePropertyFormContext.d.ts +17 -2
  30. package/implementation/context/usePropertyFormContext.js +17 -3
  31. package/implementation/context/usePropertyFormContext.js.map +1 -1
  32. package/implementation/geometry-editing/controller/EditingController.js +3 -0
  33. package/implementation/geometry-editing/controller/EditingController.js.map +1 -1
  34. package/implementation/geometry-editing/interactions/BaseInteraction.js +2 -0
  35. package/implementation/geometry-editing/interactions/BaseInteraction.js.map +1 -1
  36. package/index.d.ts +1 -1
  37. package/index.js +1 -1
  38. package/package.json +13 -13
  39. package/implementation/context/PropertyFormContextProvider.d.ts +0 -9
  40. package/implementation/context/PropertyFormContextProvider.js +0 -18
  41. package/implementation/context/PropertyFormContextProvider.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,7 +1,11 @@
1
1
  # @open-pioneer/feature-editing
2
2
 
3
- ## 1.3.0-dev.20260512095810
3
+ ## 1.3.0
4
4
 
5
5
  ### Minor Changes
6
6
 
7
7
  - d3e137d: Initial release
8
+
9
+ ### Patch Changes
10
+
11
+ - 0704cd6: Use `classnames` from `@open-pioneer/react-utils` instead of `classnames` package.
@@ -4,18 +4,17 @@ import type { Feature } from "ol";
4
4
  import type { ModificationStep } from "../model/EditingStep";
5
5
  import type { FeatureTemplate } from "../model/FeatureTemplate";
6
6
  /**
7
- * React hook for accessing the property form context.
7
+ * React hook for accessing the property form context within a custom form.
8
8
  *
9
- * Provides access to the {@link PropertyFormContext} instance, which contains the current feature
9
+ * Provides access to the {@link CustomFormContext} instance, which contains the current feature
10
10
  * being edited and methods to read and update its properties. This hook must be called from within
11
- * a component that is rendered inside a property form (typically in a custom form rendered by
12
- * {@link DynamicFormTemplate}).
11
+ * a component that is rendered inside a custom property form (see {@link DynamicFormTemplate}).
13
12
  *
14
13
  * The context also allows controlling the form's validity by setting the `isValid` property,
15
14
  * which determines whether the save button is enabled.
16
15
  *
17
- * @returns The current {@link PropertyFormContext} instance.
18
- * @throws Error if called outside of a property form context (e.g., when no feature is being
16
+ * @returns The current {@link CustomFormContext} instance.
17
+ * @throws Error if called outside of a custom property form context (e.g., when no feature is being
19
18
  * edited).
20
19
  *
21
20
  * @example
@@ -23,37 +22,36 @@ import type { FeatureTemplate } from "../model/FeatureTemplate";
23
22
  * import { useReactiveSnapshot, DISPATCH_SYNC } from "@open-pioneer/reactivity";
24
23
  *
25
24
  * function CustomForm() {
26
- * const context = usePropertyFormContext();
27
- * const name = useReactiveSnapshot(() => context.properties.get("name") ?? "", [context], DISPATCH_SYNC);
25
+ * const context = useCustomFormContext();
26
+ * const name = useReactiveSnapshot(
27
+ * () => (context.properties.get("name") as string) ?? "",
28
+ * [context],
29
+ * DISPATCH_SYNC
30
+ * );
28
31
  *
29
32
  * useEffect(() => {
30
33
  * context.isValid = name.length >= 1;
31
34
  * }, [context, name]);
32
35
  *
33
- * return (
34
- * <input
35
- * value={name}
36
- * onChange={(e) => context.properties.set("name", e.target.value)}
37
- * />
38
- * );
36
+ * return <Input value={name} onChange={(e) => context.properties.set("name", e.target.value)} />;
39
37
  * }
40
38
  * ```
41
39
  *
42
40
  * @group Editor
43
41
  */
44
- export declare const usePropertyFormContext: () => PropertyFormContext;
42
+ export declare const useCustomFormContext: () => CustomFormContext;
45
43
  /**
46
44
  * Context object providing access to feature properties and editing state during form editing.
47
45
  *
48
- * This class manages the state of a feature being edited, including its properties, validation
46
+ * The context manages the state of a feature being edited, including its properties, validation
49
47
  * status, and associated metadata. It provides reactive property management through a
50
48
  * {@link ReactiveMap}, allowing components to automatically re-render when properties change.
51
49
  *
52
- * Access this context in custom forms using the {@link usePropertyFormContext} hook.
50
+ * Access this context in custom forms using the {@link useCustomFormContext} hook.
53
51
  *
54
52
  * @group Editor
55
53
  */
56
- export interface PropertyFormContext {
54
+ export interface CustomFormContext {
57
55
  /**
58
56
  * The OpenLayers feature being edited.
59
57
  *
@@ -1,6 +1,6 @@
1
- import { usePropertyFormContext as usePropertyFormContext$1 } from '../../implementation/context/usePropertyFormContext.js';
1
+ import { useCustomFormContext as useCustomFormContext$1 } from '../../implementation/context/usePropertyFormContext.js';
2
2
 
3
- const usePropertyFormContext = usePropertyFormContext$1;
3
+ const useCustomFormContext = useCustomFormContext$1;
4
4
 
5
- export { usePropertyFormContext };
5
+ export { useCustomFormContext };
6
6
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sources":["context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport type { ReactiveMap } from \"@conterra/reactivity-core\";\nimport type { Layer } from \"@open-pioneer/map\";\nimport type { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport type { Feature } from \"ol\";\nimport { usePropertyFormContext as usePropertyFormContextImpl } from \"../../implementation/context/usePropertyFormContext\";\nimport type { CreationStep, ModificationStep, UpdateStep } from \"../model/EditingStep\";\nimport type { DynamicFormTemplate, FeatureTemplate } from \"../model/FeatureTemplate\";\n\n/**\n * React hook for accessing the property form context.\n *\n * Provides access to the {@link PropertyFormContext} instance, which contains the current feature\n * being edited and methods to read and update its properties. This hook must be called from within\n * a component that is rendered inside a property form (typically in a custom form rendered by\n * {@link DynamicFormTemplate}).\n *\n * The context also allows controlling the form's validity by setting the `isValid` property,\n * which determines whether the save button is enabled.\n *\n * @returns The current {@link PropertyFormContext} instance.\n * @throws Error if called outside of a property form context (e.g., when no feature is being\n * edited).\n *\n * @example\n * ```tsx\n * import { useReactiveSnapshot, DISPATCH_SYNC } from \"@open-pioneer/reactivity\";\n *\n * function CustomForm() {\n * const context = usePropertyFormContext();\n * const name = useReactiveSnapshot(() => context.properties.get(\"name\") ?? \"\", [context], DISPATCH_SYNC);\n *\n * useEffect(() => {\n * context.isValid = name.length >= 1;\n * }, [context, name]);\n *\n * return (\n * <input\n * value={name}\n * onChange={(e) => context.properties.set(\"name\", e.target.value)}\n * />\n * );\n * }\n * ```\n *\n * @group Editor\n */\nexport const usePropertyFormContext: () => PropertyFormContext = usePropertyFormContextImpl;\n\n/**\n * Context object providing access to feature properties and editing state during form editing.\n *\n * This class manages the state of a feature being edited, including its properties, validation\n * status, and associated metadata. It provides reactive property management through a\n * {@link ReactiveMap}, allowing components to automatically re-render when properties change.\n *\n * Access this context in custom forms using the {@link usePropertyFormContext} hook.\n *\n * @group Editor\n */\nexport interface PropertyFormContext {\n /**\n * The OpenLayers feature being edited.\n *\n * Provides direct access to the feature object, which includes its geometry and properties.\n */\n readonly feature: Feature;\n\n /**\n * Reactive map of feature properties.\n *\n * Provides reactive access to all feature properties (excluding geometry). Use `get()` to read\n * property values and `set()` to update them. Components can use {@link useReactiveSnapshot}\n * to automatically re-render when values change.\n *\n * @example\n * ```ts\n * const name = context.properties.get(\"name\");\n * context.properties.set(\"name\", \"New Name\");\n * ```\n */\n readonly properties: ReactiveMap<string, unknown>;\n\n /**\n * Returns all feature properties as a plain JavaScript object.\n *\n * Converts the reactive properties map to a standard object with string keys and unknown\n * values. Useful when you need to pass properties to functions that expect plain objects.\n *\n * Note that a new object is created on every change.\n * Prefer to use fine grained accesses to {@link properties} if performance matters.\n *\n * @returns A plain object containing all feature properties (excluding geometry).\n */\n readonly getPropertiesAsObject: () => Record<string, unknown>;\n\n /**\n * The current editing step containing the feature and associated metadata.\n *\n * Provides access to the complete editing step, which can be either a {@link CreationStep}\n * or {@link UpdateStep}.\n */\n readonly editingStep: ModificationStep;\n\n /**\n * The current editing mode.\n *\n * Returns `\"create\"` when creating a new feature, or `\"update\"` when editing an existing\n * feature. Use this to conditionally render different UI or apply different logic based on the\n * editing mode.\n */\n readonly mode: Mode;\n\n /**\n * The feature template used to create the feature, if in creation mode.\n *\n * Returns the {@link FeatureTemplate} when creating a new feature (`mode === \"create\"`), or\n * `undefined` when editing an existing feature (`mode === \"update\"`).\n */\n readonly template: FeatureTemplate | undefined;\n\n /**\n * The layer containing the feature being edited, if in update mode.\n *\n * Returns the {@link Layer} when editing an existing feature (`mode === \"update\"`), or\n * `undefined` when creating a new feature (`mode === \"create\"`) or if the layer is not\n * available.\n */\n readonly layer: Layer | undefined;\n\n /**\n * Whether the form is currently valid.\n *\n * Controls the enabled state of the save button in the property editor. Set this to `true`\n * when the form passes validation, or `false` when there are validation errors. For\n * declarative forms, this is managed automatically based on field validation rules.\n */\n isValid: boolean;\n}\n\n/**\n * The editing mode for a feature.\n *\n * - `\"create\"`: Creating a new feature\n * - `\"update\"`: Editing an existing feature\n *\n * @group Editor\n */\nexport type Mode = \"create\" | \"update\";\n"],"names":["usePropertyFormContextImpl"],"mappings":";;AAgDO,MAAM,sBAAA,GAAoDA;;;;"}
1
+ {"version":3,"file":"context.js","sources":["context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport type { ReactiveMap } from \"@conterra/reactivity-core\";\nimport type { Layer } from \"@open-pioneer/map\";\nimport type { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport type { Feature } from \"ol\";\nimport { useCustomFormContext as useCustomFormContextImpl } from \"../../implementation/context/usePropertyFormContext\";\nimport type { CreationStep, ModificationStep, UpdateStep } from \"../model/EditingStep\";\nimport type { DynamicFormTemplate, FeatureTemplate } from \"../model/FeatureTemplate\";\n\n/**\n * React hook for accessing the property form context within a custom form.\n *\n * Provides access to the {@link CustomFormContext} instance, which contains the current feature\n * being edited and methods to read and update its properties. This hook must be called from within\n * a component that is rendered inside a custom property form (see {@link DynamicFormTemplate}).\n *\n * The context also allows controlling the form's validity by setting the `isValid` property,\n * which determines whether the save button is enabled.\n *\n * @returns The current {@link CustomFormContext} instance.\n * @throws Error if called outside of a custom property form context (e.g., when no feature is being\n * edited).\n *\n * @example\n * ```tsx\n * import { useReactiveSnapshot, DISPATCH_SYNC } from \"@open-pioneer/reactivity\";\n *\n * function CustomForm() {\n * const context = useCustomFormContext();\n * const name = useReactiveSnapshot(\n * () => (context.properties.get(\"name\") as string) ?? \"\",\n * [context],\n * DISPATCH_SYNC\n * );\n *\n * useEffect(() => {\n * context.isValid = name.length >= 1;\n * }, [context, name]);\n *\n * return <Input value={name} onChange={(e) => context.properties.set(\"name\", e.target.value)} />;\n * }\n * ```\n *\n * @group Editor\n */\nexport const useCustomFormContext: () => CustomFormContext = useCustomFormContextImpl;\n\n/**\n * Context object providing access to feature properties and editing state during form editing.\n *\n * The context manages the state of a feature being edited, including its properties, validation\n * status, and associated metadata. It provides reactive property management through a\n * {@link ReactiveMap}, allowing components to automatically re-render when properties change.\n *\n * Access this context in custom forms using the {@link useCustomFormContext} hook.\n *\n * @group Editor\n */\nexport interface CustomFormContext {\n /**\n * The OpenLayers feature being edited.\n *\n * Provides direct access to the feature object, which includes its geometry and properties.\n */\n readonly feature: Feature;\n\n /**\n * Reactive map of feature properties.\n *\n * Provides reactive access to all feature properties (excluding geometry). Use `get()` to read\n * property values and `set()` to update them. Components can use {@link useReactiveSnapshot}\n * to automatically re-render when values change.\n *\n * @example\n * ```ts\n * const name = context.properties.get(\"name\");\n * context.properties.set(\"name\", \"New Name\");\n * ```\n */\n readonly properties: ReactiveMap<string, unknown>;\n\n /**\n * Returns all feature properties as a plain JavaScript object.\n *\n * Converts the reactive properties map to a standard object with string keys and unknown\n * values. Useful when you need to pass properties to functions that expect plain objects.\n *\n * Note that a new object is created on every change.\n * Prefer to use fine grained accesses to {@link properties} if performance matters.\n *\n * @returns A plain object containing all feature properties (excluding geometry).\n */\n readonly getPropertiesAsObject: () => Record<string, unknown>;\n\n /**\n * The current editing step containing the feature and associated metadata.\n *\n * Provides access to the complete editing step, which can be either a {@link CreationStep}\n * or {@link UpdateStep}.\n */\n readonly editingStep: ModificationStep;\n\n /**\n * The current editing mode.\n *\n * Returns `\"create\"` when creating a new feature, or `\"update\"` when editing an existing\n * feature. Use this to conditionally render different UI or apply different logic based on the\n * editing mode.\n */\n readonly mode: Mode;\n\n /**\n * The feature template used to create the feature, if in creation mode.\n *\n * Returns the {@link FeatureTemplate} when creating a new feature (`mode === \"create\"`), or\n * `undefined` when editing an existing feature (`mode === \"update\"`).\n */\n readonly template: FeatureTemplate | undefined;\n\n /**\n * The layer containing the feature being edited, if in update mode.\n *\n * Returns the {@link Layer} when editing an existing feature (`mode === \"update\"`), or\n * `undefined` when creating a new feature (`mode === \"create\"`) or if the layer is not\n * available.\n */\n readonly layer: Layer | undefined;\n\n /**\n * Whether the form is currently valid.\n *\n * Controls the enabled state of the save button in the property editor. Set this to `true`\n * when the form passes validation, or `false` when there are validation errors. For\n * declarative forms, this is managed automatically based on field validation rules.\n */\n isValid: boolean;\n}\n\n/**\n * The editing mode for a feature.\n *\n * - `\"create\"`: Creating a new feature\n * - `\"update\"`: Editing an existing feature\n *\n * @group Editor\n */\nexport type Mode = \"create\" | \"update\";\n"],"names":["useCustomFormContextImpl"],"mappings":";;AA8CO,MAAM,oBAAA,GAAgDA;;;;"}
@@ -1,3 +1,4 @@
1
+ import { type FormatNumberOptions } from "@formatjs/intl";
1
2
  import type { BaseFieldConfig } from "./BaseFieldConfig";
2
3
  /**
3
4
  * Configuration for a checkbox field.
@@ -87,7 +88,7 @@ export interface NumberFieldConfig extends BaseFieldConfig {
87
88
  * `maximumFractionDigits`, `style`, `currency`, etc. Use this to control how the number
88
89
  * is displayed to the user (e.g., as currency, percentage, or with specific decimal places).
89
90
  */
90
- readonly formatOptions?: Intl.NumberFormatOptions;
91
+ readonly formatOptions?: FormatNumberOptions;
91
92
  /**
92
93
  * Increment/decrement step size when using stepper buttons.
93
94
  *
@@ -95,7 +95,7 @@ export interface DeclarativeFormTemplate {
95
95
  * component. Use this when you need advanced form layouts, custom validation logic, or
96
96
  * specialized UI components that cannot be expressed through declarative field configurations.
97
97
  *
98
- * The render function should use {@link PropertyFormContext} to read and update feature properties.
98
+ * The render function should use {@link CustomFormContext} to read and update feature properties.
99
99
  *
100
100
  * @group Model
101
101
  */
@@ -113,7 +113,7 @@ export interface DynamicFormTemplate {
113
113
  * Function that renders the custom form content.
114
114
  *
115
115
  * Should return a React element representing the form UI. The function can use React hooks
116
- * and {@link PropertyFormContext} to interact with feature properties.
116
+ * and {@link CustomFormContext} to interact with feature properties.
117
117
  */
118
118
  readonly renderForm: () => ReactNode;
119
119
  }
package/i18n/de.yaml CHANGED
@@ -3,6 +3,7 @@ messages:
3
3
  editFeatureHeading: Geoobjekt bearbeiten
4
4
  createFeatureHeading: Geoobjekt erstellen
5
5
  selectButtonTitle: Auswählen
6
+ selectButtonActiveTitle: Auswählen beenden
6
7
  finishButtonTooltip: Zeichnen beenden
7
8
  resetButtonTooltip: Zeichnung zurücksetzen
8
9
  undoButtonTooltip: Rückgängig machen
@@ -10,14 +11,26 @@ messages:
10
11
  propertyEditor:
11
12
  defaultEditHeading: Geoobjekt bearbeiten
12
13
  defaultCreateHeading: Geoobjekt erstellen
14
+ requiredFieldHint: "Pflichtfeld"
13
15
  saveButtonTitle: Speichern
14
16
  cancelButtonTitle: Abbrechen
15
17
  deleteButtonTooltip: Geoobjekt löschen
18
+
19
+ errors:
20
+ minAndMax: Der Wert muss zwischen {min} und {max} liegen.
21
+ minOnly: Der Wert muss mindestens {min} sein.
22
+ maxOnly: Der Wert darf höchstens {max} sein.
23
+
16
24
  deleteConfirmationDialog:
17
25
  title: Geoobjekt löschen
18
26
  message: Sind Sie sicher, dass Sie dieses Geoobjekt löschen möchten?
19
27
  deleteButtonTitle: Geoobjekt löschen
20
28
  cancelButtonTitle: Abbrechen
29
+ cancelConfirmationDialog:
30
+ title: Änderungen verwerfen
31
+ message: Sind Sie sicher, dass Sie Ihre Änderungen verwerfen möchten?
32
+ confirmCancelButtonTitle: Änderungen verwerfen
33
+ abortCancelButtonTitle: Weiter bearbeiten
21
34
  notifier:
22
35
  creationSuccess: Geoobjekt erstellt
23
36
  creationFailure: Das Geoobjekt konnte nicht erstellt werden.
package/i18n/en.yaml CHANGED
@@ -3,6 +3,7 @@ messages:
3
3
  editFeatureHeading: Edit Feature
4
4
  createFeatureHeading: Create Feature
5
5
  selectButtonTitle: Select
6
+ selectButtonActiveTitle: Cancel selection
6
7
  finishButtonTooltip: Finish drawing
7
8
  resetButtonTooltip: Reset drawing
8
9
  undoButtonTooltip: Undo
@@ -10,14 +11,26 @@ messages:
10
11
  propertyEditor:
11
12
  defaultEditHeading: Edit Feature
12
13
  defaultCreateHeading: Create Feature
14
+ requiredFieldHint: "Required field"
13
15
  saveButtonTitle: Save
14
16
  cancelButtonTitle: Cancel
15
- deleteButtonTooltip: Delete Feature
17
+ deleteButtonTooltip: Delete feature
18
+
19
+ errors:
20
+ minAndMax: The value must be between {min} and {max}.
21
+ minOnly: The value must be {min} or higher.
22
+ maxOnly: The value must be {max} or lower.
23
+
16
24
  deleteConfirmationDialog:
17
25
  title: Delete Feature
18
26
  message: Are you sure you want to delete this feature?
19
- deleteButtonTitle: Delete Feature
27
+ deleteButtonTitle: Delete feature
20
28
  cancelButtonTitle: Cancel
29
+ cancelConfirmationDialog:
30
+ title: Discard changes
31
+ message: Are you sure you want to discard your changes?
32
+ confirmCancelButtonTitle: Discard changes
33
+ abortCancelButtonTitle: Continue editing
21
34
  notifier:
22
35
  creationSuccess: Feature created
23
36
  creationFailure: The feature failed to be created.
@@ -2,12 +2,10 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { Box } from '@chakra-ui/react';
3
3
  import { useMapModelValue } from '@open-pioneer/map';
4
4
  import { useCommonComponentProps } from '@open-pioneer/react-utils';
5
- import { useMemo } from 'react';
6
5
  import { useIntl } from '../_virtual/hooks.js';
6
+ import { useMemo } from 'react';
7
7
  import { ActionSelector } from './components/action-selector/ActionSelector.js';
8
- import { PropertyForm } from './components/property-editor/PropertyForm.js';
9
8
  import { PropertyEditor } from './components/property-editor/PropertyEditor.js';
10
- import { PropertyFormContextProvider } from './context/PropertyFormContextProvider.js';
11
9
  import { useEditingStep, useSnappingSources, useOnActionChange } from './editor/editorHooks.js';
12
10
  import { useEditingCallbacks } from './editor/useEditingCallbacks.js';
13
11
  import { useGeometryEditing } from './geometry-editing/useGeometryEditing.js';
@@ -89,13 +87,15 @@ function FeatureEditor(props) {
89
87
  break;
90
88
  case "creation":
91
89
  case "update":
92
- content = /* @__PURE__ */ jsx(PropertyFormContextProvider, { editingStep, callbacks: editingCallbacks, children: /* @__PURE__ */ jsx(PropertyEditor, { children: /* @__PURE__ */ jsx(
93
- PropertyForm,
90
+ content = /* @__PURE__ */ jsx(
91
+ PropertyEditor,
94
92
  {
93
+ editingStep,
94
+ callbacks: editingCallbacks,
95
95
  templates,
96
96
  resolveFormTemplate
97
97
  }
98
- ) }) });
98
+ );
99
99
  break;
100
100
  }
101
101
  return /* @__PURE__ */ jsx(Box, { ...containerProps, h: "full", children: content });
@@ -1 +1 @@
1
- {"version":3,"file":"FeatureEditor.js","sources":["FeatureEditor.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box } from \"@chakra-ui/react\";\nimport { useMapModelValue } from \"@open-pioneer/map\";\nimport { useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { type ReactElement, type ReactNode, useMemo } from \"react\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport type { FeatureEditorProps } from \"../api/editor/editor\";\nimport { ActionSelector } from \"./components/action-selector/ActionSelector\";\nimport { PropertyForm } from \"./components/property-editor/PropertyForm\";\nimport { PropertyEditor } from \"./components/property-editor/PropertyEditor\";\nimport { PropertyFormContextProvider } from \"./context/PropertyFormContextProvider\";\nimport { useEditingStep, useOnActionChange, useSnappingSources } from \"./editor/editorHooks\";\nimport { useEditingCallbacks } from \"./editor/useEditingCallbacks\";\nimport { useGeometryEditing } from \"./geometry-editing/useGeometryEditing\";\nimport type { Type as GeometryType } from \"ol/geom/Geometry\";\nimport { TooltipMessages } from \"./geometry-editing/controller/EditingController\";\n\nexport function FeatureEditor(props: FeatureEditorProps): ReactElement {\n const {\n map,\n templates,\n writer,\n resolveFormTemplate,\n selectableLayers,\n snappableLayers = selectableLayers,\n showActionBar = true,\n successNotifierDisplayDuration,\n failureNotifierDisplayDuration,\n onEditingStepChange,\n ...interactionOptions\n } = props;\n const { containerProps } = useCommonComponentProps(\"editor\", props);\n const mapModel = useMapModelValue(props);\n const intl = useIntl();\n\n const [editingStep, setEditingStep] = useEditingStep(onEditingStepChange);\n const snappingSources = useSnappingSources(mapModel, snappableLayers, templates);\n const onActionChange = useOnActionChange(mapModel, selectableLayers, templates, setEditingStep);\n\n const tooltipMessages = useMemo((): TooltipMessages => {\n return {\n getDrawingMessages() {\n return new Map<GeometryType, ReactNode>([\n [\"Point\", intl.formatRichMessage({ id: \"tooltips.drawingMessagePoint\" })],\n [\n \"LineString\",\n intl.formatRichMessage({ id: \"tooltips.drawingMessageLineString\" })\n ],\n [\"Polygon\", intl.formatRichMessage({ id: \"tooltips.drawingMessagePolygon\" })],\n [\"Circle\", intl.formatRichMessage({ id: \"tooltips.drawingMessageCircle\" })]\n ]);\n },\n getSelectionMessage() {\n return intl.formatRichMessage({ id: \"tooltips.selectionMessage\" });\n },\n getModificationMessages() {\n return new Map<string, ReactNode>([\n [\"Point\", intl.formatRichMessage({ id: \"tooltips.modificationMessagePoint\" })],\n [\"default\", intl.formatRichMessage({ id: \"tooltips.modificationMessage\" })]\n ]);\n }\n };\n }, [intl]);\n\n const drawingState = useGeometryEditing({\n map,\n editingStep,\n setEditingStep,\n snappingSources,\n tooltipMessages,\n ...interactionOptions\n });\n\n const editingCallbacks = useEditingCallbacks(\n mapModel,\n editingStep,\n writer,\n setEditingStep,\n successNotifierDisplayDuration,\n failureNotifierDisplayDuration\n );\n\n let content: ReactNode;\n switch (editingStep.id) {\n case \"initial\":\n case \"drawing\":\n case \"selection\":\n content = (\n <ActionSelector\n templates={templates}\n showActionBar={showActionBar}\n onActionChange={onActionChange}\n drawingState={drawingState}\n />\n );\n break;\n case \"creation\":\n case \"update\":\n content = (\n <PropertyFormContextProvider editingStep={editingStep} callbacks={editingCallbacks}>\n <PropertyEditor>\n <PropertyForm\n templates={templates}\n resolveFormTemplate={resolveFormTemplate}\n />\n </PropertyEditor>\n </PropertyFormContextProvider>\n );\n break;\n }\n\n return (\n <Box {...containerProps} h=\"full\">\n {content}\n </Box>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FeatureEditor.js","sources":["FeatureEditor.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box } from \"@chakra-ui/react\";\nimport { useMapModelValue } from \"@open-pioneer/map\";\nimport { useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport type { Type as GeometryType } from \"ol/geom/Geometry\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { type ReactElement, type ReactNode, useMemo } from \"react\";\nimport type { FeatureEditorProps } from \"../api/editor/editor\";\nimport { ActionSelector } from \"./components/action-selector/ActionSelector\";\nimport { PropertyEditor } from \"./components/property-editor/PropertyEditor\";\nimport { useEditingStep, useOnActionChange, useSnappingSources } from \"./editor/editorHooks\";\nimport { useEditingCallbacks } from \"./editor/useEditingCallbacks\";\nimport { TooltipMessages } from \"./geometry-editing/controller/EditingController\";\nimport { useGeometryEditing } from \"./geometry-editing/useGeometryEditing\";\n\nexport function FeatureEditor(props: FeatureEditorProps): ReactElement {\n const {\n map,\n templates,\n writer,\n resolveFormTemplate,\n selectableLayers,\n snappableLayers = selectableLayers,\n showActionBar = true,\n successNotifierDisplayDuration,\n failureNotifierDisplayDuration,\n onEditingStepChange,\n ...interactionOptions\n } = props;\n const { containerProps } = useCommonComponentProps(\"editor\", props);\n const mapModel = useMapModelValue(props);\n const intl = useIntl();\n\n const [editingStep, setEditingStep] = useEditingStep(onEditingStepChange);\n const snappingSources = useSnappingSources(mapModel, snappableLayers, templates);\n const onActionChange = useOnActionChange(mapModel, selectableLayers, templates, setEditingStep);\n\n const tooltipMessages = useMemo((): TooltipMessages => {\n return {\n getDrawingMessages() {\n return new Map<GeometryType, ReactNode>([\n [\"Point\", intl.formatRichMessage({ id: \"tooltips.drawingMessagePoint\" })],\n [\n \"LineString\",\n intl.formatRichMessage({ id: \"tooltips.drawingMessageLineString\" })\n ],\n [\"Polygon\", intl.formatRichMessage({ id: \"tooltips.drawingMessagePolygon\" })],\n [\"Circle\", intl.formatRichMessage({ id: \"tooltips.drawingMessageCircle\" })]\n ]);\n },\n getSelectionMessage() {\n return intl.formatRichMessage({ id: \"tooltips.selectionMessage\" });\n },\n getModificationMessages() {\n return new Map<string, ReactNode>([\n [\"Point\", intl.formatRichMessage({ id: \"tooltips.modificationMessagePoint\" })],\n [\"default\", intl.formatRichMessage({ id: \"tooltips.modificationMessage\" })]\n ]);\n }\n };\n }, [intl]);\n\n const drawingState = useGeometryEditing({\n map,\n editingStep,\n setEditingStep,\n snappingSources,\n tooltipMessages,\n ...interactionOptions\n });\n\n const editingCallbacks = useEditingCallbacks(\n mapModel,\n editingStep,\n writer,\n setEditingStep,\n successNotifierDisplayDuration,\n failureNotifierDisplayDuration\n );\n\n let content: ReactNode;\n switch (editingStep.id) {\n case \"initial\":\n case \"drawing\":\n case \"selection\":\n content = (\n <ActionSelector\n templates={templates}\n showActionBar={showActionBar}\n onActionChange={onActionChange}\n drawingState={drawingState}\n />\n );\n break;\n case \"creation\":\n case \"update\":\n content = (\n <PropertyEditor\n editingStep={editingStep}\n callbacks={editingCallbacks}\n templates={templates}\n resolveFormTemplate={resolveFormTemplate}\n />\n );\n break;\n }\n\n return (\n <Box {...containerProps} h=\"full\">\n {content}\n </Box>\n );\n}\n\n"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@ function SelectButton({ isActive, onClick }) {
16
16
  onClick,
17
17
  children: [
18
18
  /* @__PURE__ */ jsx(LuMousePointerClick, { "aria-hidden": "true" }),
19
- formatMessage({ id: "actionSelector.selectButtonTitle" })
19
+ isActive ? formatMessage({ id: "actionSelector.selectButtonActiveTitle" }) : formatMessage({ id: "actionSelector.selectButtonTitle" })
20
20
  ]
21
21
  }
22
22
  ) });
@@ -1 +1 @@
1
- {"version":3,"file":"SelectButton.js","sources":["SelectButton.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Button, Toggle } from \"@chakra-ui/react\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { LuMousePointerClick } from \"react-icons/lu\";\nimport type { ReactElement } from \"react\";\n\ninterface SelectButtonProps {\n readonly isActive: boolean;\n readonly onClick: () => void;\n}\n\nexport function SelectButton({ isActive, onClick }: SelectButtonProps): ReactElement {\n const { formatMessage } = useIntl();\n\n return (\n <Toggle.Root pressed={isActive} asChild>\n <Button\n className=\"editor__action-selector-select-button\"\n variant=\"outline\"\n _hover={{ bg: isActive ? \"colorPalette.700\" : \"colorPalette.subtle\" }}\n _pressed={{ bg: \"colorPalette.800\", color: \"colorPalette.contrast\" }}\n // Margin for focus outline\n marginX=\"4px\"\n onClick={onClick}\n >\n <LuMousePointerClick aria-hidden=\"true\" />\n {formatMessage({ id: \"actionSelector.selectButtonTitle\" })}\n </Button>\n </Toggle.Root>\n );\n}\n"],"names":[],"mappings":";;;;;AAYO,SAAS,YAAA,CAAa,EAAE,QAAA,EAAU,OAAA,EAAQ,EAAoC;AACjF,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,OAAA,EAAQ;AAElC,EAAA,2BACK,MAAA,CAAO,IAAA,EAAP,EAAY,OAAA,EAAS,QAAA,EAAU,SAAO,IAAA,EACnC,QAAA,kBAAA,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACG,SAAA,EAAU,uCAAA;AAAA,MACV,OAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ,EAAE,EAAA,EAAI,QAAA,GAAW,qBAAqB,qBAAA,EAAsB;AAAA,MACpE,QAAA,EAAU,EAAE,EAAA,EAAI,kBAAA,EAAoB,OAAO,uBAAA,EAAwB;AAAA,MAEnE,OAAA,EAAQ,KAAA;AAAA,MACR,OAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,eAAY,MAAA,EAAO,CAAA;AAAA,QACvC,aAAA,CAAc,EAAE,EAAA,EAAI,kCAAA,EAAoC;AAAA;AAAA;AAAA,GAC7D,EACJ,CAAA;AAER;;;;"}
1
+ {"version":3,"file":"SelectButton.js","sources":["SelectButton.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Button, Toggle } from \"@chakra-ui/react\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { LuMousePointerClick } from \"react-icons/lu\";\nimport type { ReactElement } from \"react\";\n\ninterface SelectButtonProps {\n readonly isActive: boolean;\n readonly onClick: () => void;\n}\n\nexport function SelectButton({ isActive, onClick }: SelectButtonProps): ReactElement {\n const { formatMessage } = useIntl();\n\n return (\n <Toggle.Root pressed={isActive} asChild>\n <Button\n className=\"editor__action-selector-select-button\"\n variant=\"outline\"\n _hover={{ bg: isActive ? \"colorPalette.700\" : \"colorPalette.subtle\" }}\n _pressed={{ bg: \"colorPalette.800\", color: \"colorPalette.contrast\" }}\n // Margin for focus outline\n marginX=\"4px\"\n onClick={onClick}\n >\n <LuMousePointerClick aria-hidden=\"true\" />\n {isActive\n ? formatMessage({ id: \"actionSelector.selectButtonActiveTitle\" })\n : formatMessage({ id: \"actionSelector.selectButtonTitle\" })}\n </Button>\n </Toggle.Root>\n );\n}\n"],"names":[],"mappings":";;;;;AAYO,SAAS,YAAA,CAAa,EAAE,QAAA,EAAU,OAAA,EAAQ,EAAoC;AACjF,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,OAAA,EAAQ;AAElC,EAAA,2BACK,MAAA,CAAO,IAAA,EAAP,EAAY,OAAA,EAAS,QAAA,EAAU,SAAO,IAAA,EACnC,QAAA,kBAAA,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACG,SAAA,EAAU,uCAAA;AAAA,MACV,OAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ,EAAE,EAAA,EAAI,QAAA,GAAW,qBAAqB,qBAAA,EAAsB;AAAA,MACpE,QAAA,EAAU,EAAE,EAAA,EAAI,kBAAA,EAAoB,OAAO,uBAAA,EAAwB;AAAA,MAEnE,OAAA,EAAQ,KAAA;AAAA,MACR,OAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,eAAY,MAAA,EAAO,CAAA;AAAA,QACvC,QAAA,GACK,aAAA,CAAc,EAAE,EAAA,EAAI,wCAAA,EAA0C,CAAA,GAC9D,aAAA,CAAc,EAAE,EAAA,EAAI,kCAAA,EAAoC;AAAA;AAAA;AAAA,GAClE,EACJ,CAAA;AAER;;;;"}
@@ -32,6 +32,7 @@ function NumberFieldControl({
32
32
  step: field.step,
33
33
  formatOptions: field.formatOptions,
34
34
  onValueChange,
35
+ clampValueOnBlur: false,
35
36
  children: [
36
37
  /* @__PURE__ */ jsx(NumberInput.Input, { ref: element, placeholder: field.placeholder ?? field.label }),
37
38
  field.showSteppers && /* @__PURE__ */ jsx(NumberInput.Control, {})
@@ -1 +1 @@
1
- {"version":3,"file":"NumberFieldControl.js","sources":["NumberFieldControl.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { NumberInput, type NumberInputValueChangeDetails } from \"@chakra-ui/react\";\nimport { useEvent } from \"@open-pioneer/react-utils\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { useCallback, useEffect, useRef, useState, type ReactElement } from \"react\";\nimport type { NumberFieldConfig } from \"../../../api/fields/standardFieldConfigs\";\n\ninterface NumberFieldControlProps {\n readonly value: number | undefined;\n readonly field: NumberFieldConfig;\n readonly onChange: (newNumber: number | undefined) => void;\n}\n\n// This component allows its value to be specified as a number. The value is still stored as a\n// string internally to allow non-numeric characters (such as '-', '.', or 'e') to be entered.\nexport function NumberFieldControl({\n value,\n field,\n onChange\n}: NumberFieldControlProps): ReactElement {\n const formatNumber = useFormatNumber(field.formatOptions);\n const [stringValue, setStringValue] = useState(() => formatNumber(value));\n const setNumericValue = useNumericState(value, field.formatOptions, setStringValue);\n\n const onValueChange = useEvent(({ value, valueAsNumber }: NumberInputValueChangeDetails) => {\n setStringValue(value);\n if (!isNaN(valueAsNumber)) {\n setNumericValue(valueAsNumber);\n onChange?.(valueAsNumber);\n } else if (value === \"\") {\n setNumericValue(undefined);\n onChange?.(undefined);\n }\n });\n\n const element = useRef<HTMLInputElement>(null);\n\n return (\n <NumberInput.Root\n value={stringValue ?? \"\"}\n min={field.min}\n max={field.max}\n step={field.step}\n formatOptions={field.formatOptions}\n onValueChange={onValueChange}\n >\n <NumberInput.Input ref={element} placeholder={field.placeholder ?? field.label} />\n {field.showSteppers && <NumberInput.Control />}\n </NumberInput.Root>\n );\n}\n\n// Additionally store the state as a number to be able to react to outside changes of 'value'.\nfunction useNumericState(\n value: number | undefined,\n formatOptions: Intl.NumberFormatOptions | undefined,\n setStringValue: (newValue: string | undefined) => void\n) {\n const [numericValue, setNumericValue] = useState(value);\n const formatNumber = useFormatNumber(formatOptions);\n\n useEffect(() => {\n if (value !== numericValue) {\n const stringValue = formatNumber(value);\n setStringValue(stringValue);\n setNumericValue(value);\n }\n }, [formatNumber, numericValue, setStringValue, value]);\n\n return setNumericValue;\n}\n\nfunction useFormatNumber(formatOptions: Intl.NumberFormatOptions | undefined) {\n const { formatNumber } = useIntl();\n\n return useCallback(\n (number: number | undefined) => {\n if (number != null) {\n return formatNumber(number, { maximumFractionDigits: 20, ...formatOptions });\n } else {\n return undefined;\n }\n },\n [formatNumber, formatOptions]\n );\n}\n"],"names":["value"],"mappings":";;;;;;AAgBO,SAAS,kBAAA,CAAmB;AAAA,EAC/B,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACJ,CAAA,EAA0C;AACtC,EAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,KAAA,CAAM,aAAa,CAAA;AACxD,EAAA,MAAM,CAAC,aAAa,cAAc,CAAA,GAAI,SAAS,MAAM,YAAA,CAAa,KAAK,CAAC,CAAA;AACxE,EAAA,MAAM,eAAA,GAAkB,eAAA,CAAgB,KAAA,EAAO,KAAA,CAAM,eAAe,cAAc,CAAA;AAElF,EAAA,MAAM,gBAAgB,QAAA,CAAS,CAAC,EAAE,KAAA,EAAAA,MAAAA,EAAO,eAAc,KAAqC;AACxF,IAAA,cAAA,CAAeA,MAAK,CAAA;AACpB,IAAA,IAAI,CAAC,KAAA,CAAM,aAAa,CAAA,EAAG;AACvB,MAAA,eAAA,CAAgB,aAAa,CAAA;AAC7B,MAAA,QAAA,GAAW,aAAa,CAAA;AAAA,IAC5B,CAAA,MAAA,IAAWA,WAAU,EAAA,EAAI;AACrB,MAAA,eAAA,CAAgB,MAAS,CAAA;AACzB,MAAA,QAAA,GAAW,MAAS,CAAA;AAAA,IACxB;AAAA,EACJ,CAAC,CAAA;AAED,EAAA,MAAM,OAAA,GAAU,OAAyB,IAAI,CAAA;AAE7C,EAAA,uBACI,IAAA;AAAA,IAAC,WAAA,CAAY,IAAA;AAAA,IAAZ;AAAA,MACG,OAAO,WAAA,IAAe,EAAA;AAAA,MACtB,KAAK,KAAA,CAAM,GAAA;AAAA,MACX,KAAK,KAAA,CAAM,GAAA;AAAA,MACX,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,eAAe,KAAA,CAAM,aAAA;AAAA,MACrB,aAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,WAAA,CAAY,OAAZ,EAAkB,GAAA,EAAK,SAAS,WAAA,EAAa,KAAA,CAAM,WAAA,IAAe,KAAA,CAAM,KAAA,EAAO,CAAA;AAAA,QAC/E,KAAA,CAAM,YAAA,oBAAgB,GAAA,CAAC,WAAA,CAAY,SAAZ,EAAoB;AAAA;AAAA;AAAA,GAChD;AAER;AAGA,SAAS,eAAA,CACL,KAAA,EACA,aAAA,EACA,cAAA,EACF;AACE,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,YAAA,GAAe,gBAAgB,aAAa,CAAA;AAElD,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,IAAI,UAAU,YAAA,EAAc;AACxB,MAAA,MAAM,WAAA,GAAc,aAAa,KAAK,CAAA;AACtC,MAAA,cAAA,CAAe,WAAW,CAAA;AAC1B,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACzB;AAAA,EACJ,GAAG,CAAC,YAAA,EAAc,YAAA,EAAc,cAAA,EAAgB,KAAK,CAAC,CAAA;AAEtD,EAAA,OAAO,eAAA;AACX;AAEA,SAAS,gBAAgB,aAAA,EAAqD;AAC1E,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,OAAA,EAAQ;AAEjC,EAAA,OAAO,WAAA;AAAA,IACH,CAAC,MAAA,KAA+B;AAC5B,MAAA,IAAI,UAAU,IAAA,EAAM;AAChB,QAAA,OAAO,aAAa,MAAA,EAAQ,EAAE,uBAAuB,EAAA,EAAI,GAAG,eAAe,CAAA;AAAA,MAC/E,CAAA,MAAO;AACH,QAAA,OAAO,MAAA;AAAA,MACX;AAAA,IACJ,CAAA;AAAA,IACA,CAAC,cAAc,aAAa;AAAA,GAChC;AACJ;;;;"}
1
+ {"version":3,"file":"NumberFieldControl.js","sources":["NumberFieldControl.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { NumberInput, type NumberInputValueChangeDetails } from \"@chakra-ui/react\";\nimport { type FormatNumberOptions } from \"@formatjs/intl\";\nimport { useEvent } from \"@open-pioneer/react-utils\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { useCallback, useEffect, useRef, useState, type ReactElement } from \"react\";\nimport type { NumberFieldConfig } from \"../../../api/fields/standardFieldConfigs\";\n\ninterface NumberFieldControlProps {\n readonly value: number | undefined;\n readonly field: NumberFieldConfig;\n readonly onChange: (newNumber: number | undefined) => void;\n}\n\n// This component allows its value to be specified as a number. The value is still stored as a\n// string internally to allow non-numeric characters (such as '-', '.', or 'e') to be entered.\nexport function NumberFieldControl({\n value,\n field,\n onChange\n}: NumberFieldControlProps): ReactElement {\n const formatNumber = useFormatNumber(field.formatOptions);\n const [stringValue, setStringValue] = useState(() => formatNumber(value));\n const setNumericValue = useNumericState(value, field.formatOptions, setStringValue);\n\n const onValueChange = useEvent(({ value, valueAsNumber }: NumberInputValueChangeDetails) => {\n setStringValue(value);\n if (!isNaN(valueAsNumber)) {\n setNumericValue(valueAsNumber);\n onChange?.(valueAsNumber);\n } else if (value === \"\") {\n setNumericValue(undefined);\n onChange?.(undefined);\n }\n });\n\n const element = useRef<HTMLInputElement>(null);\n\n return (\n <NumberInput.Root\n value={stringValue ?? \"\"}\n min={field.min}\n max={field.max}\n step={field.step}\n formatOptions={field.formatOptions}\n onValueChange={onValueChange}\n clampValueOnBlur={false}\n >\n <NumberInput.Input ref={element} placeholder={field.placeholder ?? field.label} />\n {field.showSteppers && <NumberInput.Control />}\n </NumberInput.Root>\n );\n}\n\n// Additionally store the state as a number to be able to react to outside changes of 'value'.\nfunction useNumericState(\n value: number | undefined,\n formatOptions: FormatNumberOptions | undefined,\n setStringValue: (newValue: string | undefined) => void\n) {\n const [numericValue, setNumericValue] = useState(value);\n const formatNumber = useFormatNumber(formatOptions);\n\n useEffect(() => {\n if (value !== numericValue) {\n const stringValue = formatNumber(value);\n setStringValue(stringValue);\n setNumericValue(value);\n }\n }, [formatNumber, numericValue, setStringValue, value]);\n\n return setNumericValue;\n}\n\nfunction useFormatNumber(formatOptions: FormatNumberOptions | undefined) {\n const { formatNumber } = useIntl();\n\n return useCallback(\n (number: number | undefined) => {\n if (number != null) {\n return formatNumber(number, { maximumFractionDigits: 20, ...formatOptions });\n } else {\n return undefined;\n }\n },\n [formatNumber, formatOptions]\n );\n}\n"],"names":["value"],"mappings":";;;;;;AAiBO,SAAS,kBAAA,CAAmB;AAAA,EAC/B,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACJ,CAAA,EAA0C;AACtC,EAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,KAAA,CAAM,aAAa,CAAA;AACxD,EAAA,MAAM,CAAC,aAAa,cAAc,CAAA,GAAI,SAAS,MAAM,YAAA,CAAa,KAAK,CAAC,CAAA;AACxE,EAAA,MAAM,eAAA,GAAkB,eAAA,CAAgB,KAAA,EAAO,KAAA,CAAM,eAAe,cAAc,CAAA;AAElF,EAAA,MAAM,gBAAgB,QAAA,CAAS,CAAC,EAAE,KAAA,EAAAA,MAAAA,EAAO,eAAc,KAAqC;AACxF,IAAA,cAAA,CAAeA,MAAK,CAAA;AACpB,IAAA,IAAI,CAAC,KAAA,CAAM,aAAa,CAAA,EAAG;AACvB,MAAA,eAAA,CAAgB,aAAa,CAAA;AAC7B,MAAA,QAAA,GAAW,aAAa,CAAA;AAAA,IAC5B,CAAA,MAAA,IAAWA,WAAU,EAAA,EAAI;AACrB,MAAA,eAAA,CAAgB,MAAS,CAAA;AACzB,MAAA,QAAA,GAAW,MAAS,CAAA;AAAA,IACxB;AAAA,EACJ,CAAC,CAAA;AAED,EAAA,MAAM,OAAA,GAAU,OAAyB,IAAI,CAAA;AAE7C,EAAA,uBACI,IAAA;AAAA,IAAC,WAAA,CAAY,IAAA;AAAA,IAAZ;AAAA,MACG,OAAO,WAAA,IAAe,EAAA;AAAA,MACtB,KAAK,KAAA,CAAM,GAAA;AAAA,MACX,KAAK,KAAA,CAAM,GAAA;AAAA,MACX,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,eAAe,KAAA,CAAM,aAAA;AAAA,MACrB,aAAA;AAAA,MACA,gBAAA,EAAkB,KAAA;AAAA,MAElB,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,WAAA,CAAY,OAAZ,EAAkB,GAAA,EAAK,SAAS,WAAA,EAAa,KAAA,CAAM,WAAA,IAAe,KAAA,CAAM,KAAA,EAAO,CAAA;AAAA,QAC/E,KAAA,CAAM,YAAA,oBAAgB,GAAA,CAAC,WAAA,CAAY,SAAZ,EAAoB;AAAA;AAAA;AAAA,GAChD;AAER;AAGA,SAAS,eAAA,CACL,KAAA,EACA,aAAA,EACA,cAAA,EACF;AACE,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,YAAA,GAAe,gBAAgB,aAAa,CAAA;AAElD,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,IAAI,UAAU,YAAA,EAAc;AACxB,MAAA,MAAM,WAAA,GAAc,aAAa,KAAK,CAAA;AACtC,MAAA,cAAA,CAAe,WAAW,CAAA;AAC1B,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACzB;AAAA,EACJ,GAAG,CAAC,YAAA,EAAc,YAAA,EAAc,cAAA,EAAgB,KAAK,CAAC,CAAA;AAEtD,EAAA,OAAO,eAAA;AACX;AAEA,SAAS,gBAAgB,aAAA,EAAgD;AACrE,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,OAAA,EAAQ;AAEjC,EAAA,OAAO,WAAA;AAAA,IACH,CAAC,MAAA,KAA+B;AAC5B,MAAA,IAAI,UAAU,IAAA,EAAM;AAChB,QAAA,OAAO,aAAa,MAAA,EAAQ,EAAE,uBAAuB,EAAA,EAAI,GAAG,eAAe,CAAA;AAAA,MAC/E,CAAA,MAAO;AACH,QAAA,OAAO,MAAA;AAAA,MACX;AAAA,IACJ,CAAA;AAAA,IACA,CAAC,cAAc,aAAa;AAAA,GAChC;AACJ;;;;"}
@@ -0,0 +1,8 @@
1
+ import { type ReactElement } from "react";
2
+ interface CancelConfirmationDialogProps {
3
+ readonly isOpen: boolean;
4
+ readonly onConfirmCancel: () => void;
5
+ readonly onAbortCancel: () => void;
6
+ }
7
+ export declare function CancelConfirmationDialog({ isOpen, onConfirmCancel, onAbortCancel }: CancelConfirmationDialogProps): ReactElement;
8
+ export {};
@@ -0,0 +1,51 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { Dialog, Button } from '@chakra-ui/react';
3
+ import { useIntl } from '../../../_virtual/hooks.js';
4
+ import { useRef, useCallback, useMemo } from 'react';
5
+
6
+ function CancelConfirmationDialog({
7
+ isOpen,
8
+ onConfirmCancel,
9
+ onAbortCancel
10
+ }) {
11
+ const cancelButtonRef = useRef(null);
12
+ const initialFocusEl = useCallback(() => cancelButtonRef.current, []);
13
+ const { formatMessage } = useIntl();
14
+ const { title, message, confirmCancelButtonTitle, abortCancelButtonTitle } = useMemo(
15
+ () => ({
16
+ title: formatMessage({ id: "cancelConfirmationDialog.title" }),
17
+ message: formatMessage({ id: "cancelConfirmationDialog.message" }),
18
+ confirmCancelButtonTitle: formatMessage({
19
+ id: "cancelConfirmationDialog.confirmCancelButtonTitle"
20
+ }),
21
+ abortCancelButtonTitle: formatMessage({
22
+ id: "cancelConfirmationDialog.abortCancelButtonTitle"
23
+ })
24
+ }),
25
+ [formatMessage]
26
+ );
27
+ return /* @__PURE__ */ jsxs(Dialog.Root, { open: isOpen, initialFocusEl, role: "alertdialog", children: [
28
+ /* @__PURE__ */ jsx(Dialog.Backdrop, {}),
29
+ /* @__PURE__ */ jsx(Dialog.Positioner, { children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
30
+ /* @__PURE__ */ jsx(Dialog.Header, { fontSize: "large", fontWeight: "bold", children: title }),
31
+ /* @__PURE__ */ jsx(Dialog.Body, { children: message }),
32
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
33
+ /* @__PURE__ */ jsx(
34
+ Button,
35
+ {
36
+ bg: "red.solid",
37
+ color: "red.contrast",
38
+ _hover: { bg: "red.solid/90" },
39
+ loadingText: confirmCancelButtonTitle,
40
+ onClick: onConfirmCancel,
41
+ children: confirmCancelButtonTitle
42
+ }
43
+ ),
44
+ /* @__PURE__ */ jsx(Button, { variant: "outline", ref: cancelButtonRef, onClick: onAbortCancel, children: abortCancelButtonTitle })
45
+ ] })
46
+ ] }) })
47
+ ] });
48
+ }
49
+
50
+ export { CancelConfirmationDialog };
51
+ //# sourceMappingURL=CancelConfirmationDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CancelConfirmationDialog.js","sources":["CancelConfirmationDialog.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Button, Dialog } from \"@chakra-ui/react\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { useCallback, useMemo, useRef, type ReactElement } from \"react\";\n\ninterface CancelConfirmationDialogProps {\n readonly isOpen: boolean;\n readonly onConfirmCancel: () => void;\n readonly onAbortCancel: () => void;\n}\n\nexport function CancelConfirmationDialog({\n isOpen,\n onConfirmCancel,\n onAbortCancel\n}: CancelConfirmationDialogProps): ReactElement {\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n const initialFocusEl = useCallback(() => cancelButtonRef.current, []);\n const { formatMessage } = useIntl();\n\n const { title, message, confirmCancelButtonTitle, abortCancelButtonTitle } = useMemo(\n () => ({\n title: formatMessage({ id: \"cancelConfirmationDialog.title\" }),\n message: formatMessage({ id: \"cancelConfirmationDialog.message\" }),\n confirmCancelButtonTitle: formatMessage({\n id: \"cancelConfirmationDialog.confirmCancelButtonTitle\"\n }),\n abortCancelButtonTitle: formatMessage({\n id: \"cancelConfirmationDialog.abortCancelButtonTitle\"\n })\n }),\n [formatMessage]\n );\n\n return (\n <Dialog.Root open={isOpen} initialFocusEl={initialFocusEl} role=\"alertdialog\">\n <Dialog.Backdrop />\n <Dialog.Positioner>\n <Dialog.Content>\n <Dialog.Header fontSize=\"large\" fontWeight=\"bold\">\n {title}\n </Dialog.Header>\n <Dialog.Body>{message}</Dialog.Body>\n <Dialog.Footer>\n <Button\n bg=\"red.solid\"\n color=\"red.contrast\"\n _hover={{ bg: \"red.solid/90\" }}\n loadingText={confirmCancelButtonTitle}\n onClick={onConfirmCancel}\n >\n {confirmCancelButtonTitle}\n </Button>\n <Button variant=\"outline\" ref={cancelButtonRef} onClick={onAbortCancel}>\n {abortCancelButtonTitle}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog.Positioner>\n </Dialog.Root>\n );\n}\n"],"names":[],"mappings":";;;;;AAYO,SAAS,wBAAA,CAAyB;AAAA,EACrC,MAAA;AAAA,EACA,eAAA;AAAA,EACA;AACJ,CAAA,EAAgD;AAC5C,EAAA,MAAM,eAAA,GAAkB,OAA0B,IAAI,CAAA;AACtD,EAAA,MAAM,iBAAiB,WAAA,CAAY,MAAM,eAAA,CAAgB,OAAA,EAAS,EAAE,CAAA;AACpE,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,OAAA,EAAQ;AAElC,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,wBAAA,EAA0B,wBAAuB,GAAI,OAAA;AAAA,IACzE,OAAO;AAAA,MACH,KAAA,EAAO,aAAA,CAAc,EAAE,EAAA,EAAI,kCAAkC,CAAA;AAAA,MAC7D,OAAA,EAAS,aAAA,CAAc,EAAE,EAAA,EAAI,oCAAoC,CAAA;AAAA,MACjE,0BAA0B,aAAA,CAAc;AAAA,QACpC,EAAA,EAAI;AAAA,OACP,CAAA;AAAA,MACD,wBAAwB,aAAA,CAAc;AAAA,QAClC,EAAA,EAAI;AAAA,OACP;AAAA,KACL,CAAA;AAAA,IACA,CAAC,aAAa;AAAA,GAClB;AAEA,EAAA,uBACI,IAAA,CAAC,OAAO,IAAA,EAAP,EAAY,MAAM,MAAA,EAAQ,cAAA,EAAgC,MAAK,aAAA,EAC5D,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAA,CAAO,UAAP,EAAgB,CAAA;AAAA,wBAChB,MAAA,CAAO,UAAA,EAAP,EACG,QAAA,kBAAA,IAAA,CAAC,MAAA,CAAO,SAAP,EACG,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,OAAO,MAAA,EAAP,EAAc,UAAS,OAAA,EAAQ,UAAA,EAAW,QACtC,QAAA,EAAA,KAAA,EACL,CAAA;AAAA,sBACA,GAAA,CAAC,MAAA,CAAO,IAAA,EAAP,EAAa,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,sBACtB,IAAA,CAAC,MAAA,CAAO,MAAA,EAAP,EACG,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACG,EAAA,EAAG,WAAA;AAAA,YACH,KAAA,EAAM,cAAA;AAAA,YACN,MAAA,EAAQ,EAAE,EAAA,EAAI,cAAA,EAAe;AAAA,YAC7B,WAAA,EAAa,wBAAA;AAAA,YACb,OAAA,EAAS,eAAA;AAAA,YAER,QAAA,EAAA;AAAA;AAAA,SACL;AAAA,wBACA,GAAA,CAAC,UAAO,OAAA,EAAQ,SAAA,EAAU,KAAK,eAAA,EAAiB,OAAA,EAAS,eACpD,QAAA,EAAA,sBAAA,EACL;AAAA,OAAA,EACJ;AAAA,KAAA,EACJ,CAAA,EACJ;AAAA,GAAA,EACJ,CAAA;AAER;;;;"}
@@ -1,5 +1,10 @@
1
- import type { ReactElement, ReactNode } from "react";
2
- export interface PropertyEditorProps {
3
- readonly children: ReactNode;
4
- }
5
- export declare function PropertyEditor({ children }: PropertyEditorProps): ReactElement;
1
+ import { FeatureEditorProps } from "../../../api/editor/editor";
2
+ import { CreationStep, UpdateStep } from "../../../api/model/EditingStep";
3
+ import { FeatureTemplate } from "../../../api/model/FeatureTemplate";
4
+ import { EditingCallbacks } from "../../editor/useEditingCallbacks";
5
+ export declare function PropertyEditor(props: {
6
+ editingStep: CreationStep | UpdateStep;
7
+ callbacks: EditingCallbacks;
8
+ templates: FeatureTemplate[];
9
+ resolveFormTemplate: FeatureEditorProps["resolveFormTemplate"];
10
+ }): import("react/jsx-runtime").JSX.Element | undefined;
@@ -1,15 +1,84 @@
1
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
- import { useDisclosure, VStack, Box } from '@chakra-ui/react';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { Flex, useDisclosure } from '@chakra-ui/react';
3
3
  import { useEvent } from '@open-pioneer/react-utils';
4
4
  import { useReactiveSnapshot } from '@open-pioneer/reactivity';
5
- import { usePropertyFormContext } from '../../context/usePropertyFormContext.js';
5
+ import { useMemo, useCallback } from 'react';
6
6
  import { ButtonRow } from './ButtonRow.js';
7
+ import { CancelConfirmationDialog } from './CancelConfirmationDialog.js';
7
8
  import { DeleteConfirmationDialog } from './DeleteConfirmationDialog.js';
9
+ import { DeclarativeFormContext, CustomFormContextImpl, FormContext } from '../../context/PropertyFormContext.js';
10
+ import { PropertyField } from './PropertyField.js';
11
+ import { PropertyForm } from './PropertyForm.js';
12
+ import { usePropertyFormContext } from '../../context/usePropertyFormContext.js';
8
13
 
9
- function PropertyEditor({ children }) {
14
+ function PropertyEditor(props) {
15
+ const { editingStep, callbacks, templates, resolveFormTemplate } = props;
16
+ const formTemplate = useFormTemplate(templates, resolveFormTemplate, editingStep);
17
+ const context = useMemo(() => {
18
+ if (!formTemplate) {
19
+ return void 0;
20
+ }
21
+ if (formTemplate.kind === "declarative") {
22
+ return new DeclarativeFormContext(editingStep, callbacks, formTemplate);
23
+ } else {
24
+ return new CustomFormContextImpl(editingStep, callbacks, formTemplate);
25
+ }
26
+ }, [formTemplate, editingStep, callbacks]);
27
+ return context && formTemplate && /* @__PURE__ */ jsx(FormContext, { value: context, children: /* @__PURE__ */ jsxs(
28
+ Flex,
29
+ {
30
+ className: "editor__property-editor",
31
+ direction: "column",
32
+ height: "full",
33
+ overflowY: "hidden",
34
+ children: [
35
+ /* @__PURE__ */ jsx(PropertyForm, { children: formTemplate.kind === "dynamic" ? formTemplate.renderForm() : formTemplate.fields.map((field, index) => /* @__PURE__ */ jsx(PropertyField, { field }, index)) }),
36
+ /* @__PURE__ */ jsx(EditorControls, {})
37
+ ]
38
+ }
39
+ ) });
40
+ }
41
+ function useFormTemplate(templates, customResolver, editingStep) {
42
+ const defaultResolver = useDefaultFormTemplateResolver(templates);
43
+ const resolveFormTemplate = customResolver ?? defaultResolver;
44
+ const feature = editingStep.feature;
45
+ const layer = editingStep.id === "update" ? editingStep.layer : void 0;
46
+ const explicitTemplate = editingStep.id === "creation" ? editingStep.template : void 0;
47
+ return useMemo(() => {
48
+ if (explicitTemplate) {
49
+ return explicitTemplate;
50
+ } else if (editingStep.id === "update") {
51
+ return resolveFormTemplate({ feature, layer });
52
+ } else {
53
+ return void 0;
54
+ }
55
+ }, [explicitTemplate, editingStep.id, feature, layer, resolveFormTemplate]);
56
+ }
57
+ function useDefaultFormTemplateResolver(templates) {
58
+ return useCallback(
59
+ ({ layer }) => {
60
+ if (layer?.id != null) {
61
+ return templates.find(({ layerId }) => layer.id === layerId);
62
+ } else {
63
+ return void 0;
64
+ }
65
+ },
66
+ [templates]
67
+ );
68
+ }
69
+ function EditorControls() {
10
70
  const context = usePropertyFormContext();
11
71
  const canSave = useReactiveSnapshot(() => context.isValid, [context]);
12
- const { open: dialogIsOpen, onOpen: openDialog, onClose: closeDialog } = useDisclosure();
72
+ const {
73
+ open: deleteDialogIsOpen,
74
+ onOpen: openDeleteDialog,
75
+ onClose: closeDeleteDialog
76
+ } = useDisclosure();
77
+ const {
78
+ open: cancelDialogIsOpen,
79
+ onOpen: openCancelDialog,
80
+ onClose: closeCancelConfirmationDialog
81
+ } = useDisclosure();
13
82
  const onSaveClick = useEvent(async () => {
14
83
  const properties = context.getPropertiesAsObject();
15
84
  context.feature.setProperties(properties);
@@ -17,28 +86,37 @@ function PropertyEditor({ children }) {
17
86
  });
18
87
  const onDeleteClick = useEvent(async () => {
19
88
  await context.callbacks.onDelete();
20
- closeDialog();
89
+ closeDeleteDialog();
90
+ });
91
+ const onConfirmCancelClick = useEvent(() => {
92
+ context.callbacks.onCancel();
93
+ closeCancelConfirmationDialog();
21
94
  });
22
95
  return /* @__PURE__ */ jsxs(Fragment, { children: [
23
- /* @__PURE__ */ jsxs(VStack, { className: "editor__property-editor", height: "full", gap: 5, align: "stretch", children: [
24
- /* @__PURE__ */ jsx(Box, { flex: 1, overflowY: "auto", children }),
25
- /* @__PURE__ */ jsx(
26
- ButtonRow,
27
- {
28
- canSave,
29
- showDeleteButton: context.mode === "update",
30
- onSave: onSaveClick,
31
- onDelete: openDialog,
32
- onCancel: context.callbacks.onCancel
33
- }
34
- )
35
- ] }),
96
+ /* @__PURE__ */ jsx(
97
+ ButtonRow,
98
+ {
99
+ canSave,
100
+ showDeleteButton: context.mode === "update",
101
+ onSave: onSaveClick,
102
+ onDelete: openDeleteDialog,
103
+ onCancel: openCancelDialog
104
+ }
105
+ ),
36
106
  /* @__PURE__ */ jsx(
37
107
  DeleteConfirmationDialog,
38
108
  {
39
- isOpen: dialogIsOpen,
109
+ isOpen: deleteDialogIsOpen,
40
110
  onDelete: onDeleteClick,
41
- onCancel: closeDialog
111
+ onCancel: closeDeleteDialog
112
+ }
113
+ ),
114
+ /* @__PURE__ */ jsx(
115
+ CancelConfirmationDialog,
116
+ {
117
+ isOpen: cancelDialogIsOpen,
118
+ onConfirmCancel: onConfirmCancelClick,
119
+ onAbortCancel: closeCancelConfirmationDialog
42
120
  }
43
121
  )
44
122
  ] });