@jupytergis/base 0.13.2 → 0.14.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 (116) hide show
  1. package/lib/commands/BaseCommandIDs.d.ts +14 -13
  2. package/lib/commands/BaseCommandIDs.js +14 -14
  3. package/lib/commands/index.js +528 -130
  4. package/lib/commands/operationCommands.d.ts +22 -0
  5. package/lib/commands/operationCommands.js +305 -0
  6. package/lib/constants.js +11 -9
  7. package/lib/dialogs/ProcessingFormDialog.d.ts +1 -1
  8. package/lib/dialogs/ProcessingFormDialog.js +2 -2
  9. package/lib/dialogs/layerBrowserDialog.d.ts +2 -0
  10. package/lib/dialogs/layerBrowserDialog.js +12 -5
  11. package/lib/dialogs/layerCreationFormDialog.d.ts +7 -0
  12. package/lib/dialogs/layerCreationFormDialog.js +10 -2
  13. package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.d.ts +2 -1
  14. package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.js +21 -19
  15. package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.d.ts +3 -1
  16. package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.js +13 -5
  17. package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +6 -4
  18. package/lib/dialogs/symbology/vector_layer/types/Categorized.js +7 -11
  19. package/lib/dialogs/symbology/vector_layer/types/Graduated.js +7 -10
  20. package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +7 -8
  21. package/lib/formbuilder/creationform.d.ts +8 -8
  22. package/lib/formbuilder/creationform.js +130 -85
  23. package/lib/formbuilder/editform.d.ts +1 -7
  24. package/lib/formbuilder/editform.js +64 -52
  25. package/lib/formbuilder/formselectors.d.ts +5 -4
  26. package/lib/formbuilder/index.d.ts +1 -1
  27. package/lib/formbuilder/index.js +1 -1
  28. package/lib/formbuilder/objectform/SchemaForm.d.ts +36 -0
  29. package/lib/formbuilder/objectform/SchemaForm.js +77 -0
  30. package/lib/formbuilder/objectform/StoryEditorForm.d.ts +3 -9
  31. package/lib/formbuilder/objectform/StoryEditorForm.js +20 -14
  32. package/lib/formbuilder/objectform/components/LayerSelect.js +3 -8
  33. package/lib/formbuilder/objectform/components/SegmentFormSymbology.js +23 -10
  34. package/lib/formbuilder/objectform/components/SourcePropertiesField.d.ts +7 -0
  35. package/lib/formbuilder/objectform/components/SourcePropertiesField.js +29 -0
  36. package/lib/formbuilder/objectform/components/StorySegmentReset.js +1 -1
  37. package/lib/formbuilder/objectform/fileselectorwidget.js +1 -1
  38. package/lib/formbuilder/objectform/layer/heatmapLayerForm.d.ts +3 -12
  39. package/lib/formbuilder/objectform/layer/heatmapLayerForm.js +87 -55
  40. package/lib/formbuilder/objectform/layer/hillshadeLayerForm.d.ts +3 -8
  41. package/lib/formbuilder/objectform/layer/hillshadeLayerForm.js +36 -10
  42. package/lib/formbuilder/objectform/layer/layerform.d.ts +7 -9
  43. package/lib/formbuilder/objectform/layer/layerform.js +33 -20
  44. package/lib/formbuilder/objectform/layer/storySegmentLayerForm.d.ts +3 -5
  45. package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +73 -29
  46. package/lib/formbuilder/objectform/layer/vectorlayerform.d.ts +3 -14
  47. package/lib/formbuilder/objectform/layer/vectorlayerform.js +36 -29
  48. package/lib/formbuilder/objectform/layer/webGlLayerForm.d.ts +3 -10
  49. package/lib/formbuilder/objectform/layer/webGlLayerForm.js +37 -13
  50. package/lib/formbuilder/objectform/process/dissolveProcessForm.d.ts +8 -18
  51. package/lib/formbuilder/objectform/process/dissolveProcessForm.js +68 -56
  52. package/lib/formbuilder/objectform/processingForm.d.ts +12 -0
  53. package/lib/formbuilder/objectform/processingForm.js +33 -0
  54. package/lib/formbuilder/objectform/schemaUtils.d.ts +16 -0
  55. package/lib/formbuilder/objectform/schemaUtils.js +59 -0
  56. package/lib/formbuilder/objectform/source/geojsonsource.d.ts +3 -19
  57. package/lib/formbuilder/objectform/source/geojsonsource.js +94 -53
  58. package/lib/formbuilder/objectform/source/geotiffsource.d.ts +3 -20
  59. package/lib/formbuilder/objectform/source/geotiffsource.js +73 -74
  60. package/lib/formbuilder/objectform/source/pathbasedsource.d.ts +3 -19
  61. package/lib/formbuilder/objectform/source/pathbasedsource.js +76 -75
  62. package/lib/formbuilder/objectform/source/sourceform.d.ts +7 -8
  63. package/lib/formbuilder/objectform/source/sourceform.js +28 -11
  64. package/lib/formbuilder/objectform/source/tilesourceform.d.ts +3 -7
  65. package/lib/formbuilder/objectform/source/tilesourceform.js +63 -53
  66. package/lib/formbuilder/objectform/useSchemaFormState.d.ts +48 -0
  67. package/lib/formbuilder/objectform/useSchemaFormState.js +35 -0
  68. package/lib/index.d.ts +0 -1
  69. package/lib/index.js +0 -1
  70. package/lib/keybindings.json +10 -10
  71. package/lib/mainview/mainView.d.ts +11 -7
  72. package/lib/mainview/mainView.js +63 -36
  73. package/lib/mainview/mainviewmodel.js +2 -2
  74. package/lib/menus.js +8 -8
  75. package/lib/panelview/components/layers.js +5 -2
  76. package/lib/panelview/objectproperties.js +2 -2
  77. package/lib/panelview/rightpanel.js +17 -2
  78. package/lib/panelview/story-maps/SpectaPanel.d.ts +15 -0
  79. package/lib/panelview/story-maps/SpectaPanel.js +35 -0
  80. package/lib/panelview/story-maps/StoryViewerPanel.d.ts +24 -9
  81. package/lib/panelview/story-maps/StoryViewerPanel.js +22 -268
  82. package/lib/panelview/story-maps/{PreviewModeSwitch.js → components/PreviewModeSwitch.js} +1 -1
  83. package/lib/panelview/story-maps/components/SpectaDesktopView.d.ts +21 -0
  84. package/lib/panelview/story-maps/components/SpectaDesktopView.js +49 -0
  85. package/lib/panelview/story-maps/components/SpectaMobileView.d.ts +17 -0
  86. package/lib/panelview/story-maps/{MobileSpectaPanel.js → components/SpectaMobileView.js} +8 -22
  87. package/lib/panelview/story-maps/{StoryNavBar.d.ts → components/StoryNavBar.d.ts} +1 -1
  88. package/lib/panelview/story-maps/{StoryNavBar.js → components/StoryNavBar.js} +2 -4
  89. package/lib/panelview/story-maps/hooks/useStoryMap.d.ts +39 -0
  90. package/lib/panelview/story-maps/hooks/useStoryMap.js +252 -0
  91. package/lib/processing/index.d.ts +2 -2
  92. package/lib/processing/index.js +62 -35
  93. package/lib/processing/processingCommands.d.ts +1 -1
  94. package/lib/processing/processingCommands.js +26 -6
  95. package/lib/shared/components/Collapsible.d.ts +6 -0
  96. package/lib/shared/components/Collapsible.js +26 -0
  97. package/lib/statusbar/SpectaPresentationProgressBar.d.ts +7 -0
  98. package/lib/statusbar/SpectaPresentationProgressBar.js +40 -0
  99. package/lib/toolbar/widget.js +4 -2
  100. package/lib/tools.d.ts +6 -0
  101. package/lib/tools.js +9 -0
  102. package/lib/types.d.ts +29 -2
  103. package/lib/widget.js +14 -2
  104. package/package.json +2 -4
  105. package/style/base.css +23 -1
  106. package/style/dialog.css +5 -0
  107. package/style/leftPanel.css +14 -37
  108. package/style/shared/button.css +0 -10
  109. package/style/shared/switch.css +8 -7
  110. package/style/spectaProgressBar.css +144 -0
  111. package/style/storyPanel.css +33 -0
  112. package/style/symbologyDialog.css +2 -2
  113. package/lib/formbuilder/objectform/baseform.d.ts +0 -91
  114. package/lib/formbuilder/objectform/baseform.js +0 -231
  115. package/lib/panelview/story-maps/MobileSpectaPanel.d.ts +0 -7
  116. /package/lib/panelview/story-maps/{PreviewModeSwitch.d.ts → components/PreviewModeSwitch.d.ts} +0 -0
@@ -2,65 +2,77 @@ import { Signal } from '@lumino/signaling';
2
2
  import * as React from 'react';
3
3
  import { deepCopy } from "../tools";
4
4
  import { getLayerTypeForm, getSourceTypeForm } from './formselectors';
5
+ function syncObjectProperties(model, id, properties) {
6
+ if (!id) {
7
+ return;
8
+ }
9
+ model.sharedModel.updateObjectParameters(id, properties);
10
+ }
5
11
  /**
6
12
  * Form for editing a source, a layer or both at the same time
7
13
  */
8
- export class EditForm extends React.Component {
9
- constructor() {
10
- super(...arguments);
11
- this.sourceFormChangedSignal = new Signal(this);
14
+ export function EditForm(props) {
15
+ const { layer: layerId, source: sourceId, formSchemaRegistry, model } = props;
16
+ const sourceFormChangedSignalRef = React.useRef(null);
17
+ if (!sourceFormChangedSignalRef.current) {
18
+ sourceFormChangedSignalRef.current = new Signal({});
12
19
  }
13
- async syncObjectProperties(id, properties) {
14
- if (!id) {
15
- return;
20
+ const sourceFormChangedSignal = sourceFormChangedSignalRef.current;
21
+ let layer;
22
+ let LayerForm;
23
+ let layerData;
24
+ let layerSchema;
25
+ if (layerId) {
26
+ layer = model.getLayer(layerId);
27
+ if (!layer) {
28
+ return null;
29
+ }
30
+ LayerForm = getLayerTypeForm(layer.type || 'RasterLayer');
31
+ layerData = deepCopy(layer.parameters || {});
32
+ layerSchema = deepCopy(formSchemaRegistry.getSchemas().get(layer.type));
33
+ if (!layerSchema) {
34
+ console.error(`Cannot find schema for ${layer.type}`);
35
+ return null;
16
36
  }
17
- this.props.model.sharedModel.updateObjectParameters(id, properties);
18
37
  }
19
- render() {
20
- let layerSchema = undefined;
21
- let LayerForm = undefined;
22
- let layerData = undefined;
23
- let layer = undefined;
24
- if (this.props.layer) {
25
- layer = this.props.model.getLayer(this.props.layer);
26
- if (!layer) {
27
- return;
28
- }
29
- LayerForm = getLayerTypeForm((layer === null || layer === void 0 ? void 0 : layer.type) || 'RasterLayer');
30
- layerData = deepCopy((layer === null || layer === void 0 ? void 0 : layer.parameters) || {});
31
- layerSchema = deepCopy(this.props.formSchemaRegistry.getSchemas().get(layer.type));
32
- if (!layerSchema) {
33
- console.error(`Cannot find schema for ${layer.type}`);
34
- return;
35
- }
38
+ else {
39
+ layer = undefined;
40
+ LayerForm = undefined;
41
+ layerData = undefined;
42
+ layerSchema = undefined;
43
+ }
44
+ let source;
45
+ let SourceForm;
46
+ let sourceData;
47
+ let sourceSchema;
48
+ if (sourceId) {
49
+ source = model.getSource(sourceId);
50
+ if (!source) {
51
+ return null;
36
52
  }
37
- let sourceSchema = undefined;
38
- let SourceForm = undefined;
39
- let sourceData = undefined;
40
- let source = undefined;
41
- if (this.props.source) {
42
- source = this.props.model.getSource(this.props.source);
43
- if (!source) {
44
- return;
45
- }
46
- SourceForm = getSourceTypeForm((source === null || source === void 0 ? void 0 : source.type) || 'RasterSource');
47
- sourceData = deepCopy((source === null || source === void 0 ? void 0 : source.parameters) || {});
48
- sourceSchema = deepCopy(this.props.formSchemaRegistry.getSchemas().get(source.type));
49
- if (!sourceSchema) {
50
- console.error(`Cannot find schema for ${source.type}`);
51
- return;
52
- }
53
+ SourceForm = getSourceTypeForm(source.type || 'RasterSource');
54
+ sourceData = deepCopy(source.parameters || {});
55
+ sourceSchema = deepCopy(formSchemaRegistry.getSchemas().get(source.type));
56
+ if (!sourceSchema) {
57
+ console.error(`Cannot find schema for ${source.type}`);
58
+ return null;
53
59
  }
54
- return (React.createElement("div", null,
55
- this.props.layer && LayerForm && (React.createElement("div", null,
56
- React.createElement("h3", { style: { paddingLeft: '5px' } }, "Layer Properties"),
57
- React.createElement(LayerForm, { key: `${this.props.layer}-${source === null || source === void 0 ? void 0 : source.type}`, formContext: "update", sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource', model: this.props.model, filePath: this.props.model.filePath, schema: layerSchema, sourceData: layerData, syncData: (properties) => {
58
- this.syncObjectProperties(this.props.layer, properties);
59
- } }))),
60
- this.props.source && SourceForm && (React.createElement("div", null,
61
- React.createElement("h3", { style: { paddingLeft: '5px' } }, "Source Properties"),
62
- React.createElement(SourceForm, { key: `${this.props.source}-${layer === null || layer === void 0 ? void 0 : layer.type}`, formContext: "update", model: this.props.model, filePath: this.props.model.filePath, schema: sourceSchema, sourceData: sourceData, syncData: (properties) => {
63
- this.syncObjectProperties(this.props.source, properties);
64
- }, formChangedSignal: this.sourceFormChangedSignal, sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource' })))));
65
60
  }
61
+ else {
62
+ source = undefined;
63
+ SourceForm = undefined;
64
+ sourceData = undefined;
65
+ sourceSchema = undefined;
66
+ }
67
+ return (React.createElement("div", null,
68
+ layerId && LayerForm && layerSchema && layerData !== undefined && (React.createElement("div", null,
69
+ React.createElement("h3", { style: { paddingLeft: '5px' } }, "Layer Properties"),
70
+ React.createElement(LayerForm, { key: `${layerId}-${source === null || source === void 0 ? void 0 : source.type}`, formContext: "update", sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource', model: model, filePath: model.filePath, schema: layerSchema, sourceData: layerData, syncData: (properties) => {
71
+ syncObjectProperties(model, layerId, properties);
72
+ }, formSchemaRegistry: formSchemaRegistry }))),
73
+ sourceId && SourceForm && sourceSchema && sourceData !== undefined && (React.createElement("div", null,
74
+ React.createElement("h3", { style: { paddingLeft: '5px' } }, "Source Properties"),
75
+ React.createElement(SourceForm, { key: `${sourceId}-${layer === null || layer === void 0 ? void 0 : layer.type}`, formContext: "update", model: model, filePath: model.filePath, schema: sourceSchema, sourceData: sourceData, syncData: (properties) => {
76
+ syncObjectProperties(model, sourceId, properties);
77
+ }, formChangedSignal: sourceFormChangedSignal, sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource', formSchemaRegistry: formSchemaRegistry })))));
66
78
  }
@@ -1,5 +1,6 @@
1
1
  import { LayerType, SourceType } from '@jupytergis/schema';
2
- import { LayerPropertiesForm } from './objectform/layer';
3
- import { SourcePropertiesForm } from './objectform/source';
4
- export declare function getLayerTypeForm(layerType: LayerType): typeof LayerPropertiesForm;
5
- export declare function getSourceTypeForm(sourceType: SourceType): typeof SourcePropertiesForm;
2
+ import * as React from 'react';
3
+ import type { ILayerProps } from './objectform/layer/layerform';
4
+ import type { ISourceFormProps } from './objectform/source/sourceform';
5
+ export declare function getLayerTypeForm(layerType: LayerType): React.ComponentType<ILayerProps>;
6
+ export declare function getSourceTypeForm(sourceType: SourceType): React.ComponentType<ISourceFormProps>;
@@ -1,4 +1,4 @@
1
- export * from './objectform/baseform';
1
+ export * from './objectform/SchemaForm';
2
2
  export * from './objectform/source';
3
3
  export * from './objectform/layer';
4
4
  export * from './creationform';
@@ -1,4 +1,4 @@
1
- export * from './objectform/baseform';
1
+ export * from './objectform/SchemaForm';
2
2
  export * from './objectform/source';
3
3
  export * from './objectform/layer';
4
4
  export * from './creationform';
@@ -0,0 +1,36 @@
1
+ import type { Signal } from '@lumino/signaling';
2
+ import { RegistryFieldsType, UiSchema } from '@rjsf/utils';
3
+ import React from 'react';
4
+ import { IDict, type IJupyterGISFormContext } from "../../types";
5
+ export interface ISchemaFormProps {
6
+ /** JSON Schema for the form. */
7
+ schema: IDict;
8
+ /** Current form data (controlled). */
9
+ formData: IDict | undefined;
10
+ /** Called when form data changes. */
11
+ onChange: (data: IDict) => void;
12
+ /** Called when form is submitted (e.g. submit button or Enter). */
13
+ onSubmit: (data: IDict) => void;
14
+ /** Context for custom fields (e.g. LayerSelect) that need model and formData. */
15
+ formContext: IJupyterGISFormContext;
16
+ /** Path to the file; used for data-path on the panel. */
17
+ filePath?: string;
18
+ /** Enable live validation. Default true. */
19
+ liveValidate?: boolean;
20
+ /** Additional custom fields to register (merged with opacity, layerSelect). */
21
+ additionalFields?: RegistryFieldsType;
22
+ /** Optional pre-built uiSchema (e.g. from processBaseSchema). When provided, merged with additionalProperties hidden field. */
23
+ uiSchema?: UiSchema;
24
+ /** Optional extra validation errors (RJSF extraErrors format). */
25
+ extraErrors?: IDict;
26
+ /** Optional ref to the hidden submit button; when provided, parent can trigger submit (e.g. on ok signal). */
27
+ submitButtonRef?: React.MutableRefObject<HTMLButtonElement | null>;
28
+ /** When provided, emit(true) when there are validation/extra errors, emit(false) when clear (e.g. to disable dialog OK). */
29
+ formErrorSignal?: Signal<any, boolean>;
30
+ }
31
+ /**
32
+ * Renders a JSON Schema form (RJSF) for layer, source, and other object properties.
33
+ * The parent is responsible for state (formData), syncing to the model, and dialog
34
+ * behaviour; this component only renders the form and calls onChange/onSubmit.
35
+ */
36
+ export declare function SchemaForm(props: ISchemaFormProps): React.ReactElement;
@@ -0,0 +1,77 @@
1
+ import { FormComponent } from '@jupyterlab/ui-components';
2
+ import validatorAjv8 from '@rjsf/validator-ajv8';
3
+ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
4
+ import { LayerSelect } from './components/LayerSelect';
5
+ import OpacitySlider from './components/OpacitySlider';
6
+ const defaultFields = {
7
+ opacity: OpacitySlider,
8
+ layerSelect: LayerSelect,
9
+ };
10
+ /** True if extraErrors has a non-empty __errors array. */
11
+ function hasExtraErrors(extraErrors) {
12
+ if (!extraErrors || typeof extraErrors !== 'object') {
13
+ return false;
14
+ }
15
+ for (const key of Object.keys(extraErrors)) {
16
+ const value = extraErrors[key];
17
+ const errorList = value && typeof value === 'object'
18
+ ? value.__errors
19
+ : undefined;
20
+ if (Array.isArray(errorList) && errorList.length > 0) {
21
+ return true;
22
+ }
23
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
24
+ if (hasExtraErrors(value)) {
25
+ return true;
26
+ }
27
+ }
28
+ }
29
+ return false;
30
+ }
31
+ /**
32
+ * Renders a JSON Schema form (RJSF) for layer, source, and other object properties.
33
+ * The parent is responsible for state (formData), syncing to the model, and dialog
34
+ * behaviour; this component only renders the form and calls onChange/onSubmit.
35
+ */
36
+ export function SchemaForm(props) {
37
+ const { schema, formData, onChange, onSubmit, formContext, filePath = '', liveValidate = true, additionalFields, uiSchema: uiSchemaProp, extraErrors, submitButtonRef, formErrorSignal, } = props;
38
+ const schemaWithExtra = useMemo(() => (Object.assign(Object.assign({}, schema), { additionalProperties: true })), [schema]);
39
+ const defaultUiSchema = useMemo(() => ({
40
+ additionalProperties: {
41
+ 'ui:label': false,
42
+ classNames: 'jGIS-hidden-field',
43
+ },
44
+ }), []);
45
+ const uiSchema = useMemo(() => uiSchemaProp ? Object.assign(Object.assign({}, defaultUiSchema), uiSchemaProp) : defaultUiSchema, [uiSchemaProp, defaultUiSchema]);
46
+ const fields = useMemo(() => (Object.assign(Object.assign({}, defaultFields), additionalFields)), [additionalFields]);
47
+ const contextForForm = formContext;
48
+ useEffect(() => {
49
+ if (formErrorSignal) {
50
+ formErrorSignal.emit(hasExtraErrors(extraErrors !== null && extraErrors !== void 0 ? extraErrors : undefined));
51
+ }
52
+ }, [formErrorSignal, extraErrors]);
53
+ const handleChange = useCallback((e) => {
54
+ var _a;
55
+ onChange(((_a = e.formData) !== null && _a !== void 0 ? _a : {}));
56
+ }, [onChange]);
57
+ const handleSubmit = useCallback((e) => {
58
+ var _a;
59
+ onSubmit(((_a = e.formData) !== null && _a !== void 0 ? _a : {}));
60
+ }, [onSubmit]);
61
+ const handleKeyUp = useCallback((e, submitRef) => {
62
+ var _a;
63
+ if (e.key === 'Enter') {
64
+ e.preventDefault();
65
+ (_a = submitRef.current) === null || _a === void 0 ? void 0 : _a.click();
66
+ }
67
+ }, []);
68
+ const submitRef = useRef(null);
69
+ return (React.createElement("div", { className: "jGIS-property-panel", "data-path": filePath },
70
+ React.createElement("div", { className: "jGIS-property-outer", onKeyUp: e => handleKeyUp(e, submitRef) },
71
+ React.createElement(FormComponent, Object.assign({ schema: schemaWithExtra, uiSchema: uiSchema, formData: formData !== null && formData !== void 0 ? formData : {}, formContext: contextForForm, onChange: handleChange, onSubmit: handleSubmit, validator: validatorAjv8, fields: fields, liveValidate: liveValidate, extraErrors: extraErrors, children: React.createElement("button", { ref: el => {
72
+ submitRef.current = el;
73
+ if (submitButtonRef) {
74
+ submitButtonRef.current = el;
75
+ }
76
+ }, type: "submit", style: { display: 'none' } }) }, {})))));
77
+ }
@@ -1,9 +1,3 @@
1
- import { IDict } from '@jupytergis/schema';
2
- import { RJSFSchema, UiSchema } from '@rjsf/utils';
3
- import { BaseForm } from './baseform';
4
- /**
5
- * The form to modify story map properties.
6
- */
7
- export declare class StoryEditorPropertiesForm extends BaseForm {
8
- protected processSchema(data: IDict<any> | undefined, schema: RJSFSchema, uiSchema: UiSchema): void;
9
- }
1
+ import React from 'react';
2
+ import type { IBaseFormProps } from "../../types";
3
+ export declare function StoryEditorPropertiesForm(props: IBaseFormProps): React.ReactElement | null;
@@ -1,16 +1,22 @@
1
- import { BaseForm } from './baseform';
2
- /**
3
- * The form to modify story map properties.
4
- */
5
- export class StoryEditorPropertiesForm extends BaseForm {
6
- processSchema(data, schema, uiSchema) {
7
- super.processSchema(data, schema, uiSchema);
8
- this.removeFormEntry('storySegments', data, schema, uiSchema);
9
- uiSchema.presentationBgColor = {
10
- 'ui:widget': 'color',
11
- };
12
- uiSchema.presentationTextColor = {
13
- 'ui:widget': 'color',
14
- };
1
+ import React, { useMemo } from 'react';
2
+ import { deepCopy } from "../../tools";
3
+ import { SchemaForm } from './SchemaForm';
4
+ import { processBaseSchema, removeFormEntry } from './schemaUtils';
5
+ import { useSchemaFormState } from './useSchemaFormState';
6
+ export function StoryEditorPropertiesForm(props) {
7
+ const { schema: schemaProp, sourceData, syncData, model, filePath, formContext, cancel, } = props;
8
+ const { formData, schema, formContextValue, hasSchema, handleChangeBase, handleSubmitBase, } = useSchemaFormState({ sourceData, schemaProp, model, syncData, cancel });
9
+ const uiSchema = useMemo(() => {
10
+ const builtUiSchema = {};
11
+ const dataCopy = deepCopy(formData);
12
+ removeFormEntry('storySegments', dataCopy, schema, builtUiSchema);
13
+ processBaseSchema(dataCopy, schema, builtUiSchema, formContext, removeFormEntry);
14
+ builtUiSchema.presentationBgColor = { 'ui:widget': 'color' };
15
+ builtUiSchema.presentationTextColor = { 'ui:widget': 'color' };
16
+ return builtUiSchema;
17
+ }, [schema, formData, formContext]);
18
+ if (!hasSchema) {
19
+ return null;
15
20
  }
21
+ return (React.createElement(SchemaForm, { schema: schema, formData: formData, onChange: handleChangeBase, onSubmit: handleSubmitBase, formContext: formContextValue, filePath: filePath, uiSchema: uiSchema }));
16
22
  }
@@ -1,10 +1,5 @@
1
1
  import React from 'react';
2
- function extractlayerOverrideIndex(idSchema) {
3
- var _a;
4
- const id = (_a = idSchema === null || idSchema === void 0 ? void 0 : idSchema.$id) !== null && _a !== void 0 ? _a : '';
5
- const match = id.match(/layerOverride_(\d+)/);
6
- return match ? parseInt(match[1], 10) : undefined;
7
- }
2
+ import { extractLayerOverrideIndex } from "../../../tools";
8
3
  /**
9
4
  * Simple select populated with layers (valid types only).
10
5
  * Used as the targetLayer field inside layerOverride array items.
@@ -15,7 +10,7 @@ export function LayerSelect(props) {
15
10
  const context = formContext;
16
11
  const model = context === null || context === void 0 ? void 0 : context.model;
17
12
  const fullFormData = (_a = context === null || context === void 0 ? void 0 : context.formData) !== null && _a !== void 0 ? _a : formData;
18
- const arrayIndex = extractlayerOverrideIndex(idSchema !== null && idSchema !== void 0 ? idSchema : {});
13
+ const arrayIndex = extractLayerOverrideIndex(idSchema !== null && idSchema !== void 0 ? idSchema : {});
19
14
  const value = arrayIndex !== undefined && ((_b = fullFormData === null || fullFormData === void 0 ? void 0 : fullFormData.layerOverride) === null || _b === void 0 ? void 0 : _b[arrayIndex])
20
15
  ? ((_c = fullFormData.layerOverride[arrayIndex].targetLayer) !== null && _c !== void 0 ? _c : '')
21
16
  : '';
@@ -32,7 +27,7 @@ export function LayerSelect(props) {
32
27
  .filter(id => id !== undefined && id !== '')
33
28
  .filter(id => id !== currentTargetLayer));
34
29
  const availableLayers = model.getLayers();
35
- const optionsList = Object.entries(availableLayers).filter(([layerId]) => !usedTargetLayerIds.has(layerId));
30
+ const optionsList = Object.entries(availableLayers).filter(([layerId, layer]) => !usedTargetLayerIds.has(layerId) && layer.type !== 'StorySegmentLayer');
36
31
  const handleChange = (e) => {
37
32
  const newValue = e.target.value;
38
33
  onChange(newValue === '' ? undefined : newValue);
@@ -1,8 +1,10 @@
1
+ import { ChevronRightIcon } from 'lucide-react';
1
2
  import React from 'react';
2
3
  import { SymbologyWidget } from "../../../dialogs/symbology/symbologyDialog";
3
4
  import { Button } from "../../../shared/components/Button";
5
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "../../../shared/components/Collapsible";
4
6
  import { GlobalStateDbManager } from "../../../store";
5
- import { SYMBOLOGY_VALID_LAYER_TYPES } from "../../../types";
7
+ import { SYMBOLOGY_VALID_LAYER_TYPES, } from "../../../types";
6
8
  const SELECTION_SETTLE_MS = 100;
7
9
  function LayerOverrideItem({ item, formContext }) {
8
10
  var _a, _b;
@@ -46,14 +48,25 @@ function LayerOverrideItem({ item, formContext }) {
46
48
  item.hasRemove && (React.createElement(Button, { variant: "destructive", onClick: item.onDropIndexClick(item.index), title: "Remove item" }, "Remove")))));
47
49
  }
48
50
  export function ArrayFieldTemplate(props) {
51
+ const { formData, formContext } = props;
52
+ const model = formContext.model;
49
53
  return (React.createElement(React.Fragment, null,
50
- React.createElement("div", null, props.title),
51
- React.createElement("div", { style: {
52
- display: 'flex',
53
- flexDirection: 'column',
54
- gap: '1rem',
55
- alignItems: 'center',
56
- } },
57
- props.items.map(item => (React.createElement(LayerOverrideItem, { key: item.key, item: item, formContext: props.formContext }))),
58
- props.canAdd && (React.createElement(Button, { onClick: props.onAddClick }, "Add Layer Override")))));
54
+ React.createElement("div", { style: { paddingBottom: '1rem' } }, "Symbology Overrides"),
55
+ React.createElement("div", { className: "jgis-symbology-override-list" }, props.items.map(item => {
56
+ var _a, _b;
57
+ const overrideData = formData === null || formData === void 0 ? void 0 : formData[item.index];
58
+ const layerName = (_b = (_a = model.getLayer(overrideData === null || overrideData === void 0 ? void 0 : overrideData.targetLayer)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'Layer';
59
+ return (React.createElement(Collapsible, { key: item.key },
60
+ React.createElement(CollapsibleTrigger, { asChild: true },
61
+ React.createElement("div", { className: "jgis-symbology-override-collapsible-trigger" },
62
+ React.createElement(Button, { size: "icon-sm", variant: "icon", className: "jgis-rotate-90 jgis-bg-transparent" },
63
+ React.createElement(ChevronRightIcon, null)),
64
+ React.createElement("span", null,
65
+ layerName,
66
+ " Override"))),
67
+ React.createElement(CollapsibleContent, null,
68
+ React.createElement(LayerOverrideItem, { key: item.key, item: item, formContext: props.formContext }))));
69
+ })),
70
+ props.canAdd && (React.createElement("div", { className: "jgis-center-content", style: { paddingTop: '1rem' } },
71
+ React.createElement(Button, { onClick: props.onAddClick }, "Add Layer Override")))));
59
72
  }
@@ -0,0 +1,7 @@
1
+ import { FieldProps } from '@rjsf/core';
2
+ import * as React from 'react';
3
+ /**
4
+ * RJSF custom field for layerOverride[].sourceProperties: renders the
5
+ * appropriate source form for the target layer's source type.
6
+ */
7
+ export declare function SourcePropertiesField(props: FieldProps): React.ReactElement;
@@ -0,0 +1,29 @@
1
+ import * as React from 'react';
2
+ import { deepCopy, extractLayerOverrideIndex } from "../../../tools";
3
+ import { getSourceTypeForm } from '../../formselectors';
4
+ /**
5
+ * RJSF custom field for layerOverride[].sourceProperties: renders the
6
+ * appropriate source form for the target layer's source type.
7
+ */
8
+ export function SourcePropertiesField(props) {
9
+ var _a, _b, _c, _d, _e, _f, _g, _h;
10
+ const context = props.formContext;
11
+ const fullFormData = context === null || context === void 0 ? void 0 : context.formData;
12
+ const formSchemaRegistry = context === null || context === void 0 ? void 0 : context.formSchemaRegistry;
13
+ // const docManager = context?.docManager;
14
+ const index = extractLayerOverrideIndex((_a = props.idSchema) !== null && _a !== void 0 ? _a : {});
15
+ const model = (_b = props.formContext) === null || _b === void 0 ? void 0 : _b.model;
16
+ const layerId = (_d = (_c = fullFormData === null || fullFormData === void 0 ? void 0 : fullFormData.layerOverride) === null || _c === void 0 ? void 0 : _c[index !== null && index !== void 0 ? index : 0]) === null || _d === void 0 ? void 0 : _d.targetLayer;
17
+ const layer = model === null || model === void 0 ? void 0 : model.getLayer(layerId);
18
+ const sourceID = (_e = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _e === void 0 ? void 0 : _e.source;
19
+ const source = model === null || model === void 0 ? void 0 : model.getSource(sourceID);
20
+ /* Use form value so edits persist; fall back to live source for initial display */
21
+ const sourceProperties = (_f = props.formData) !== null && _f !== void 0 ? _f : source === null || source === void 0 ? void 0 : source.parameters;
22
+ const sourceSchema = (source === null || source === void 0 ? void 0 : source.type) && formSchemaRegistry
23
+ ? deepCopy(formSchemaRegistry.getSchemas().get(source.type))
24
+ : undefined;
25
+ const SourceForm = getSourceTypeForm((_g = source === null || source === void 0 ? void 0 : source.type) !== null && _g !== void 0 ? _g : 'GeoJSONSource');
26
+ return (React.createElement(React.Fragment, null,
27
+ React.createElement("div", { id: "jgis-source-properties-field" }, "Source Parameters"),
28
+ React.createElement(SourceForm, { formContext: "update", model: model, filePath: model === null || model === void 0 ? void 0 : model.filePath, schema: sourceSchema, sourceData: sourceProperties !== null && sourceProperties !== void 0 ? sourceProperties : undefined, syncData: (properties) => props.onChange(properties), sourceType: (_h = source === null || source === void 0 ? void 0 : source.type) !== null && _h !== void 0 ? _h : 'GeoJSONSource', formSchemaRegistry: formSchemaRegistry })));
29
+ }
@@ -16,7 +16,7 @@ function StorySegmentReset({ model, layerId }) {
16
16
  extent }) });
17
17
  model.sharedModel.updateLayer(layerId, updatedLayer);
18
18
  };
19
- return (React.createElement("div", null,
19
+ return (React.createElement("div", { className: "jgis-center-content" },
20
20
  React.createElement(Button, { title: "Set story segment to current viewport", onClick: handleSetStorySegmentToCurrentView },
21
21
  React.createElement(LabIcon.resolveReact, { icon: targetWithCenterIcon, className: "jp-gis-layerIcon", tag: "span" }),
22
22
  "Set Story Segment Extent")));
@@ -80,7 +80,7 @@ export const FileSelectorWidget = props => {
80
80
  };
81
81
  return (React.createElement("div", null,
82
82
  React.createElement("div", { className: "file-container" },
83
- React.createElement("button", { className: "jp-mod-styled", onClick: handleBrowseServerFiles }, "Browse Server Files"),
83
+ React.createElement("button", { type: "button", className: "jp-mod-styled", onClick: handleBrowseServerFiles }, "Browse Server Files"),
84
84
  React.createElement("p", null, serverFilePath || '')),
85
85
  React.createElement("div", null,
86
86
  React.createElement("h3", { className: "jp-FormGroup-fieldLabel jp-FormGroup-contentItem" }, "Or enter external URL"),
@@ -1,12 +1,3 @@
1
- import { IDict, IHeatmapLayer } from '@jupytergis/schema';
2
- import { IChangeEvent, ISubmitEvent } from '@rjsf/core';
3
- import { ILayerProps, LayerPropertiesForm } from './layerform';
4
- export declare class HeatmapLayerPropertiesForm extends LayerPropertiesForm {
5
- protected currentFormData: IHeatmapLayer;
6
- private features;
7
- constructor(props: ILayerProps);
8
- protected onFormSubmit(e: ISubmitEvent<any>): void;
9
- protected onFormChange(e: IChangeEvent): void;
10
- protected processSchema(data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
11
- private fetchFeatureNames;
12
- }
1
+ import React from 'react';
2
+ import type { ILayerProps } from './layerform';
3
+ export declare function HeatmapLayerPropertiesForm(props: ILayerProps): React.ReactElement | null;