@jupytergis/base 0.11.1 → 0.12.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 (101) hide show
  1. package/lib/commands/BaseCommandIDs.d.ts +1 -0
  2. package/lib/commands/BaseCommandIDs.js +1 -0
  3. package/lib/commands/index.js +52 -0
  4. package/lib/constants.js +3 -0
  5. package/lib/dialogs/symbology/hooks/useGetBandInfo.d.ts +0 -6
  6. package/lib/dialogs/symbology/hooks/useGetBandInfo.js +2 -2
  7. package/lib/dialogs/symbology/tiff_layer/types/MultibandColor.js +4 -4
  8. package/lib/formbuilder/objectform/StoryEditorForm.d.ts +3 -2
  9. package/lib/formbuilder/objectform/StoryEditorForm.js +7 -1
  10. package/lib/mainview/mainView.d.ts +18 -0
  11. package/lib/mainview/mainView.js +243 -18
  12. package/lib/panelview/{components/filter-panel → filter-panel}/Filter.js +1 -1
  13. package/lib/panelview/leftpanel.js +4 -4
  14. package/lib/panelview/rightpanel.d.ts +2 -0
  15. package/lib/panelview/rightpanel.js +21 -14
  16. package/lib/panelview/{components/story-maps → story-maps}/PreviewModeSwitch.js +3 -2
  17. package/lib/panelview/story-maps/StoryEditorPanel.d.ts +9 -0
  18. package/lib/panelview/story-maps/StoryEditorPanel.js +34 -0
  19. package/lib/panelview/{components/story-maps → story-maps}/StoryNavBar.d.ts +2 -1
  20. package/lib/panelview/{components/story-maps → story-maps}/StoryNavBar.js +3 -3
  21. package/lib/panelview/story-maps/StoryViewerPanel.d.ts +13 -0
  22. package/lib/panelview/{components/story-maps → story-maps}/StoryViewerPanel.js +37 -24
  23. package/lib/panelview/story-maps/components/StoryContentSection.d.ts +6 -0
  24. package/lib/panelview/story-maps/components/StoryContentSection.js +10 -0
  25. package/lib/panelview/story-maps/components/StoryImageSection.d.ts +15 -0
  26. package/lib/panelview/story-maps/components/StoryImageSection.js +13 -0
  27. package/lib/panelview/story-maps/components/StorySubtitleSection.d.ts +11 -0
  28. package/lib/panelview/story-maps/components/StorySubtitleSection.js +9 -0
  29. package/lib/panelview/story-maps/components/StoryTitleSection.d.ts +12 -0
  30. package/lib/panelview/story-maps/components/StoryTitleSection.js +8 -0
  31. package/lib/shared/components/Combobox.d.ts +21 -0
  32. package/lib/shared/components/Combobox.js +32 -0
  33. package/lib/shared/components/Command.js +10 -10
  34. package/lib/shared/components/Input.d.ts +3 -0
  35. package/lib/shared/components/Input.js +18 -0
  36. package/lib/shared/components/Pagination.js +3 -2
  37. package/lib/shared/components/Select.d.ts +19 -0
  38. package/lib/shared/components/Select.js +28 -0
  39. package/lib/shared/components/SingleDatePicker.d.ts +11 -0
  40. package/lib/shared/components/SingleDatePicker.js +16 -0
  41. package/lib/stacBrowser/components/StacPanel.d.ts +9 -1
  42. package/lib/stacBrowser/components/StacPanel.js +53 -9
  43. package/lib/stacBrowser/components/filter-extension/QueryableComboBox.d.ts +9 -0
  44. package/lib/stacBrowser/components/filter-extension/QueryableComboBox.js +179 -0
  45. package/lib/stacBrowser/components/filter-extension/QueryableRow.d.ts +16 -0
  46. package/lib/stacBrowser/components/filter-extension/QueryableRow.js +16 -0
  47. package/lib/stacBrowser/components/filter-extension/StacFilterExtensionPanel.d.ts +7 -0
  48. package/lib/stacBrowser/components/filter-extension/StacFilterExtensionPanel.js +49 -0
  49. package/lib/stacBrowser/components/filter-extension/StacQueryableFilters.d.ts +11 -0
  50. package/lib/stacBrowser/components/filter-extension/StacQueryableFilters.js +19 -0
  51. package/lib/stacBrowser/components/{StacFilterSection.d.ts → geodes/StacFilterSection.d.ts} +1 -1
  52. package/lib/stacBrowser/components/{StacFilterSection.js → geodes/StacFilterSection.js} +3 -3
  53. package/lib/stacBrowser/components/geodes/StacGeodesFilterPanel.d.ts +7 -0
  54. package/lib/stacBrowser/components/geodes/StacGeodesFilterPanel.js +69 -0
  55. package/lib/stacBrowser/components/shared/StacPanelResults.d.ts +3 -0
  56. package/lib/stacBrowser/components/shared/StacPanelResults.js +68 -0
  57. package/lib/stacBrowser/components/shared/StacSpatialExtent.d.ts +8 -0
  58. package/lib/stacBrowser/components/shared/StacSpatialExtent.js +10 -0
  59. package/lib/stacBrowser/components/shared/StacTemporalExtent.d.ts +9 -0
  60. package/lib/stacBrowser/components/shared/StacTemporalExtent.js +9 -0
  61. package/lib/stacBrowser/context/StacResultsContext.d.ts +33 -0
  62. package/lib/stacBrowser/context/StacResultsContext.js +269 -0
  63. package/lib/stacBrowser/hooks/useGeodesSearch.d.ts +24 -0
  64. package/lib/stacBrowser/hooks/useGeodesSearch.js +178 -0
  65. package/lib/stacBrowser/hooks/useStacFilterExtension.d.ts +30 -0
  66. package/lib/stacBrowser/hooks/useStacFilterExtension.js +262 -0
  67. package/lib/stacBrowser/hooks/useStacSearch.d.ts +5 -16
  68. package/lib/stacBrowser/hooks/useStacSearch.js +30 -184
  69. package/lib/stacBrowser/types/types.d.ts +86 -3
  70. package/lib/toolbar/widget.d.ts +5 -0
  71. package/lib/toolbar/widget.js +23 -2
  72. package/lib/tools.d.ts +0 -7
  73. package/lib/tools.js +55 -14
  74. package/package.json +2 -2
  75. package/style/base.css +38 -3
  76. package/style/shared/button.css +5 -4
  77. package/style/shared/calendar.css +7 -1
  78. package/style/shared/combobox.css +75 -0
  79. package/style/shared/command.css +178 -0
  80. package/style/shared/input.css +59 -0
  81. package/style/shared/pagination.css +1 -1
  82. package/style/shared/popover.css +1 -0
  83. package/style/shared/tabs.css +1 -1
  84. package/style/shared/toggle.css +1 -1
  85. package/style/stacBrowser.css +169 -16
  86. package/style/statusBar.css +1 -0
  87. package/style/storyPanel.css +120 -3
  88. package/style/tabPanel.css +0 -86
  89. package/lib/panelview/components/story-maps/StoryEditorPanel.d.ts +0 -7
  90. package/lib/panelview/components/story-maps/StoryEditorPanel.js +0 -29
  91. package/lib/panelview/components/story-maps/StoryViewerPanel.d.ts +0 -7
  92. package/lib/stacBrowser/components/StacPanelFilters.d.ts +0 -14
  93. package/lib/stacBrowser/components/StacPanelFilters.js +0 -81
  94. package/lib/stacBrowser/components/StacPanelResults.d.ts +0 -13
  95. package/lib/stacBrowser/components/StacPanelResults.js +0 -48
  96. /package/lib/panelview/{components/filter-panel → filter-panel}/Filter.d.ts +0 -0
  97. /package/lib/panelview/{components/filter-panel → filter-panel}/FilterRow.d.ts +0 -0
  98. /package/lib/panelview/{components/filter-panel → filter-panel}/FilterRow.js +0 -0
  99. /package/lib/panelview/{components/identify-panel → identify-panel}/IdentifyPanel.d.ts +0 -0
  100. /package/lib/panelview/{components/identify-panel → identify-panel}/IdentifyPanel.js +0 -0
  101. /package/lib/panelview/{components/story-maps → story-maps}/PreviewModeSwitch.d.ts +0 -0
@@ -1,8 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { LayersBodyComponent } from './components/layers';
3
+ import FilterComponent from './filter-panel/Filter';
3
4
  import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
4
5
  import StacPanel from '../stacBrowser/components/StacPanel';
5
- import FilterComponent from './components/filter-panel/Filter';
6
6
  export const LeftPanel = (props) => {
7
7
  var _a;
8
8
  const [settings, setSettings] = React.useState(props.model.jgisSettings);
@@ -82,11 +82,11 @@ export const LeftPanel = (props) => {
82
82
  }, [layerTree]);
83
83
  // Updates story segments array based on layer tree array
84
84
  React.useEffect(() => {
85
- const { storySegmentId, story } = props.model.getSelectedStory();
85
+ const { storyId, story } = props.model.getSelectedStory();
86
86
  if (!story) {
87
87
  return;
88
88
  }
89
- props.model.sharedModel.updateStoryMap(storySegmentId, Object.assign(Object.assign({}, story), { storySegments: storySegmentLayerTree }));
89
+ props.model.sharedModel.updateStoryMap(storyId, Object.assign(Object.assign({}, story), { storySegments: storySegmentLayerTree }));
90
90
  }, [storySegmentLayerTree]);
91
91
  const allLeftTabsDisabled = settings.layersDisabled &&
92
92
  settings.stacBrowserDisabled &&
@@ -118,7 +118,7 @@ export const LeftPanel = (props) => {
118
118
  } }, tab.title)))),
119
119
  !settings.layersDisabled && (React.createElement(TabsContent, { value: "layers", className: "jgis-panel-tab-content jp-gis-layerPanel" },
120
120
  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" },
121
+ !settings.stacBrowserDisabled && (React.createElement(TabsContent, { value: "stac", className: "jgis-panel-tab-content jgis-panel-tab-content-stac-panel" },
122
122
  React.createElement(StacPanel, { model: props.model }))),
123
123
  !settings.filtersDisabled && (React.createElement(TabsContent, { value: "filters", className: "jgis-panel-tab-content" },
124
124
  React.createElement(FilterComponent, { model: props.model }))),
@@ -1,9 +1,11 @@
1
1
  import { IAnnotationModel, IJGISFormSchemaRegistry, IJupyterGISModel } from '@jupytergis/schema';
2
+ import { CommandRegistry } from '@lumino/commands';
2
3
  import * as React from 'react';
3
4
  interface IRightPanelProps {
4
5
  formSchemaRegistry: IJGISFormSchemaRegistry;
5
6
  annotationModel: IAnnotationModel;
6
7
  model: IJupyterGISModel;
8
+ commands: CommandRegistry;
7
9
  }
8
10
  export declare const RightPanel: React.FC<IRightPanelProps>;
9
11
  export {};
@@ -1,17 +1,24 @@
1
1
  import * as React from 'react';
2
2
  import { AnnotationsPanel } from './annotationPanel';
3
- import { IdentifyPanelComponent } from './components/identify-panel/IdentifyPanel';
4
- import { PreviewModeSwitch } from './components/story-maps/PreviewModeSwitch';
5
- import StoryEditorPanel from './components/story-maps/StoryEditorPanel';
6
- import StoryViewerPanel from './components/story-maps/StoryViewerPanel';
3
+ import { IdentifyPanelComponent } from './identify-panel/IdentifyPanel';
7
4
  import { ObjectPropertiesReact } from './objectproperties';
5
+ import { PreviewModeSwitch } from './story-maps/PreviewModeSwitch';
6
+ import StoryEditorPanel from './story-maps/StoryEditorPanel';
7
+ import StoryViewerPanel from './story-maps/StoryViewerPanel';
8
8
  import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
9
9
  export const RightPanel = props => {
10
10
  var _a;
11
- const [displayEditor, setDisplayEditor] = React.useState(true);
11
+ const [editorMode, setEditorMode] = React.useState(true);
12
12
  const [settings, setSettings] = React.useState(props.model.jgisSettings);
13
- const [options, setOptions] = React.useState(props.model.getOptions());
14
- const storyMapPresentationMode = (_a = options.storyMapPresentationMode) !== null && _a !== void 0 ? _a : false;
13
+ const [storyMapPresentationMode, setStoryMapPresentationMode] = React.useState((_a = props.model.getOptions().storyMapPresentationMode) !== null && _a !== void 0 ? _a : false);
14
+ // Only show editor when not in presentation mode and editorMode is true
15
+ const showEditor = !storyMapPresentationMode && editorMode;
16
+ // Tab title: "Story Map" in presentation mode, otherwise based on editorMode
17
+ const storyPanelTitle = storyMapPresentationMode
18
+ ? 'Story Map'
19
+ : editorMode
20
+ ? 'Story Editor'
21
+ : 'Story Map';
15
22
  const tabInfo = [
16
23
  !settings.objectPropertiesDisabled && !storyMapPresentationMode
17
24
  ? { name: 'objectProperties', title: 'Object Properties' }
@@ -19,7 +26,7 @@ export const RightPanel = props => {
19
26
  !settings.storyMapsDisabled
20
27
  ? {
21
28
  name: 'storyPanel',
22
- title: displayEditor ? 'Story Editor' : 'Story Map',
29
+ title: storyPanelTitle,
23
30
  }
24
31
  : false,
25
32
  !settings.annotationsDisabled
@@ -40,7 +47,8 @@ export const RightPanel = props => {
40
47
  setSettings(Object.assign({}, props.model.jgisSettings));
41
48
  };
42
49
  const onOptionsChanged = () => {
43
- setOptions(Object.assign({}, props.model.getOptions()));
50
+ const { storyMapPresentationMode } = props.model.getOptions();
51
+ setStoryMapPresentationMode(storyMapPresentationMode !== null && storyMapPresentationMode !== void 0 ? storyMapPresentationMode : false);
44
52
  };
45
53
  let currentlyIdentifiedFeatures = undefined;
46
54
  const onAwerenessChanged = (_, clients) => {
@@ -69,11 +77,11 @@ export const RightPanel = props => {
69
77
  const rightPanelVisible = !settings.rightPanelDisabled && !allRightTabsDisabled;
70
78
  const [selectedObjectProperties, setSelectedObjectProperties] = React.useState(undefined);
71
79
  const toggleEditor = () => {
72
- setDisplayEditor(!displayEditor);
80
+ setEditorMode(!editorMode);
73
81
  };
74
82
  return (React.createElement("div", { className: "jgis-right-panel-container", style: { display: rightPanelVisible ? 'block' : 'none' } },
75
83
  React.createElement(PanelTabs, { className: "jgis-panel-tabs", curTab: curTab },
76
- React.createElement(TabsList, null, tabInfo.map(tab => (React.createElement(TabsTrigger, { className: "jGIS-layer-browser-category", key: tab.name, value: tab.name, onClick: () => {
84
+ React.createElement(TabsList, null, tabInfo.map(tab => (React.createElement(TabsTrigger, { className: "jGIS-layer-browser-category", key: `${tab.name}-${tab.title}`, value: tab.name, onClick: () => {
77
85
  if (curTab !== tab.name) {
78
86
  setCurTab(tab.name);
79
87
  }
@@ -84,9 +92,8 @@ export const RightPanel = props => {
84
92
  !settings.objectPropertiesDisabled && (React.createElement(TabsContent, { value: "objectProperties", className: "jgis-panel-tab-content" },
85
93
  React.createElement(ObjectPropertiesReact, { setSelectedObject: setSelectedObjectProperties, selectedObject: selectedObjectProperties, formSchemaRegistry: props.formSchemaRegistry, model: props.model }))),
86
94
  !settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "storyPanel", className: "jgis-panel-tab-content", style: { paddingTop: 0 } },
87
- React.createElement("div", { style: { padding: '0 0.5rem 0.5rem 0.5rem' } },
88
- !storyMapPresentationMode && (React.createElement(PreviewModeSwitch, { checked: !displayEditor, onCheckedChange: toggleEditor })),
89
- storyMapPresentationMode || !displayEditor ? (React.createElement(StoryViewerPanel, { model: props.model })) : (React.createElement(StoryEditorPanel, { model: props.model }))))),
95
+ !storyMapPresentationMode && (React.createElement(PreviewModeSwitch, { checked: !editorMode, onCheckedChange: toggleEditor })),
96
+ showEditor ? (React.createElement(StoryEditorPanel, { model: props.model, commands: props.commands })) : (React.createElement(StoryViewerPanel, { model: props.model, isSpecta: false })))),
90
97
  !settings.annotationsDisabled && (React.createElement(TabsContent, { value: "annotations", className: "jgis-panel-tab-content" },
91
98
  React.createElement(AnnotationsPanel, { annotationModel: props.annotationModel, jgisModel: props.model }))),
92
99
  !settings.identifyDisabled && (React.createElement(TabsContent, { value: "identifyPanel", className: "jgis-panel-tab-content" },
@@ -1,11 +1,12 @@
1
1
  import * as React from 'react';
2
- import { Switch } from "../../../shared/components/Switch";
2
+ import { Switch } from "../../shared/components/Switch";
3
3
  export function PreviewModeSwitch({ checked, onCheckedChange, }) {
4
4
  return (React.createElement("div", { style: {
5
5
  display: 'flex',
6
6
  alignItems: 'center',
7
7
  gap: '0.5rem',
8
- padding: '1rem 1rem 1rem 0',
8
+ padding: '1rem',
9
+ paddingBottom: '0',
9
10
  } },
10
11
  React.createElement("label", { htmlFor: "preview-mode-switch", style: { fontSize: '0.875rem' } }, "Preview Mode"),
11
12
  React.createElement(Switch, { id: "preview-mode-switch", checked: checked, onCheckedChange: onCheckedChange })));
@@ -0,0 +1,9 @@
1
+ import { IJupyterGISModel } from '@jupytergis/schema';
2
+ import { CommandRegistry } from '@lumino/commands';
3
+ import React from 'react';
4
+ interface IStoryPanelProps {
5
+ model: IJupyterGISModel;
6
+ commands: CommandRegistry;
7
+ }
8
+ export declare function StoryEditorPanel({ model, commands }: IStoryPanelProps): React.JSX.Element;
9
+ export default StoryEditorPanel;
@@ -0,0 +1,34 @@
1
+ import { faLink } from '@fortawesome/free-solid-svg-icons';
2
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
+ import jgisSchema from '@jupytergis/schema/lib/schema/project/jgis.json';
4
+ import React, { useMemo } from 'react';
5
+ import { CommandIDs } from "../../constants";
6
+ import { StoryEditorPropertiesForm } from "../../formbuilder/objectform/StoryEditorForm";
7
+ import { Button } from "../../shared/components/Button";
8
+ import { deepCopy } from "../../tools";
9
+ const storyMapSchema = deepCopy(jgisSchema.definitions.jGISStoryMap);
10
+ const AddStorySegmentButton = ({ model, commands }) => (React.createElement("div", { style: { display: 'flex', justifyContent: 'center' } },
11
+ React.createElement(Button, { onClick: () => commands.execute(CommandIDs.addStorySegment) },
12
+ React.createElement(FontAwesomeIcon, { icon: faLink }),
13
+ " Add Story Segment")));
14
+ export function StoryEditorPanel({ model, commands }) {
15
+ const { storyId, story } = useMemo(() => {
16
+ return model.getSelectedStory();
17
+ }, [model, model.sharedModel.stories]);
18
+ const syncStoryData = (properties) => {
19
+ var _a;
20
+ // Preserve storySegments when updating, since the form removes it from the UI
21
+ const updatedStory = Object.assign(Object.assign(Object.assign({}, story), properties), { storySegments: (_a = story === null || story === void 0 ? void 0 : story.storySegments) !== null && _a !== void 0 ? _a : [] });
22
+ model.sharedModel.updateStoryMap(storyId, updatedStory);
23
+ };
24
+ if (!story) {
25
+ return (React.createElement("div", { style: { padding: '1rem' } },
26
+ React.createElement("p", null, "No Story Map available."),
27
+ React.createElement("p", null, "Add a Story Segment from the Add Layer menu. A segment captures the current map view. You can add markdown text and an image to each segment to tell your story."),
28
+ React.createElement(AddStorySegmentButton, { model: model, commands: commands })));
29
+ }
30
+ return (React.createElement("div", { className: "jgis-story-editor-panel" },
31
+ React.createElement(StoryEditorPropertiesForm, { formContext: "update", sourceData: story, model: model, schema: storyMapSchema, syncData: syncStoryData, filePath: model.filePath }),
32
+ React.createElement(AddStorySegmentButton, { model: model, commands: commands })));
33
+ }
34
+ export default StoryEditorPanel;
@@ -4,6 +4,7 @@ interface IStoryNavBarProps {
4
4
  onNext: () => void;
5
5
  hasPrev: boolean;
6
6
  hasNext: boolean;
7
+ isSpecta: boolean;
7
8
  }
8
- declare function StoryNavBar({ onPrev, onNext, hasPrev, hasNext }: IStoryNavBarProps): React.JSX.Element;
9
+ declare function StoryNavBar({ onPrev, onNext, hasPrev, hasNext, isSpecta, }: IStoryNavBarProps): React.JSX.Element;
9
10
  export default StoryNavBar;
@@ -1,8 +1,8 @@
1
1
  import { ChevronLeft, ChevronRight } from 'lucide-react';
2
2
  import React from 'react';
3
- import { Button } from "../../../shared/components/Button";
4
- function StoryNavBar({ onPrev, onNext, hasPrev, hasNext }) {
5
- return (React.createElement("div", { style: { display: 'flex', gap: '8px', justifyContent: 'center' } },
3
+ import { Button } from "../../shared/components/Button";
4
+ function StoryNavBar({ onPrev, onNext, hasPrev, hasNext, isSpecta, }) {
5
+ return (React.createElement("div", { className: `jgis-story-navbar ${isSpecta ? 'jgis-story-navbar-specta-mod' : ''}` },
6
6
  React.createElement(Button, { onClick: onPrev, disabled: !hasPrev, "aria-label": "Previous slide" },
7
7
  React.createElement(ChevronLeft, null)),
8
8
  React.createElement(Button, { onClick: onNext, disabled: !hasNext, "aria-label": "Next slide" },
@@ -0,0 +1,13 @@
1
+ import { IJupyterGISModel } from '@jupytergis/schema';
2
+ import React from 'react';
3
+ interface IStoryViewerPanelProps {
4
+ model: IJupyterGISModel;
5
+ isSpecta: boolean;
6
+ }
7
+ export interface IStoryViewerPanelHandle {
8
+ handlePrev: () => void;
9
+ handleNext: () => void;
10
+ canNavigate: boolean;
11
+ }
12
+ declare const StoryViewerPanel: React.ForwardRefExoticComponent<IStoryViewerPanelProps & React.RefAttributes<IStoryViewerPanelHandle>>;
13
+ export default StoryViewerPanel;
@@ -1,11 +1,14 @@
1
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
- import Markdown from 'react-markdown';
3
- import StoryNavBar from './StoryNavBar';
4
- function StoryViewerPanel({ model }) {
5
- var _a, _b, _c, _d, _e, _f;
1
+ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
2
+ import StoryContentSection from './components/StoryContentSection';
3
+ import StoryImageSection from './components/StoryImageSection';
4
+ import StorySubtitleSection from './components/StorySubtitleSection';
5
+ import StoryTitleSection from './components/StoryTitleSection';
6
+ const StoryViewerPanel = forwardRef(({ model, isSpecta }, ref) => {
7
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
6
8
  const [currentIndexDisplayed, setCurrentIndexDisplayed] = useState(0);
7
9
  const [storyData, setStoryData] = useState((_a = model.getSelectedStory().story) !== null && _a !== void 0 ? _a : null);
8
10
  const [imageLoaded, setImageLoaded] = useState(false);
11
+ const panelRef = useRef(null);
9
12
  // Derive story segments from story data
10
13
  const storySegments = useMemo(() => {
11
14
  if (!(storyData === null || storyData === void 0 ? void 0 : storyData.storySegments)) {
@@ -133,34 +136,44 @@ function StoryViewerPanel({ model }) {
133
136
  model.sharedModel.awareness.off('change', handleSelectedStorySegmentChange);
134
137
  };
135
138
  }, [model, storyData]);
136
- const handlePrev = () => {
139
+ const handlePrev = useCallback(() => {
137
140
  if (currentIndexDisplayed > 0) {
138
141
  const newIndex = currentIndexDisplayed - 1;
139
142
  setCurrentIndexDisplayed(newIndex);
140
143
  }
141
- };
142
- const handleNext = () => {
144
+ }, [currentIndexDisplayed]);
145
+ const handleNext = useCallback(() => {
143
146
  if (currentIndexDisplayed < storySegments.length - 1) {
144
147
  const newIndex = currentIndexDisplayed + 1;
145
148
  setCurrentIndexDisplayed(newIndex);
146
149
  }
147
- };
150
+ }, [currentIndexDisplayed, storySegments.length]);
151
+ // Expose methods via ref for parent component to use
152
+ useImperativeHandle(ref, () => ({
153
+ handlePrev,
154
+ handleNext,
155
+ canNavigate: isSpecta,
156
+ }), [handlePrev, handleNext, storyData, isSpecta]);
148
157
  if (!storyData || ((_c = storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) === null || _c === void 0 ? void 0 : _c.length) === 0) {
149
- return (React.createElement("div", { style: { padding: '0 0.5rem 0.5rem 0.5rem' } },
158
+ return (React.createElement("div", { style: { padding: '1rem' } },
150
159
  React.createElement("p", null, "No Segments available. Add one using the Add Layer menu.")));
151
160
  }
152
- return (React.createElement("div", { className: "jgis-story-viewer-panel" },
153
- ((_d = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _d === void 0 ? void 0 : _d.image) && imageLoaded ? (React.createElement("div", { className: "jgis-story-viewer-image-container" },
154
- React.createElement("img", { src: activeSlide.content.image, alt: activeSlide.content.title || 'Story map image', className: "jgis-story-viewer-image" }),
155
- React.createElement("h1", { className: "jgis-story-viewer-image-title" }, layerName !== null && layerName !== void 0 ? layerName : `Slide ${currentIndexDisplayed + 1}`),
156
- storyData.storyType === 'guided' && (React.createElement("div", { className: "jgis-story-viewer-nav-container" },
157
- React.createElement(StoryNavBar, { onPrev: handlePrev, onNext: handleNext, hasPrev: currentIndexDisplayed > 0, hasNext: currentIndexDisplayed < storySegments.length - 1 }))))) : (React.createElement(React.Fragment, null,
158
- React.createElement("h1", { className: "jgis-story-viewer-title" }, storyData.title),
159
- storyData.storyType === 'guided' && (React.createElement(StoryNavBar, { onPrev: handlePrev, onNext: handleNext, hasPrev: currentIndexDisplayed > 0, hasNext: currentIndexDisplayed < storySegments.length - 1 })))),
160
- React.createElement("h2", { className: "jgis-story-viewer-subtitle" }, ((_e = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _e === void 0 ? void 0 : _e.title)
161
- ? activeSlide.content.title
162
- : 'Slide Title'),
163
- ((_f = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _f === void 0 ? void 0 : _f.markdown) && (React.createElement("div", { className: "jgis-story-viewer-content" },
164
- React.createElement(Markdown, null, activeSlide.content.markdown)))));
165
- }
161
+ const navProps = {
162
+ onPrev: handlePrev,
163
+ onNext: handleNext,
164
+ hasPrev: currentIndexDisplayed > 0,
165
+ hasNext: currentIndexDisplayed < storySegments.length - 1,
166
+ };
167
+ // Get transition time from current segment, default to 0.3s
168
+ const transitionTime = (_e = (_d = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.transition) === null || _d === void 0 ? void 0 : _d.time) !== null && _e !== void 0 ? _e : 0.3;
169
+ return (React.createElement("div", { ref: panelRef, className: `jgis-story-viewer-panel ${isSpecta ? 'jgis-story-viewer-panel-specta-mod' : ''}` },
170
+ React.createElement("div", { key: currentIndexDisplayed, className: "jgis-story-segment-container", style: {
171
+ animationDuration: `${transitionTime}s`,
172
+ } },
173
+ React.createElement("h1", { className: "jgis-story-viewer-title" }, layerName !== null && layerName !== void 0 ? layerName : `Slide ${currentIndexDisplayed + 1}`),
174
+ ((_f = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _f === void 0 ? void 0 : _f.image) && imageLoaded ? (React.createElement(StoryImageSection, Object.assign({ imageUrl: activeSlide.content.image, imageLoaded: imageLoaded, layerName: layerName !== null && layerName !== void 0 ? layerName : '', slideNumber: currentIndexDisplayed, isSpecta: isSpecta, storyType: (_g = storyData.storyType) !== null && _g !== void 0 ? _g : 'guided' }, navProps))) : (React.createElement(StoryTitleSection, Object.assign({ title: (_h = storyData.title) !== null && _h !== void 0 ? _h : '', isSpecta: isSpecta, storyType: (_j = storyData.storyType) !== null && _j !== void 0 ? _j : 'guided' }, navProps))),
175
+ React.createElement(StorySubtitleSection, Object.assign({ title: (_l = (_k = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _k === void 0 ? void 0 : _k.title) !== null && _l !== void 0 ? _l : '', isSpecta: isSpecta }, navProps)),
176
+ React.createElement(StoryContentSection, { markdown: (_o = (_m = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _m === void 0 ? void 0 : _m.markdown) !== null && _o !== void 0 ? _o : '' }))));
177
+ });
178
+ StoryViewerPanel.displayName = 'StoryViewerPanel';
166
179
  export default StoryViewerPanel;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ interface IStoryContentProps {
3
+ markdown: string;
4
+ }
5
+ declare function StoryContentSection({ markdown }: IStoryContentProps): React.JSX.Element | null;
6
+ export default StoryContentSection;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import Markdown from 'react-markdown';
3
+ function StoryContentSection({ markdown }) {
4
+ if (!markdown) {
5
+ return null;
6
+ }
7
+ return (React.createElement("div", { className: "jgis-story-viewer-content" },
8
+ React.createElement(Markdown, null, markdown)));
9
+ }
10
+ export default StoryContentSection;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ interface IStoryImageSectionProps {
3
+ imageUrl: string;
4
+ imageLoaded: boolean;
5
+ layerName: string;
6
+ slideNumber: number;
7
+ isSpecta: boolean;
8
+ storyType: string;
9
+ onPrev: () => void;
10
+ onNext: () => void;
11
+ hasPrev: boolean;
12
+ hasNext: boolean;
13
+ }
14
+ declare function StoryImageSection({ imageUrl, imageLoaded, layerName, slideNumber, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }: IStoryImageSectionProps): React.JSX.Element | null;
15
+ export default StoryImageSection;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import StoryNavBar from '../StoryNavBar';
3
+ function StoryImageSection({ imageUrl, imageLoaded, layerName, slideNumber, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }) {
4
+ if (!imageLoaded) {
5
+ return null;
6
+ }
7
+ return (React.createElement("div", { className: "jgis-story-viewer-image-section" },
8
+ React.createElement("div", { className: "jgis-story-viewer-image-container" },
9
+ React.createElement("img", { src: imageUrl, alt: "Story map image", className: "jgis-story-viewer-image" }),
10
+ !isSpecta && storyType === 'guided' && (React.createElement("div", { className: "jgis-story-viewer-nav-container" },
11
+ React.createElement(StoryNavBar, { onPrev: onPrev, onNext: onNext, hasPrev: hasPrev, hasNext: hasNext, isSpecta: isSpecta }))))));
12
+ }
13
+ export default StoryImageSection;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface IStorySubtitleSectionProps {
3
+ title: string;
4
+ isSpecta: boolean;
5
+ onPrev: () => void;
6
+ onNext: () => void;
7
+ hasPrev: boolean;
8
+ hasNext: boolean;
9
+ }
10
+ declare function StorySubtitleSection({ title, isSpecta, onPrev, onNext, hasPrev, hasNext, }: IStorySubtitleSectionProps): React.JSX.Element;
11
+ export default StorySubtitleSection;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import StoryNavBar from '../StoryNavBar';
3
+ function StorySubtitleSection({ title, isSpecta, onPrev, onNext, hasPrev, hasNext, }) {
4
+ return (React.createElement("div", { className: "jgis-story-viewer-subtitle-container" },
5
+ React.createElement("h2", { className: "jgis-story-viewer-subtitle" }, title || 'Slide Title'),
6
+ isSpecta && (React.createElement("div", { className: "jgis-story-viewer-nav-container-specta-mod" },
7
+ React.createElement(StoryNavBar, { onPrev: onPrev, onNext: onNext, hasPrev: hasPrev, hasNext: hasNext, isSpecta: isSpecta })))));
8
+ }
9
+ export default StorySubtitleSection;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ interface IStoryTitleSectionProps {
3
+ title: string;
4
+ isSpecta: boolean;
5
+ storyType: string;
6
+ onPrev: () => void;
7
+ onNext: () => void;
8
+ hasPrev: boolean;
9
+ hasNext: boolean;
10
+ }
11
+ declare function StoryTitleSection({ title, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }: IStoryTitleSectionProps): React.JSX.Element;
12
+ export default StoryTitleSection;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import StoryNavBar from '../StoryNavBar';
3
+ function StoryTitleSection({ title, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }) {
4
+ return (React.createElement(React.Fragment, null,
5
+ React.createElement("h1", { className: "jgis-story-viewer-title" }, title),
6
+ !isSpecta && storyType === 'guided' && (React.createElement(StoryNavBar, { onPrev: onPrev, onNext: onNext, hasPrev: hasPrev, hasNext: hasNext, isSpecta: isSpecta }))));
7
+ }
8
+ export default StoryTitleSection;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ export interface IComboboxItem {
3
+ value: string;
4
+ label: string;
5
+ onSelect?: () => void;
6
+ selected?: boolean;
7
+ showCheckIcon?: boolean;
8
+ }
9
+ interface IComboboxProps {
10
+ items: IComboboxItem[];
11
+ buttonText: string;
12
+ searchPlaceholder?: string;
13
+ emptyText?: string;
14
+ className?: string;
15
+ buttonClassName?: string;
16
+ open?: boolean;
17
+ onOpenChange?: (open: boolean) => void;
18
+ showSearch?: boolean;
19
+ }
20
+ export declare function Combobox({ items, buttonText, searchPlaceholder, emptyText, className, buttonClassName, open: controlledOpen, onOpenChange: controlledOnOpenChange, showSearch, }: IComboboxProps): React.JSX.Element;
21
+ export {};
@@ -0,0 +1,32 @@
1
+ import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react';
2
+ import React, { useState } from 'react';
3
+ import { Button } from "./Button";
4
+ import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "./Command";
5
+ import { Popover, PopoverContent, PopoverTrigger, } from "./Popover";
6
+ import { cn } from './utils';
7
+ export function Combobox({ items, buttonText, searchPlaceholder = 'Search...', emptyText = 'No option found.', className, buttonClassName, open: controlledOpen, onOpenChange: controlledOnOpenChange, showSearch = true, }) {
8
+ const [internalOpen, setInternalOpen] = useState(false);
9
+ const open = controlledOpen !== undefined ? controlledOpen : internalOpen;
10
+ const setOpen = controlledOnOpenChange || setInternalOpen;
11
+ const handleSelect = (item) => {
12
+ // Don't close automatically - allow multi-select
13
+ if (item.onSelect) {
14
+ item.onSelect();
15
+ }
16
+ };
17
+ return (React.createElement(Popover, { open: open, onOpenChange: setOpen },
18
+ React.createElement(PopoverTrigger, { asChild: true },
19
+ React.createElement(Button, { variant: "outline", role: "combobox", "aria-expanded": open, className: cn('jgis-combobox-button', buttonClassName) },
20
+ React.createElement("span", { className: "jgis-combobox-button-text" }, buttonText),
21
+ React.createElement(ChevronsUpDownIcon, { className: "jgis-combobox-icon" }))),
22
+ React.createElement(PopoverContent, { className: cn('jgis-combobox-popover', className) },
23
+ React.createElement(Command, null,
24
+ showSearch && React.createElement(CommandInput, { placeholder: searchPlaceholder }),
25
+ React.createElement(CommandList, null,
26
+ React.createElement(CommandEmpty, null, emptyText),
27
+ React.createElement(CommandGroup, null, items.map(item => (React.createElement(CommandItem, { key: item.value, value: item.label, onSelect: () => handleSelect(item) },
28
+ item.showCheckIcon && (React.createElement(CheckIcon, { className: "jgis-combobox-check-icon", style: {
29
+ opacity: item.selected ? 1 : 0,
30
+ } })),
31
+ item.label)))))))));
32
+ }
@@ -16,7 +16,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, }
16
16
  import { cn } from './utils';
17
17
  function Command(_a) {
18
18
  var { className } = _a, props = __rest(_a, ["className"]);
19
- return (React.createElement(CommandPrimitive, Object.assign({ "data-slot": "command", className: cn('bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md', className) }, props)));
19
+ return (React.createElement(CommandPrimitive, Object.assign({ "data-slot": "command", className: cn('jgis-command', className) }, props)));
20
20
  }
21
21
  function CommandDialog(_a) {
22
22
  var { title = 'Command Palette', description = 'Search for a command to run...', children, className, showCloseButton = true } = _a, props = __rest(_a, ["title", "description", "children", "className", "showCloseButton"]);
@@ -24,18 +24,18 @@ function CommandDialog(_a) {
24
24
  React.createElement(DialogHeader, { className: "sr-only" },
25
25
  React.createElement(DialogTitle, null, title),
26
26
  React.createElement(DialogDescription, null, description)),
27
- React.createElement(DialogContent, { className: cn('overflow-hidden p-0', className), showCloseButton: showCloseButton },
28
- React.createElement(Command, { className: "[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5" }, children))));
27
+ React.createElement(DialogContent, { className: cn(className), showCloseButton: showCloseButton },
28
+ React.createElement(Command, null, children))));
29
29
  }
30
30
  function CommandInput(_a) {
31
31
  var { className } = _a, props = __rest(_a, ["className"]);
32
- return (React.createElement("div", { "data-slot": "command-input-wrapper", className: "flex h-9 items-center gap-2 border-b px-3" },
33
- React.createElement(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
34
- React.createElement(CommandPrimitive.Input, Object.assign({ "data-slot": "command-input", className: cn('placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50', className) }, props))));
32
+ return (React.createElement("div", { "data-slot": "command-input-wrapper", className: "jgis-command-input-wrapper" },
33
+ React.createElement(SearchIcon, { className: "size-4" }),
34
+ React.createElement(CommandPrimitive.Input, Object.assign({ "data-slot": "command-input", className: cn('jgis-command-input', className) }, props))));
35
35
  }
36
36
  function CommandList(_a) {
37
37
  var { className } = _a, props = __rest(_a, ["className"]);
38
- return (React.createElement(CommandPrimitive.List, Object.assign({ "data-slot": "command-list", className: cn('max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto', className) }, props)));
38
+ return (React.createElement(CommandPrimitive.List, Object.assign({ "data-slot": "command-list", className: cn('jgis-command-list', className) }, props)));
39
39
  }
40
40
  function CommandEmpty(_a) {
41
41
  var props = __rest(_a, []);
@@ -43,7 +43,7 @@ function CommandEmpty(_a) {
43
43
  }
44
44
  function CommandGroup(_a) {
45
45
  var { className } = _a, props = __rest(_a, ["className"]);
46
- return (React.createElement(CommandPrimitive.Group, Object.assign({ "data-slot": "command-group", className: cn('text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium', className) }, props)));
46
+ return (React.createElement(CommandPrimitive.Group, Object.assign({ "data-slot": "command-group", className: cn('jgis-command-group', className) }, props)));
47
47
  }
48
48
  function CommandSeparator(_a) {
49
49
  var { className } = _a, props = __rest(_a, ["className"]);
@@ -51,10 +51,10 @@ function CommandSeparator(_a) {
51
51
  }
52
52
  function CommandItem(_a) {
53
53
  var { className } = _a, props = __rest(_a, ["className"]);
54
- return (React.createElement(CommandPrimitive.Item, Object.assign({ "data-slot": "command-item", className: cn("data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className) }, props)));
54
+ return (React.createElement(CommandPrimitive.Item, Object.assign({ "data-slot": "command-item", className: cn('jgis-command-item', className) }, props)));
55
55
  }
56
56
  function CommandShortcut(_a) {
57
57
  var { className } = _a, props = __rest(_a, ["className"]);
58
- return (React.createElement("span", Object.assign({ "data-slot": "command-shortcut", className: cn('text-muted-foreground ml-auto text-xs tracking-widest', className) }, props)));
58
+ return (React.createElement("span", Object.assign({ "data-slot": "command-shortcut", className: cn('jgis-command-shortcut', className) }, props)));
59
59
  }
60
60
  export { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator, };
@@ -0,0 +1,3 @@
1
+ import * as React from 'react';
2
+ declare function Input({ className, type, ...props }: React.ComponentProps<'input'>): React.JSX.Element;
3
+ export { Input };
@@ -0,0 +1,18 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import * as React from 'react';
13
+ import { cn } from './utils';
14
+ function Input(_a) {
15
+ var { className, type } = _a, props = __rest(_a, ["className", "type"]);
16
+ return (React.createElement("input", Object.assign({ type: type, "data-slot": "input", className: cn(className) }, props)));
17
+ }
18
+ export { Input };
@@ -12,14 +12,15 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
13
13
  import * as React from 'react';
14
14
  import { Button } from './Button';
15
+ import { cn } from './utils';
15
16
  const Pagination = (_a) => {
16
17
  var props = __rest(_a, []);
17
18
  return (React.createElement("nav", Object.assign({ role: "navigation", "aria-label": "pagination", className: 'jgis-pagination' }, props)));
18
19
  };
19
20
  Pagination.displayName = 'Pagination';
20
21
  const PaginationContent = React.forwardRef((_a, ref) => {
21
- var props = __rest(_a, []);
22
- return (React.createElement("ul", Object.assign({ ref: ref, className: 'jgis-pagination-content' }, props)));
22
+ var { className } = _a, props = __rest(_a, ["className"]);
23
+ return (React.createElement("ul", Object.assign({ ref: ref, className: cn('jgis-pagination-content', className) }, props)));
23
24
  });
24
25
  PaginationContent.displayName = 'PaginationContent';
25
26
  const PaginationItem = React.forwardRef((_a, ref) => {
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ export interface ISelectItem {
3
+ value: string;
4
+ label: string;
5
+ onSelect?: () => void;
6
+ }
7
+ interface ISelectProps {
8
+ items: ISelectItem[];
9
+ buttonText: string;
10
+ emptyText?: string;
11
+ className?: string;
12
+ buttonClassName?: string;
13
+ open?: boolean;
14
+ onOpenChange?: (open: boolean) => void;
15
+ showSearch?: boolean;
16
+ searchPlaceholder?: string;
17
+ }
18
+ export declare function Select({ items, buttonText, emptyText, className, buttonClassName, open: controlledOpen, onOpenChange: controlledOnOpenChange, showSearch, searchPlaceholder, }: ISelectProps): React.JSX.Element;
19
+ export {};