@ttoss/geovis-workspace 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,691 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ Object.defineProperty(exports, Symbol.toStringTag, {
3
+ value: 'Module'
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
15
+ key = keys[i];
16
+ if (!__hasOwnProp.call(to, key) && key !== except) {
17
+ __defProp(to, key, {
18
+ get: (k => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ }
23
+ }
24
+ return to;
25
+ };
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
27
+ value: mod,
28
+ enumerable: true
29
+ }) : target, mod));
30
+
31
+ //#endregion
32
+ let _ttoss_geovis = require("@ttoss/geovis");
33
+ let _ttoss_ui = require("@ttoss/ui");
34
+ let _ttoss_react_i18n = require("@ttoss/react-i18n");
35
+ let react = require("react");
36
+ let react$1 = __toESM(react, 1);
37
+ react = __toESM(react);
38
+ let react_jsx_runtime = require("react/jsx-runtime");
39
+
40
+ //#region src/context/GeovisWorkspaceContext.ts
41
+ var GeovisWorkspaceContext = react$1.createContext(void 0);
42
+
43
+ //#endregion
44
+ //#region src/hooks/useGeovisWorkspace.ts
45
+ /**
46
+ * Consumes the GeovisWorkspace context.
47
+ * Must be used inside a GeovisWorkspaceProvider.
48
+ */
49
+ var useGeovisWorkspace = () => {
50
+ const context = react$1.useContext(GeovisWorkspaceContext);
51
+ if (!context) throw new Error("useGeovisWorkspace must be used within a GeovisWorkspaceProvider");
52
+ return context;
53
+ };
54
+
55
+ //#endregion
56
+ //#region src/messages.ts
57
+ var messages = (0, _ttoss_react_i18n.defineMessages)({
58
+ detailsTitle: {
59
+ defaultMessage: "Details",
60
+ description: "Default title shown in the right sidebar when none is set."
61
+ },
62
+ noSelection: {
63
+ defaultMessage: "Select an item to view details.",
64
+ description: "Message shown in the right sidebar when nothing is selected."
65
+ },
66
+ openMenu: {
67
+ defaultMessage: "Open menu",
68
+ description: "Accessible label for the button that opens the left sidebar."
69
+ },
70
+ closeMenu: {
71
+ defaultMessage: "Close menu",
72
+ description: "Accessible label for the button that closes the left sidebar."
73
+ },
74
+ openDetails: {
75
+ defaultMessage: "Open details",
76
+ description: "Accessible label for the button that opens the right sidebar."
77
+ },
78
+ closeDetails: {
79
+ defaultMessage: "Close details",
80
+ description: "Accessible label for the button that closes the right sidebar."
81
+ }
82
+ });
83
+
84
+ //#endregion
85
+ //#region src/components/MenuButton.tsx
86
+ /**
87
+ * Internal full-width menu item used inside the left sidebar groups.
88
+ * Highlights itself when `active` is true.
89
+ */
90
+ var MenuButton = ({
91
+ label,
92
+ active,
93
+ onClick
94
+ }) => {
95
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Box, {
96
+ as: "button",
97
+ type: "button",
98
+ "aria-pressed": active,
99
+ "data-active": active ? "" : void 0,
100
+ onClick,
101
+ sx: {
102
+ display: "block",
103
+ width: "100%",
104
+ marginBottom: "2px",
105
+ paddingBlock: "7px",
106
+ paddingInline: "10px",
107
+ border: "none",
108
+ borderRadius: "6px",
109
+ cursor: "pointer",
110
+ textAlign: "left",
111
+ fontFamily: "body",
112
+ fontSize: "14px",
113
+ lineHeight: "1.4",
114
+ letterSpacing: "0.01em",
115
+ fontWeight: active ? 600 : 500,
116
+ color: active ? "#4338ca" : "#374151",
117
+ backgroundColor: active ? "#eef2ff" : "transparent",
118
+ transition: "background-color 0.15s ease, color 0.15s ease",
119
+ "&:hover": {
120
+ backgroundColor: active ? "#e0e7ff" : "#f3f4f6",
121
+ color: "#4338ca"
122
+ },
123
+ "&:focus-visible": {
124
+ outline: "2px solid #6366f1",
125
+ outlineOffset: "1px"
126
+ }
127
+ },
128
+ children: label
129
+ });
130
+ };
131
+
132
+ //#endregion
133
+ //#region src/components/LeftSidebar.tsx
134
+ /**
135
+ * Internal left sidebar that renders the menu groups defined in the config.
136
+ * Reads and writes the per-group selection via GeovisWorkspaceContext.
137
+ */
138
+ var LeftSidebar = () => {
139
+ const {
140
+ intl: {
141
+ formatMessage
142
+ }
143
+ } = (0, _ttoss_react_i18n.useI18n)();
144
+ const {
145
+ config,
146
+ selection,
147
+ setSelection,
148
+ setLeftSidebarOpen
149
+ } = useGeovisWorkspace();
150
+ const menus = config.leftSidebar?.menus ?? [];
151
+ return /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Flex, {
152
+ sx: {
153
+ position: "relative",
154
+ flexDirection: "column",
155
+ gap: "5",
156
+ width: "256px",
157
+ height: "100%",
158
+ flexShrink: 0,
159
+ paddingX: "4",
160
+ paddingTop: "5",
161
+ paddingBottom: "4",
162
+ backgroundColor: "#ffffff",
163
+ borderRight: "1px solid #e5e7eb",
164
+ overflowY: "auto"
165
+ },
166
+ children: [/* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.IconButton, {
167
+ icon: "lucide:chevron-left",
168
+ "aria-label": formatMessage(messages.closeMenu),
169
+ onClick: event => {
170
+ event.currentTarget.blur();
171
+ setLeftSidebarOpen({
172
+ open: false
173
+ });
174
+ },
175
+ sx: {
176
+ position: "absolute",
177
+ top: "3",
178
+ right: "3",
179
+ color: "#6b7280",
180
+ backgroundColor: "transparent",
181
+ borderRadius: "md",
182
+ "&:hover": {
183
+ color: "#4338ca"
184
+ }
185
+ }
186
+ }), menus.map(menu => {
187
+ return /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Box, {
188
+ sx: {
189
+ display: "flex",
190
+ flexDirection: "column"
191
+ },
192
+ children: [/* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Text, {
193
+ sx: {
194
+ fontSize: "xs",
195
+ fontWeight: "semibold",
196
+ color: "#6b7280",
197
+ textTransform: "uppercase",
198
+ letterSpacing: "0.08em",
199
+ marginBottom: "2"
200
+ },
201
+ children: menu.title
202
+ }), menu.items.map(item => {
203
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(MenuButton, {
204
+ label: item.label,
205
+ active: selection[menu.id] === item.value,
206
+ onClick: () => {
207
+ setSelection({
208
+ menuId: menu.id,
209
+ value: item.value
210
+ });
211
+ }
212
+ }, item.value);
213
+ })]
214
+ }, menu.id);
215
+ })]
216
+ });
217
+ };
218
+
219
+ //#endregion
220
+ //#region src/components/RightSidebar.tsx
221
+ /** Renders one data-source entry, as an external link when `href` is set. */
222
+ var SourceItem = ({
223
+ label,
224
+ href
225
+ }) => {
226
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Box, {
227
+ as: "li",
228
+ sx: {
229
+ fontSize: "xs",
230
+ color: "#6b7280",
231
+ lineHeight: "base"
232
+ },
233
+ children: href ? /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Link, {
234
+ href,
235
+ target: "_blank",
236
+ rel: "noopener noreferrer",
237
+ sx: {
238
+ color: "#4338ca",
239
+ textDecoration: "underline"
240
+ },
241
+ children: label
242
+ }) : label
243
+ });
244
+ };
245
+ /**
246
+ * Color legend panel driven by `rightSidebar.legendWithColor`: an optional
247
+ * description, a swatch-per-class legend and a list of data sources. Each block
248
+ * renders only when present in the spec.
249
+ */
250
+ var LegendWithColorPanel = ({
251
+ description,
252
+ legend,
253
+ sources
254
+ }) => {
255
+ return /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Flex, {
256
+ sx: {
257
+ flexDirection: "column",
258
+ gap: "4"
259
+ },
260
+ children: [description && /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Text, {
261
+ sx: {
262
+ fontSize: "sm",
263
+ color: "#374151",
264
+ lineHeight: "base"
265
+ },
266
+ children: description
267
+ }), legend && /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Flex, {
268
+ sx: {
269
+ flexDirection: "column",
270
+ gap: "2"
271
+ },
272
+ children: [legend.title && /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Text, {
273
+ sx: {
274
+ fontSize: "xs",
275
+ fontWeight: "semibold",
276
+ textTransform: "uppercase",
277
+ letterSpacing: "0.08em",
278
+ color: "#6b7280"
279
+ },
280
+ children: legend.title
281
+ }), /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Flex, {
282
+ sx: {
283
+ flexDirection: "column",
284
+ gap: "1"
285
+ },
286
+ children: legend.items.map(item => {
287
+ return /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Flex, {
288
+ sx: {
289
+ alignItems: "center",
290
+ gap: "2"
291
+ },
292
+ children: [/* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Box, {
293
+ sx: {
294
+ width: "20px",
295
+ height: "14px",
296
+ borderRadius: "2px",
297
+ flexShrink: 0,
298
+ backgroundColor: item.color
299
+ }
300
+ }), /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Text, {
301
+ sx: {
302
+ fontSize: "xs",
303
+ color: "#374151"
304
+ },
305
+ children: item.label
306
+ })]
307
+ }, item.label);
308
+ })
309
+ })]
310
+ }), sources && /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Box, {
311
+ children: [sources.title && /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Text, {
312
+ sx: {
313
+ fontSize: "sm",
314
+ fontWeight: "semibold",
315
+ color: "#6b7280"
316
+ },
317
+ children: sources.title
318
+ }), /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Box, {
319
+ as: "ul",
320
+ sx: {
321
+ paddingLeft: "4",
322
+ marginTop: "1",
323
+ display: "flex",
324
+ flexDirection: "column",
325
+ gap: "1"
326
+ },
327
+ children: sources.items.map(source => {
328
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(SourceItem, {
329
+ ...source
330
+ }, source.label);
331
+ })
332
+ })]
333
+ })]
334
+ });
335
+ };
336
+ /**
337
+ * Internal right sidebar. Shows the config-defined title and an optional color
338
+ * legend panel. Rendered only when the config defines a rightSidebar.
339
+ */
340
+ var RightSidebar = () => {
341
+ const {
342
+ intl: {
343
+ formatMessage
344
+ }
345
+ } = (0, _ttoss_react_i18n.useI18n)();
346
+ const {
347
+ config,
348
+ setRightSidebarOpen
349
+ } = useGeovisWorkspace();
350
+ const legendWithColor = config.rightSidebar?.legendWithColor;
351
+ return /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Flex, {
352
+ sx: {
353
+ position: "relative",
354
+ flexDirection: "column",
355
+ gap: "4",
356
+ width: "256px",
357
+ height: "100%",
358
+ flexShrink: 0,
359
+ paddingX: "4",
360
+ paddingTop: "5",
361
+ paddingBottom: "4",
362
+ backgroundColor: "#ffffff",
363
+ borderLeft: "1px solid #e5e7eb",
364
+ overflowY: "auto"
365
+ },
366
+ children: [/* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.IconButton, {
367
+ icon: "lucide:chevron-right",
368
+ "aria-label": formatMessage(messages.closeDetails),
369
+ onClick: event => {
370
+ event.currentTarget.blur();
371
+ setRightSidebarOpen({
372
+ open: false
373
+ });
374
+ },
375
+ sx: {
376
+ position: "absolute",
377
+ top: "3",
378
+ right: "3",
379
+ color: "#6b7280",
380
+ backgroundColor: "transparent",
381
+ borderRadius: "md",
382
+ "&:hover": {
383
+ color: "#4338ca"
384
+ }
385
+ }
386
+ }), /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Heading, {
387
+ as: "h3",
388
+ sx: {
389
+ margin: 0,
390
+ fontSize: "xs",
391
+ fontWeight: "semibold",
392
+ textTransform: "uppercase",
393
+ letterSpacing: "0.08em",
394
+ color: "#6b7280"
395
+ },
396
+ children: config.rightSidebar?.title ?? formatMessage(messages.detailsTitle)
397
+ }), legendWithColor && /* @__PURE__ */(0, react_jsx_runtime.jsx)(LegendWithColorPanel, {
398
+ ...legendWithColor
399
+ })]
400
+ });
401
+ };
402
+
403
+ //#endregion
404
+ //#region src/components/Layout.tsx
405
+ /**
406
+ * Slide-in overlay that hosts a sidebar on the given side. The sidebar fills
407
+ * the height and is positioned absolutely so it does not push the children.
408
+ */
409
+ var SidebarOverlay = ({
410
+ side,
411
+ open,
412
+ children
413
+ }) => {
414
+ const hiddenTransform = side === "left" ? "translateX(-100%)" : "translateX(100%)";
415
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Box, {
416
+ "aria-hidden": !open,
417
+ sx: {
418
+ position: "absolute",
419
+ top: 0,
420
+ bottom: 0,
421
+ [side]: 0,
422
+ zIndex: 2,
423
+ transform: open ? "translateX(0)" : hiddenTransform,
424
+ opacity: open ? 1 : 0,
425
+ visibility: open ? "visible" : "hidden",
426
+ boxShadow: open ? "lg" : "none",
427
+ transition: "transform 0.25s ease-in-out, opacity 0.2s ease-in-out, visibility 0.25s ease-in-out, box-shadow 0.25s ease-in-out"
428
+ },
429
+ children
430
+ });
431
+ };
432
+ /**
433
+ * Floating button that opens the left sidebar. Hidden while it is open.
434
+ */
435
+ var OpenLeftSidebarButton = () => {
436
+ const {
437
+ intl: {
438
+ formatMessage
439
+ }
440
+ } = (0, _ttoss_react_i18n.useI18n)();
441
+ const {
442
+ isLeftSidebarOpen,
443
+ setLeftSidebarOpen
444
+ } = useGeovisWorkspace();
445
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.IconButton, {
446
+ icon: "lucide:sliders-horizontal",
447
+ "aria-label": formatMessage(messages.openMenu),
448
+ onClick: event => {
449
+ event.currentTarget.blur();
450
+ setLeftSidebarOpen({
451
+ open: true
452
+ });
453
+ },
454
+ "aria-hidden": isLeftSidebarOpen,
455
+ tabIndex: isLeftSidebarOpen ? -1 : 0,
456
+ sx: {
457
+ position: "absolute",
458
+ top: "4",
459
+ left: "4",
460
+ zIndex: 1,
461
+ color: "display.text.primary.default",
462
+ backgroundColor: "display.background.primary.default",
463
+ border: "sm",
464
+ borderColor: "display.border.muted.default",
465
+ boxShadow: "md",
466
+ opacity: isLeftSidebarOpen ? 0 : 1,
467
+ visibility: isLeftSidebarOpen ? "hidden" : "visible",
468
+ pointerEvents: isLeftSidebarOpen ? "none" : "auto",
469
+ transition: "opacity 0.2s ease-in-out, visibility 0.2s ease-in-out",
470
+ "&:hover": {
471
+ backgroundColor: "display.background.secondary.default"
472
+ }
473
+ }
474
+ });
475
+ };
476
+ /**
477
+ * Floating button that opens the right sidebar. Sits vertically centered on
478
+ * the right edge and is hidden while the sidebar is open.
479
+ */
480
+ var OpenRightSidebarButton = () => {
481
+ const {
482
+ intl: {
483
+ formatMessage
484
+ }
485
+ } = (0, _ttoss_react_i18n.useI18n)();
486
+ const {
487
+ isRightSidebarOpen,
488
+ setRightSidebarOpen
489
+ } = useGeovisWorkspace();
490
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.IconButton, {
491
+ icon: "lucide:chevrons-left",
492
+ "aria-label": formatMessage(messages.openDetails),
493
+ onClick: event => {
494
+ event.currentTarget.blur();
495
+ setRightSidebarOpen({
496
+ open: true
497
+ });
498
+ },
499
+ "aria-hidden": isRightSidebarOpen,
500
+ tabIndex: isRightSidebarOpen ? -1 : 0,
501
+ sx: {
502
+ position: "absolute",
503
+ top: "50%",
504
+ right: 0,
505
+ transform: "translateY(-50%)",
506
+ zIndex: 1,
507
+ borderTopLeftRadius: "md",
508
+ borderBottomLeftRadius: "md",
509
+ borderTopRightRadius: 0,
510
+ borderBottomRightRadius: 0,
511
+ color: "display.text.primary.default",
512
+ backgroundColor: "display.background.primary.default",
513
+ border: "sm",
514
+ borderColor: "display.border.muted.default",
515
+ boxShadow: "md",
516
+ opacity: isRightSidebarOpen ? 0 : 1,
517
+ visibility: isRightSidebarOpen ? "hidden" : "visible",
518
+ pointerEvents: isRightSidebarOpen ? "none" : "auto",
519
+ transition: "opacity 0.2s ease-in-out, visibility 0.2s ease-in-out",
520
+ "&:hover": {
521
+ backgroundColor: "display.background.secondary.default"
522
+ }
523
+ }
524
+ });
525
+ };
526
+ /**
527
+ * Internal layout shell. The children fill the whole area, and each sidebar
528
+ * (and its floating reopen button) is rendered only when the corresponding
529
+ * section is defined in the spec.
530
+ */
531
+ var Layout = ({
532
+ children
533
+ }) => {
534
+ const {
535
+ config,
536
+ isLeftSidebarOpen,
537
+ isRightSidebarOpen
538
+ } = useGeovisWorkspace();
539
+ const hasLeftSidebar = config.leftSidebar !== void 0;
540
+ const hasRightSidebar = config.rightSidebar !== void 0;
541
+ return /* @__PURE__ */(0, react_jsx_runtime.jsxs)(_ttoss_ui.Flex, {
542
+ sx: {
543
+ position: "relative",
544
+ overflow: "hidden",
545
+ minHeight: "440px",
546
+ border: "sm",
547
+ borderColor: "display.border.muted.default",
548
+ borderRadius: "lg",
549
+ backgroundColor: "display.background.primary.default"
550
+ },
551
+ children: [/* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Flex, {
552
+ sx: {
553
+ flex: 1
554
+ },
555
+ children
556
+ }), hasLeftSidebar && /* @__PURE__ */(0, react_jsx_runtime.jsx)(SidebarOverlay, {
557
+ side: "left",
558
+ open: isLeftSidebarOpen,
559
+ children: /* @__PURE__ */(0, react_jsx_runtime.jsx)(LeftSidebar, {})
560
+ }), hasRightSidebar && /* @__PURE__ */(0, react_jsx_runtime.jsx)(SidebarOverlay, {
561
+ side: "right",
562
+ open: isRightSidebarOpen,
563
+ children: /* @__PURE__ */(0, react_jsx_runtime.jsx)(RightSidebar, {})
564
+ }), hasLeftSidebar && /* @__PURE__ */(0, react_jsx_runtime.jsx)(OpenLeftSidebarButton, {}), hasRightSidebar && /* @__PURE__ */(0, react_jsx_runtime.jsx)(OpenRightSidebarButton, {})]
565
+ });
566
+ };
567
+
568
+ //#endregion
569
+ //#region src/GeovisWorkspaceProvider.tsx
570
+ /**
571
+ * Builds the initial selection by reading the `defaultValue` of every menu
572
+ * group in the config. Use it to seed the parent's selection state when
573
+ * controlling the workspace.
574
+ */
575
+ var getInitialSelection = ({
576
+ config
577
+ }) => {
578
+ const selection = {};
579
+ const menus = config.leftSidebar?.menus ?? [];
580
+ for (const menu of menus) selection[menu.id] = menu.defaultValue;
581
+ return selection;
582
+ };
583
+ /**
584
+ * Provides shared state for GeovisWorkspace and all internal components.
585
+ * Manages the per-group selection (controlled or uncontrolled) and the sidebar
586
+ * open state, exposing them via useGeovisWorkspace.
587
+ */
588
+ var GeovisWorkspaceProvider = ({
589
+ children,
590
+ config,
591
+ selection,
592
+ onSelectionChange
593
+ }) => {
594
+ const isControlled = selection !== void 0;
595
+ const [internalSelection, setInternalSelection] = react.useState(() => {
596
+ return getInitialSelection({
597
+ config
598
+ });
599
+ });
600
+ const currentSelection = isControlled ? selection : internalSelection;
601
+ const [isLeftSidebarOpen, setIsLeftSidebarOpen] = react.useState(false);
602
+ const [isRightSidebarOpen, setIsRightSidebarOpen] = react.useState(false);
603
+ const setSelection = react.useCallback(({
604
+ menuId,
605
+ value
606
+ }) => {
607
+ const next = {
608
+ ...currentSelection,
609
+ [menuId]: value
610
+ };
611
+ if (!isControlled) setInternalSelection(next);
612
+ onSelectionChange?.(next);
613
+ }, [currentSelection, isControlled, onSelectionChange]);
614
+ const setLeftSidebarOpen = react.useCallback(({
615
+ open
616
+ }) => {
617
+ setIsLeftSidebarOpen(open);
618
+ }, []);
619
+ const setRightSidebarOpen = react.useCallback(({
620
+ open
621
+ }) => {
622
+ setIsRightSidebarOpen(open);
623
+ }, []);
624
+ const value = react.useMemo(() => {
625
+ return {
626
+ config,
627
+ selection: currentSelection,
628
+ setSelection,
629
+ isLeftSidebarOpen,
630
+ setLeftSidebarOpen,
631
+ isRightSidebarOpen,
632
+ setRightSidebarOpen
633
+ };
634
+ }, [config, currentSelection, setSelection, isLeftSidebarOpen, setLeftSidebarOpen, isRightSidebarOpen, setRightSidebarOpen]);
635
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(GeovisWorkspaceContext.Provider, {
636
+ value,
637
+ children
638
+ });
639
+ };
640
+
641
+ //#endregion
642
+ //#region src/GeovisWorkspace.tsx
643
+ /**
644
+ * Renders the GeoVis map for the workspace inside the main content area. Kept
645
+ * as an internal component so the map fills the layout's main slot and mounts
646
+ * inside the provider tree.
647
+ */
648
+ var GeovisWorkspaceMap = ({
649
+ visualizationSpec
650
+ }) => {
651
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_ui.Box, {
652
+ sx: {
653
+ position: "relative",
654
+ flex: 1,
655
+ display: "flex",
656
+ minHeight: "440px"
657
+ },
658
+ children: /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_geovis.GeoVisProvider, {
659
+ spec: visualizationSpec,
660
+ children: /* @__PURE__ */(0, react_jsx_runtime.jsx)(_ttoss_geovis.GeoVisCanvas, {
661
+ style: {
662
+ width: "100%",
663
+ height: "100%"
664
+ }
665
+ })
666
+ })
667
+ });
668
+ };
669
+ var GeovisWorkspace = ({
670
+ config,
671
+ visualizationSpec,
672
+ variables,
673
+ onVariableChange
674
+ }) => {
675
+ return /* @__PURE__ */(0, react_jsx_runtime.jsx)(GeovisWorkspaceProvider, {
676
+ config,
677
+ selection: variables,
678
+ onSelectionChange: onVariableChange,
679
+ children: /* @__PURE__ */(0, react_jsx_runtime.jsx)(Layout, {
680
+ children: /* @__PURE__ */(0, react_jsx_runtime.jsx)(GeovisWorkspaceMap, {
681
+ visualizationSpec
682
+ })
683
+ })
684
+ });
685
+ };
686
+
687
+ //#endregion
688
+ exports.GeovisWorkspace = GeovisWorkspace;
689
+ exports.GeovisWorkspaceProvider = GeovisWorkspaceProvider;
690
+ exports.getInitialSelection = getInitialSelection;
691
+ exports.useGeovisWorkspace = useGeovisWorkspace;