@jupytergis/base 0.12.0 → 0.12.2

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 (55) hide show
  1. package/lib/constants.d.ts +3 -2
  2. package/lib/dialogs/layerBrowserDialog.d.ts +3 -3
  3. package/lib/dialogs/layerBrowserDialog.js +9 -10
  4. package/lib/formbuilder/objectform/StoryEditorForm.js +19 -2
  5. package/lib/mainview/mainView.d.ts +8 -2
  6. package/lib/mainview/mainView.js +40 -11
  7. package/lib/mainview/mainviewwidget.js +2 -2
  8. package/lib/panelview/leftpanel.d.ts +2 -1
  9. package/lib/panelview/leftpanel.js +46 -29
  10. package/lib/panelview/rightpanel.d.ts +2 -1
  11. package/lib/panelview/rightpanel.js +13 -18
  12. package/lib/panelview/story-maps/MobileSpectaPanel.d.ts +7 -0
  13. package/lib/panelview/story-maps/MobileSpectaPanel.js +114 -0
  14. package/lib/panelview/story-maps/StoryNavBar.d.ts +3 -2
  15. package/lib/panelview/story-maps/StoryNavBar.js +18 -6
  16. package/lib/panelview/story-maps/StoryViewerPanel.d.ts +10 -0
  17. package/lib/panelview/story-maps/StoryViewerPanel.js +44 -18
  18. package/lib/panelview/story-maps/components/StoryImageSection.d.ts +2 -7
  19. package/lib/panelview/story-maps/components/StoryImageSection.js +2 -4
  20. package/lib/panelview/story-maps/components/StorySubtitleSection.d.ts +2 -6
  21. package/lib/panelview/story-maps/components/StorySubtitleSection.js +2 -4
  22. package/lib/panelview/story-maps/components/StoryTitleSection.d.ts +2 -7
  23. package/lib/panelview/story-maps/components/StoryTitleSection.js +2 -3
  24. package/lib/shared/components/Button.js +2 -2
  25. package/lib/shared/components/Calendar.js +0 -1
  26. package/lib/shared/components/Checkbox.d.ts +1 -1
  27. package/lib/shared/components/Checkbox.js +1 -1
  28. package/lib/shared/components/Dialog.d.ts +1 -1
  29. package/lib/shared/components/Dialog.js +1 -1
  30. package/lib/shared/components/Drawer.d.ts +13 -0
  31. package/lib/shared/components/Drawer.js +59 -0
  32. package/lib/shared/components/DropdownMenu.d.ts +1 -1
  33. package/lib/shared/components/DropdownMenu.js +1 -1
  34. package/lib/shared/components/Popover.d.ts +1 -1
  35. package/lib/shared/components/Popover.js +1 -1
  36. package/lib/shared/components/RadioGroup.d.ts +1 -1
  37. package/lib/shared/components/RadioGroup.js +1 -1
  38. package/lib/shared/components/Sheet.d.ts +15 -0
  39. package/lib/shared/components/Sheet.js +64 -0
  40. package/lib/shared/components/Switch.d.ts +1 -1
  41. package/lib/shared/components/Switch.js +1 -1
  42. package/lib/shared/components/Tabs.d.ts +1 -1
  43. package/lib/shared/components/Tabs.js +1 -1
  44. package/lib/shared/components/ToggleGroup.d.ts +1 -1
  45. package/lib/shared/components/ToggleGroup.js +1 -1
  46. package/lib/shared/hooks/useMediaQuery.d.ts +9 -0
  47. package/lib/shared/hooks/useMediaQuery.js +32 -0
  48. package/lib/tools.d.ts +2 -1
  49. package/lib/tools.js +33 -38
  50. package/package.json +5 -13
  51. package/style/base.css +23 -8
  52. package/style/shared/drawer.css +154 -0
  53. package/style/shared/sheet.css +258 -0
  54. package/style/shared/tabs.css +0 -6
  55. package/style/storyPanel.css +39 -9
@@ -1,9 +1,10 @@
1
- import { IDict } from '@jupytergis/schema';
1
+ import { ProcessingCommandIDs } from '@jupytergis/schema';
2
2
  import { LabIcon } from '@jupyterlab/ui-components';
3
+ import * as BaseCommandIDs from './commands/BaseCommandIDs';
3
4
  /**
4
5
  * The command IDs.
5
6
  */
6
- export declare const CommandIDs: IDict;
7
+ export declare const CommandIDs: typeof BaseCommandIDs & typeof ProcessingCommandIDs;
7
8
  interface IRegisteredIcon {
8
9
  icon?: LabIcon;
9
10
  iconClass?: string;
@@ -1,11 +1,11 @@
1
- import { IJGISFormSchemaRegistry, IJupyterGISModel, IRasterLayerGalleryEntry } from '@jupytergis/schema';
1
+ import { IJGISFormSchemaRegistry, IJupyterGISModel, ILayerGalleryEntry } from '@jupytergis/schema';
2
2
  import { Dialog } from '@jupyterlab/apputils';
3
3
  import { PromiseDelegate } from '@lumino/coreutils';
4
4
  import { Signal } from '@lumino/signaling';
5
5
  import React from 'react';
6
6
  interface ILayerBrowserDialogProps {
7
7
  model: IJupyterGISModel;
8
- registry: IRasterLayerGalleryEntry[];
8
+ registry: ILayerGalleryEntry[];
9
9
  formSchemaRegistry: IJGISFormSchemaRegistry;
10
10
  okSignalPromise: PromiseDelegate<Signal<Dialog<any>, number>>;
11
11
  cancel: () => void;
@@ -13,7 +13,7 @@ interface ILayerBrowserDialogProps {
13
13
  export declare const LayerBrowserComponent: React.FC<ILayerBrowserDialogProps>;
14
14
  export interface ILayerBrowserOptions {
15
15
  model: IJupyterGISModel;
16
- registry: IRasterLayerGalleryEntry[];
16
+ registry: ILayerGalleryEntry[];
17
17
  formSchemaRegistry: IJGISFormSchemaRegistry;
18
18
  }
19
19
  export declare class LayerBrowserWidget extends Dialog<boolean> {
@@ -5,14 +5,14 @@ import { PromiseDelegate, UUID } from '@lumino/coreutils';
5
5
  import { Signal } from '@lumino/signaling';
6
6
  import React, { useEffect, useState } from 'react';
7
7
  import { CreationFormWrapper } from './layerCreationFormDialog';
8
- import CUSTOM_RASTER_IMAGE from '../../rasterlayer_gallery/custom_raster.png';
8
+ import CUSTOM_RASTER_IMAGE from '../../layer_gallery/custom_raster.png';
9
9
  export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okSignalPromise, cancel, }) => {
10
10
  const [searchTerm, setSearchTerm] = useState('');
11
11
  const [activeLayers, setActiveLayers] = useState([]);
12
12
  const [selectedCategory, setSelectedCategory] = useState();
13
13
  const [creatingCustomRaster, setCreatingCustomRaster] = useState(false);
14
14
  const [galleryWithCategory, setGalleryWithCategory] = useState(registry);
15
- const providers = [...new Set(registry.map(item => item.source.provider))];
15
+ const providers = [...new Set(registry.map(item => item.provider))];
16
16
  const filteredGallery = galleryWithCategory.filter(item => item.name.toLowerCase().includes(searchTerm));
17
17
  useEffect(() => {
18
18
  model.sharedModel.layersChanged.connect(handleLayerChange);
@@ -37,7 +37,7 @@ export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okS
37
37
  selectedCategory === null || selectedCategory === void 0 ? void 0 : selectedCategory.classList.remove('jGIS-layer-browser-category-selected');
38
38
  const filteredGallery = sameAsOld
39
39
  ? registry
40
- : registry.filter(item => { var _a; return (_a = item.source.provider) === null || _a === void 0 ? void 0 : _a.includes(categoryTab.innerText); });
40
+ : registry.filter(item => { var _a; return (_a = item.provider) === null || _a === void 0 ? void 0 : _a.includes(categoryTab.innerText); });
41
41
  setGalleryWithCategory(filteredGallery);
42
42
  setSearchTerm('');
43
43
  setSelectedCategory(sameAsOld ? null : categoryTab);
@@ -52,15 +52,13 @@ export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okS
52
52
  const handleTileClick = (tile) => {
53
53
  const sourceId = UUID.uuid4();
54
54
  const sourceModel = {
55
- type: 'RasterSource',
55
+ type: tile.sourceType,
56
56
  name: tile.name,
57
- parameters: tile.source,
57
+ parameters: tile.sourceParameters,
58
58
  };
59
59
  const layerModel = {
60
- type: 'RasterLayer',
61
- parameters: {
62
- source: sourceId,
63
- },
60
+ type: tile.layerType,
61
+ parameters: Object.assign(Object.assign({}, tile.layerParameters), { source: sourceId }),
64
62
  visible: true,
65
63
  name: tile.name + ' Layer',
66
64
  };
@@ -113,7 +111,8 @@ export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okS
113
111
  React.createElement("div", { className: "jGIS-layer-browser-text-container" },
114
112
  React.createElement("div", { className: "jGIS-layer-browser-text-info" },
115
113
  React.createElement("h3", { className: "jGIS-layer-browser-text-header jGIS-layer-browser-text-general" }, tile.name)),
116
- React.createElement("p", { className: "jGIS-layer-browser-text-general jGIS-layer-browser-text-source" }, tile.source.attribution))))))));
114
+ React.createElement("div", null, tile.sourceType),
115
+ React.createElement("p", { className: "jGIS-layer-browser-text-general jGIS-layer-browser-text-source" }, tile.description))))))));
117
116
  };
118
117
  export class LayerBrowserWidget extends Dialog {
119
118
  constructor(options) {
@@ -1,3 +1,4 @@
1
+ import { getCssVarAsColor } from "../../tools";
1
2
  import { BaseForm } from './baseform';
2
3
  /**
3
4
  * The form to modify story map properties.
@@ -6,11 +7,27 @@ export class StoryEditorPropertiesForm extends BaseForm {
6
7
  processSchema(data, schema, uiSchema) {
7
8
  super.processSchema(data, schema, uiSchema);
8
9
  this.removeFormEntry('storySegments', data, schema, uiSchema);
9
- uiSchema.presentaionBgColor = {
10
+ uiSchema.presentationBgColor = {
10
11
  'ui:widget': 'color',
11
12
  };
12
- uiSchema.presentaionTextColor = {
13
+ uiSchema.presentationTextColor = {
13
14
  'ui:widget': 'color',
14
15
  };
16
+ // Set default values from theme CSS variables when not already in data
17
+ const schemaProps = schema.properties;
18
+ if ((schemaProps === null || schemaProps === void 0 ? void 0 : schemaProps.presentationBgColor) &&
19
+ (data === null || data === void 0 ? void 0 : data.presentationBgColor) === undefined) {
20
+ const defaultBg = getCssVarAsColor('--jp-layout-color0');
21
+ if (defaultBg) {
22
+ schemaProps.presentationBgColor.default = defaultBg;
23
+ }
24
+ }
25
+ if ((schemaProps === null || schemaProps === void 0 ? void 0 : schemaProps.presentationTextColor) &&
26
+ (data === null || data === void 0 ? void 0 : data.presentationTextColor) === undefined) {
27
+ const defaultText = getCssVarAsColor('--jp-ui-font-color0');
28
+ if (defaultText) {
29
+ schemaProps.presentationTextColor.default = defaultText;
30
+ }
31
+ }
15
32
  }
16
33
  }
@@ -1,4 +1,4 @@
1
- import { IAnnotation, IAnnotationModel, IDict, IJGISFilterItem, IJGISFormSchemaRegistry, IJGISLayer, IJGISSource } from '@jupytergis/schema';
1
+ import { IAnnotation, IAnnotationModel, IDict, IJGISFilterItem, IJGISFormSchemaRegistry, IJGISLayer, IJGISSource, IJupyterGISSettings } from '@jupytergis/schema';
2
2
  import { User } from '@jupyterlab/services';
3
3
  import { IStateDB } from '@jupyterlab/statedb';
4
4
  import { Layer } from 'ol/layer';
@@ -10,6 +10,8 @@ interface IProps {
10
10
  state?: IStateDB;
11
11
  formSchemaRegistry?: IJGISFormSchemaRegistry;
12
12
  annotationModel?: IAnnotationModel;
13
+ /** True when viewport matches (max-width: 768px). Injected by MainViewWithMediaQuery. */
14
+ isMobile?: boolean;
13
15
  }
14
16
  interface IStates {
15
17
  id: string;
@@ -31,6 +33,7 @@ interface IStates {
31
33
  }>;
32
34
  displayTemporalController: boolean;
33
35
  filterStates: IDict<IJGISFilterItem | undefined>;
36
+ jgisSettings: IJupyterGISSettings;
34
37
  isSpectaPresentation: boolean;
35
38
  }
36
39
  export declare class MainView extends React.Component<IProps, IStates> {
@@ -136,6 +139,7 @@ export declare class MainView extends React.Component<IProps, IStates> {
136
139
  removeLayer(id: string): void;
137
140
  private _onClientSharedStateChanged;
138
141
  private _onSharedOptionsChanged;
142
+ private _syncSettingsFromRegistry;
139
143
  private _onSettingsChanged;
140
144
  private updateOptions;
141
145
  private _onViewChanged;
@@ -222,4 +226,6 @@ export declare class MainView extends React.Component<IProps, IStates> {
222
226
  private _isSpectaPresentationInitialized;
223
227
  private _storyScrollHandler;
224
228
  }
225
- export {};
229
+ /** Thin wrapper that injects isMobile from useMediaQuery so MainView can use it in JSX. */
230
+ declare function MainViewWithMediaQuery(props: IProps): React.JSX.Element;
231
+ export { MainViewWithMediaQuery };
@@ -39,6 +39,7 @@ import * as React from 'react';
39
39
  import AnnotationFloater from "../annotations/components/AnnotationFloater";
40
40
  import { CommandIDs } from "../constants";
41
41
  import { LoadingOverlay } from "../shared/components/loading";
42
+ import useMediaQuery from "../shared/hooks/useMediaQuery";
42
43
  import StatusBar from "../statusbar/StatusBar";
43
44
  import { debounce, isLightTheme, loadFile, throttle } from "../tools";
44
45
  import CollaboratorPointers from './CollaboratorPointers';
@@ -47,6 +48,7 @@ import TemporalSlider from './TemporalSlider';
47
48
  import { hexToRgb } from '../dialogs/symbology/colorRampUtils';
48
49
  import { markerIcon } from '../icons';
49
50
  import { LeftPanel, RightPanel } from '../panelview';
51
+ import { MobileSpectaPanel } from '../panelview/story-maps/MobileSpectaPanel';
50
52
  import StoryViewerPanel from '../panelview/story-maps/StoryViewerPanel';
51
53
  export class MainView extends React.Component {
52
54
  constructor(props) {
@@ -528,8 +530,8 @@ export class MainView extends React.Component {
528
530
  return;
529
531
  }
530
532
  const story = this._model.getSelectedStory().story;
531
- const bgColor = story === null || story === void 0 ? void 0 : story.presentaionBgColor;
532
- const textColor = story === null || story === void 0 ? void 0 : story.presentaionTextColor;
533
+ const bgColor = story === null || story === void 0 ? void 0 : story.presentationBgColor;
534
+ const textColor = story === null || story === void 0 ? void 0 : story.presentationTextColor;
533
535
  // Set background color
534
536
  if (bgColor) {
535
537
  const rgb = hexToRgb(bgColor);
@@ -634,6 +636,9 @@ export class MainView extends React.Component {
634
636
  this._model.geolocationChanged.connect(this._handleGeolocationChanged, this);
635
637
  this._model.flyToGeometrySignal.connect(this.flyToGeometry, this);
636
638
  this._model.highlightFeatureSignal.connect(this.highlightFeatureOnMap, this);
639
+ Promise.resolve().then(() => {
640
+ this._syncSettingsFromRegistry();
641
+ });
637
642
  // Watch isIdentifying and clear the highlight when Identify Tool is turned off
638
643
  this._model.sharedModel.awareness.on('change', () => {
639
644
  var _a;
@@ -653,6 +658,7 @@ export class MainView extends React.Component {
653
658
  loadingErrors: [],
654
659
  displayTemporalController: false,
655
660
  filterStates: {},
661
+ jgisSettings: this._model.jgisSettings,
656
662
  isSpectaPresentation: false,
657
663
  };
658
664
  this._sources = [];
@@ -705,11 +711,11 @@ export class MainView extends React.Component {
705
711
  const fullScreen = new FullScreen({
706
712
  target: this.controlsToolbarRef.current || undefined,
707
713
  });
708
- this._zoomControl = new Zoom({
709
- target: this.controlsToolbarRef.current || undefined,
710
- });
711
714
  const controls = [scaleLine, fullScreen];
712
715
  if (this._model.jgisSettings.zoomButtonsEnabled) {
716
+ this._zoomControl = new Zoom({
717
+ target: this.controlsToolbarRef.current || undefined,
718
+ });
713
719
  controls.push(this._zoomControl);
714
720
  }
715
721
  if (this.divRef.current) {
@@ -1564,8 +1570,16 @@ export class MainView extends React.Component {
1564
1570
  this._isPositionInitialized = true;
1565
1571
  }
1566
1572
  }
1567
- _onSettingsChanged(sender, key) {
1568
- if (key !== 'zoomButtonsEnabled' || !this._Map) {
1573
+ async _syncSettingsFromRegistry() {
1574
+ const composite = this._model.jgisSettings;
1575
+ if (composite) {
1576
+ this.setState({ jgisSettings: composite });
1577
+ this._onSettingsChanged();
1578
+ }
1579
+ }
1580
+ _onSettingsChanged() {
1581
+ this.setState({ jgisSettings: this._model.jgisSettings });
1582
+ if (!this._Map) {
1569
1583
  return;
1570
1584
  }
1571
1585
  const enabled = this._model.jgisSettings.zoomButtonsEnabled;
@@ -1795,6 +1809,14 @@ export class MainView extends React.Component {
1795
1809
  if ((jgisLayer === null || jgisLayer === void 0 ? void 0 : jgisLayer.type) === 'StorySegmentLayer') {
1796
1810
  const layerParams = jgisLayer.parameters;
1797
1811
  const coords = getCenter(layerParams.extent);
1812
+ // Don't move map if we're already centered on the segment
1813
+ const viewCenter = this._Map.getView().getCenter();
1814
+ const centersEqual = viewCenter !== undefined &&
1815
+ Math.abs(viewCenter[0] - coords[0]) < 1e-9 &&
1816
+ Math.abs(viewCenter[1] - coords[1]) < 1e-9;
1817
+ if (centersEqual) {
1818
+ return;
1819
+ }
1798
1820
  this._flyToPosition({ x: coords[0], y: coords[1] }, layerParams.zoom, ((_c = layerParams.transition.time) !== null && _c !== void 0 ? _c : 1) * 1000, // seconds -> ms
1799
1821
  layerParams.transition.type);
1800
1822
  return;
@@ -2064,11 +2086,18 @@ export class MainView extends React.Component {
2064
2086
  height: '100%',
2065
2087
  } },
2066
2088
  React.createElement("div", { className: "jgis-panels-wrapper" }, !this.state.isSpectaPresentation ? (React.createElement(React.Fragment, null,
2067
- this._state && (React.createElement(LeftPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state })),
2068
- this._formSchemaRegistry && this._annotationModel && (React.createElement(RightPanel, { model: this._model, commands: this._mainViewModel.commands, formSchemaRegistry: this._formSchemaRegistry, annotationModel: this._annotationModel })))) : (React.createElement("div", { className: "jgis-specta-right-panel-container-mod jgis-right-panel-container" },
2089
+ this._state && (React.createElement(LeftPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state, settings: this.state.jgisSettings })),
2090
+ this._formSchemaRegistry && this._annotationModel && (React.createElement(RightPanel, { model: this._model, commands: this._mainViewModel.commands, formSchemaRegistry: this._formSchemaRegistry, annotationModel: this._annotationModel, settings: this.state.jgisSettings })))) : this.props.isMobile ? (React.createElement(MobileSpectaPanel, { model: this._model })) : (React.createElement("div", { className: "jgis-specta-right-panel-container-mod jgis-right-panel-container" },
2069
2091
  React.createElement("div", { ref: this.spectaContainerRef, className: "jgis-specta-story-panel-container" },
2070
- React.createElement(StoryViewerPanel, { ref: this.storyViewerPanelRef, model: this._model, isSpecta: this.state.isSpectaPresentation }))))),
2092
+ React.createElement(StoryViewerPanel, { ref: this.storyViewerPanelRef, model: this._model, isSpecta: this.state.isSpectaPresentation, className: "jgis-story-viewer-panel-specta-mod" }))))),
2071
2093
  React.createElement("div", { ref: this.controlsToolbarRef, className: "jgis-controls-toolbar" }))),
2072
- React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale }))));
2094
+ !this.state.isSpectaPresentation && (React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale })))));
2073
2095
  }
2074
2096
  }
2097
+ // ! TODO make mainview a modern react component instead of a class
2098
+ /** Thin wrapper that injects isMobile from useMediaQuery so MainView can use it in JSX. */
2099
+ function MainViewWithMediaQuery(props) {
2100
+ const isMobile = useMediaQuery('(max-width: 768px)');
2101
+ return React.createElement(MainView, Object.assign({}, props, { isMobile: isMobile }));
2102
+ }
2103
+ export { MainViewWithMediaQuery };
@@ -1,6 +1,6 @@
1
1
  import { ReactWidget } from '@jupyterlab/apputils';
2
2
  import * as React from 'react';
3
- import { MainView } from './mainView';
3
+ import { MainViewWithMediaQuery } from './mainView';
4
4
  export class JupyterGISMainViewPanel extends ReactWidget {
5
5
  /**
6
6
  * Construct a `JupyterGISPanel`.
@@ -12,6 +12,6 @@ export class JupyterGISMainViewPanel extends ReactWidget {
12
12
  this._options = options;
13
13
  }
14
14
  render() {
15
- return (React.createElement(MainView, { state: this._state, viewModel: this._options.mainViewModel, formSchemaRegistry: this._options.formSchemaRegistry, annotationModel: this._options.annotationModel }));
15
+ return (React.createElement(MainViewWithMediaQuery, { state: this._state, viewModel: this._options.mainViewModel, formSchemaRegistry: this._options.formSchemaRegistry, annotationModel: this._options.annotationModel }));
16
16
  }
17
17
  }
@@ -1,4 +1,4 @@
1
- import { IJupyterGISModel, SelectionType } from '@jupytergis/schema';
1
+ import { IJupyterGISModel, SelectionType, IJupyterGISSettings } from '@jupytergis/schema';
2
2
  import { IStateDB } from '@jupyterlab/statedb';
3
3
  import { CommandRegistry } from '@lumino/commands';
4
4
  import { MouseEvent as ReactMouseEvent } from 'react';
@@ -12,6 +12,7 @@ interface ILeftPanelProps {
12
12
  model: IJupyterGISModel;
13
13
  state: IStateDB;
14
14
  commands: CommandRegistry;
15
+ settings: IJupyterGISSettings;
15
16
  }
16
17
  export declare const LeftPanel: React.FC<ILeftPanelProps>;
17
18
  export {};
@@ -1,34 +1,64 @@
1
1
  import * as React from 'react';
2
+ import { CommandIDs } from '../constants';
2
3
  import { LayersBodyComponent } from './components/layers';
3
4
  import FilterComponent from './filter-panel/Filter';
4
5
  import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
5
6
  import StacPanel from '../stacBrowser/components/StacPanel';
6
7
  export const LeftPanel = (props) => {
7
8
  var _a;
8
- const [settings, setSettings] = React.useState(props.model.jgisSettings);
9
9
  const [options, setOptions] = React.useState(props.model.getOptions());
10
10
  const storyMapPresentationMode = (_a = options.storyMapPresentationMode) !== null && _a !== void 0 ? _a : false;
11
11
  const [layerTree, setLayerTree] = React.useState(props.model.getLayerTree());
12
+ const hasSyncedInitialSelectionRef = React.useRef(false);
13
+ const tabInfo = [
14
+ !props.settings.layersDisabled
15
+ ? { name: 'layers', title: 'Layers' }
16
+ : false,
17
+ !props.settings.stacBrowserDisabled && !storyMapPresentationMode
18
+ ? { name: 'stac', title: 'Stac Browser' }
19
+ : false,
20
+ !props.settings.filtersDisabled && !storyMapPresentationMode
21
+ ? { name: 'filters', title: 'Filters' }
22
+ : false,
23
+ !props.settings.storyMapsDisabled
24
+ ? { name: 'segments', title: 'Segments' }
25
+ : false,
26
+ ].filter(Boolean);
27
+ const [curTab, setCurTab] = React.useState(tabInfo.length > 0 ? tabInfo[0].name : undefined);
12
28
  React.useEffect(() => {
13
- const onSettingsChanged = () => {
14
- setSettings(Object.assign({}, props.model.jgisSettings));
15
- };
16
29
  const onOptionsChanged = () => {
17
30
  setOptions(Object.assign({}, props.model.getOptions()));
18
31
  };
19
32
  const updateLayerTree = () => {
20
- setLayerTree(props.model.getLayerTree() || []);
33
+ const freshTree = props.model.getLayerTree() || [];
34
+ setLayerTree(freshTree);
35
+ // Sync selected to top layer/group only the first time the tree has items
36
+ if (!hasSyncedInitialSelectionRef.current && freshTree.length > 0) {
37
+ hasSyncedInitialSelectionRef.current = true;
38
+ const lastItem = freshTree[freshTree.length - 1];
39
+ const lastId = typeof lastItem === 'string' ? lastItem : lastItem === null || lastItem === void 0 ? void 0 : lastItem.name;
40
+ const lastType = typeof lastItem === 'string' ? 'layer' : 'group';
41
+ if (lastId) {
42
+ props.model.syncSelected({ [lastId]: { type: lastType } }, props.model.getClientId().toString());
43
+ }
44
+ }
45
+ // Need to let command know when segments get populated
46
+ props.commands.notifyCommandChanged(CommandIDs.toggleStoryPresentationMode);
47
+ };
48
+ const onSegmentAdded = (_sender, payload) => {
49
+ props.model.syncSelected({ [payload.storySegmentId]: { type: 'layer' } }, props.model.getClientId().toString());
50
+ setCurTab('segments');
21
51
  };
22
- props.model.settingsChanged.connect(onSettingsChanged);
23
52
  props.model.sharedOptionsChanged.connect(onOptionsChanged);
24
53
  props.model.sharedModel.layersChanged.connect(updateLayerTree);
25
54
  props.model.sharedModel.layerTreeChanged.connect(updateLayerTree);
55
+ props.model.segmentAdded.connect(onSegmentAdded);
26
56
  updateLayerTree();
27
57
  return () => {
28
- props.model.settingsChanged.disconnect(onSettingsChanged);
29
58
  props.model.sharedOptionsChanged.disconnect(onOptionsChanged);
30
59
  props.model.sharedModel.layersChanged.disconnect(updateLayerTree);
31
60
  props.model.sharedModel.layerTreeChanged.disconnect(updateLayerTree);
61
+ props.model.segmentAdded.disconnect(onSegmentAdded);
32
62
  };
33
63
  }, [props.model]);
34
64
  // Since story segments are technically layers they are stored in the layer tree, so we separate them
@@ -88,24 +118,11 @@ export const LeftPanel = (props) => {
88
118
  }
89
119
  props.model.sharedModel.updateStoryMap(storyId, Object.assign(Object.assign({}, story), { storySegments: storySegmentLayerTree }));
90
120
  }, [storySegmentLayerTree]);
91
- const allLeftTabsDisabled = settings.layersDisabled &&
92
- settings.stacBrowserDisabled &&
93
- settings.filtersDisabled &&
94
- settings.storyMapsDisabled;
95
- const leftPanelVisible = !settings.leftPanelDisabled && !allLeftTabsDisabled;
96
- const tabInfo = [
97
- !settings.layersDisabled ? { name: 'layers', title: 'Layers' } : false,
98
- !settings.stacBrowserDisabled && !storyMapPresentationMode
99
- ? { name: 'stac', title: 'Stac Browser' }
100
- : false,
101
- !settings.filtersDisabled && !storyMapPresentationMode
102
- ? { name: 'filters', title: 'Filters' }
103
- : false,
104
- !settings.storyMapsDisabled
105
- ? { name: 'segments', title: 'Segments' }
106
- : false,
107
- ].filter(Boolean);
108
- const [curTab, setCurTab] = React.useState(tabInfo.length > 0 ? tabInfo[0].name : undefined);
121
+ const allLeftTabsDisabled = props.settings.layersDisabled &&
122
+ props.settings.stacBrowserDisabled &&
123
+ props.settings.filtersDisabled &&
124
+ props.settings.storyMapsDisabled;
125
+ const leftPanelVisible = !props.settings.leftPanelDisabled && !allLeftTabsDisabled;
109
126
  return (React.createElement("div", { className: "jgis-left-panel-container", style: { display: leftPanelVisible ? 'block' : 'none' } },
110
127
  React.createElement(PanelTabs, { curTab: curTab, className: "jgis-panel-tabs" },
111
128
  React.createElement(TabsList, null, tabInfo.map(tab => (React.createElement(TabsTrigger, { className: "jGIS-layer-browser-category", key: tab.name, value: tab.name, onClick: () => {
@@ -116,12 +133,12 @@ export const LeftPanel = (props) => {
116
133
  setCurTab('');
117
134
  }
118
135
  } }, tab.title)))),
119
- !settings.layersDisabled && (React.createElement(TabsContent, { value: "layers", className: "jgis-panel-tab-content jp-gis-layerPanel" },
136
+ !props.settings.layersDisabled && (React.createElement(TabsContent, { value: "layers", className: "jgis-panel-tab-content jp-gis-layerPanel" },
120
137
  React.createElement(LayersBodyComponent, { model: props.model, commands: props.commands, state: props.state, layerTree: filteredLayerTree }))),
121
- !settings.stacBrowserDisabled && (React.createElement(TabsContent, { value: "stac", className: "jgis-panel-tab-content jgis-panel-tab-content-stac-panel" },
138
+ !props.settings.stacBrowserDisabled && (React.createElement(TabsContent, { value: "stac", className: "jgis-panel-tab-content jgis-panel-tab-content-stac-panel" },
122
139
  React.createElement(StacPanel, { model: props.model }))),
123
- !settings.filtersDisabled && (React.createElement(TabsContent, { value: "filters", className: "jgis-panel-tab-content" },
140
+ !props.settings.filtersDisabled && (React.createElement(TabsContent, { value: "filters", className: "jgis-panel-tab-content" },
124
141
  React.createElement(FilterComponent, { model: props.model }))),
125
- !settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "segments", className: "jgis-panel-tab-content" },
142
+ !props.settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "segments", className: "jgis-panel-tab-content" },
126
143
  React.createElement(LayersBodyComponent, { model: props.model, commands: props.commands, state: props.state, layerTree: storySegmentLayerTree }))))));
127
144
  };
@@ -1,4 +1,4 @@
1
- import { IAnnotationModel, IJGISFormSchemaRegistry, IJupyterGISModel } from '@jupytergis/schema';
1
+ import { IAnnotationModel, IJGISFormSchemaRegistry, IJupyterGISModel, IJupyterGISSettings } from '@jupytergis/schema';
2
2
  import { CommandRegistry } from '@lumino/commands';
3
3
  import * as React from 'react';
4
4
  interface IRightPanelProps {
@@ -6,6 +6,7 @@ interface IRightPanelProps {
6
6
  annotationModel: IAnnotationModel;
7
7
  model: IJupyterGISModel;
8
8
  commands: CommandRegistry;
9
+ settings: IJupyterGISSettings;
9
10
  }
10
11
  export declare const RightPanel: React.FC<IRightPanelProps>;
11
12
  export {};
@@ -9,7 +9,6 @@ import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/compon
9
9
  export const RightPanel = props => {
10
10
  var _a;
11
11
  const [editorMode, setEditorMode] = React.useState(true);
12
- const [settings, setSettings] = React.useState(props.model.jgisSettings);
13
12
  const [storyMapPresentationMode, setStoryMapPresentationMode] = React.useState((_a = props.model.getOptions().storyMapPresentationMode) !== null && _a !== void 0 ? _a : false);
14
13
  // Only show editor when not in presentation mode and editorMode is true
15
14
  const showEditor = !storyMapPresentationMode && editorMode;
@@ -20,19 +19,19 @@ export const RightPanel = props => {
20
19
  ? 'Story Editor'
21
20
  : 'Story Map';
22
21
  const tabInfo = [
23
- !settings.objectPropertiesDisabled && !storyMapPresentationMode
22
+ !props.settings.objectPropertiesDisabled && !storyMapPresentationMode
24
23
  ? { name: 'objectProperties', title: 'Object Properties' }
25
24
  : false,
26
- !settings.storyMapsDisabled
25
+ !props.settings.storyMapsDisabled
27
26
  ? {
28
27
  name: 'storyPanel',
29
28
  title: storyPanelTitle,
30
29
  }
31
30
  : false,
32
- !settings.annotationsDisabled
31
+ !props.settings.annotationsDisabled
33
32
  ? { name: 'annotations', title: 'Annotations' }
34
33
  : false,
35
- !settings.identifyDisabled
34
+ !props.settings.identifyDisabled
36
35
  ? { name: 'identifyPanel', title: 'Identified Features' }
37
36
  : false,
38
37
  ].filter(Boolean);
@@ -43,12 +42,10 @@ export const RightPanel = props => {
43
42
  return tabInfo.length > 0 ? tabInfo[0].name : '';
44
43
  });
45
44
  React.useEffect(() => {
46
- const onSettingsChanged = () => {
47
- setSettings(Object.assign({}, props.model.jgisSettings));
48
- };
49
45
  const onOptionsChanged = () => {
50
46
  const { storyMapPresentationMode } = props.model.getOptions();
51
47
  setStoryMapPresentationMode(storyMapPresentationMode !== null && storyMapPresentationMode !== void 0 ? storyMapPresentationMode : false);
48
+ storyMapPresentationMode && setCurTab('storyPanel');
52
49
  };
53
50
  let currentlyIdentifiedFeatures = undefined;
54
51
  const onAwerenessChanged = (_, clients) => {
@@ -62,19 +59,17 @@ export const RightPanel = props => {
62
59
  setCurTab('identifyPanel');
63
60
  }
64
61
  };
65
- props.model.settingsChanged.connect(onSettingsChanged);
66
62
  props.model.sharedOptionsChanged.connect(onOptionsChanged);
67
63
  props.model.clientStateChanged.connect(onAwerenessChanged);
68
64
  return () => {
69
- props.model.settingsChanged.disconnect(onSettingsChanged);
70
65
  props.model.sharedOptionsChanged.disconnect(onOptionsChanged);
71
66
  props.model.clientStateChanged.disconnect(onAwerenessChanged);
72
67
  };
73
68
  }, [props.model]);
74
- const allRightTabsDisabled = settings.objectPropertiesDisabled &&
75
- settings.annotationsDisabled &&
76
- settings.identifyDisabled;
77
- const rightPanelVisible = !settings.rightPanelDisabled && !allRightTabsDisabled;
69
+ const allRightTabsDisabled = props.settings.objectPropertiesDisabled &&
70
+ props.settings.annotationsDisabled &&
71
+ props.settings.identifyDisabled;
72
+ const rightPanelVisible = !props.settings.rightPanelDisabled && !allRightTabsDisabled;
78
73
  const [selectedObjectProperties, setSelectedObjectProperties] = React.useState(undefined);
79
74
  const toggleEditor = () => {
80
75
  setEditorMode(!editorMode);
@@ -89,13 +84,13 @@ export const RightPanel = props => {
89
84
  setCurTab('');
90
85
  }
91
86
  } }, tab.title)))),
92
- !settings.objectPropertiesDisabled && (React.createElement(TabsContent, { value: "objectProperties", className: "jgis-panel-tab-content" },
87
+ !props.settings.objectPropertiesDisabled && (React.createElement(TabsContent, { value: "objectProperties", className: "jgis-panel-tab-content" },
93
88
  React.createElement(ObjectPropertiesReact, { setSelectedObject: setSelectedObjectProperties, selectedObject: selectedObjectProperties, formSchemaRegistry: props.formSchemaRegistry, model: props.model }))),
94
- !settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "storyPanel", className: "jgis-panel-tab-content", style: { paddingTop: 0 } },
89
+ !props.settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "storyPanel", className: "jgis-panel-tab-content", style: { paddingTop: 0 } },
95
90
  !storyMapPresentationMode && (React.createElement(PreviewModeSwitch, { checked: !editorMode, onCheckedChange: toggleEditor })),
96
91
  showEditor ? (React.createElement(StoryEditorPanel, { model: props.model, commands: props.commands })) : (React.createElement(StoryViewerPanel, { model: props.model, isSpecta: false })))),
97
- !settings.annotationsDisabled && (React.createElement(TabsContent, { value: "annotations", className: "jgis-panel-tab-content" },
92
+ !props.settings.annotationsDisabled && (React.createElement(TabsContent, { value: "annotations", className: "jgis-panel-tab-content" },
98
93
  React.createElement(AnnotationsPanel, { annotationModel: props.annotationModel, jgisModel: props.model }))),
99
- !settings.identifyDisabled && (React.createElement(TabsContent, { value: "identifyPanel", className: "jgis-panel-tab-content" },
94
+ !props.settings.identifyDisabled && (React.createElement(TabsContent, { value: "identifyPanel", className: "jgis-panel-tab-content" },
100
95
  React.createElement(IdentifyPanelComponent, { model: props.model }))))));
101
96
  };
@@ -0,0 +1,7 @@
1
+ import { IJupyterGISModel } from '@jupytergis/schema';
2
+ import React from 'react';
3
+ interface IMobileSpectaPanelProps {
4
+ model: IJupyterGISModel;
5
+ }
6
+ export declare function MobileSpectaPanel({ model }: IMobileSpectaPanelProps): React.JSX.Element;
7
+ export {};