@sqlrooms/deck 0.29.0-rc.11 → 0.29.0-rc.12

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 (126) hide show
  1. package/README.md +49 -13
  2. package/dist/BlockMapSettings.d.ts.map +1 -1
  3. package/dist/BlockMapSettings.js +4 -16
  4. package/dist/BlockMapSettings.js.map +1 -1
  5. package/dist/DashboardMapSettings.d.ts.map +1 -1
  6. package/dist/DashboardMapSettings.js +7 -10
  7. package/dist/DashboardMapSettings.js.map +1 -1
  8. package/dist/DeckJsonMap.d.ts.map +1 -1
  9. package/dist/DeckJsonMap.js +18 -12
  10. package/dist/DeckJsonMap.js.map +1 -1
  11. package/dist/DeckJsonMapSpec.d.ts +41 -0
  12. package/dist/DeckJsonMapSpec.d.ts.map +1 -1
  13. package/dist/DeckJsonMapSpec.js +2 -0
  14. package/dist/DeckJsonMapSpec.js.map +1 -1
  15. package/dist/DeckMapSurface.d.ts +1 -1
  16. package/dist/DeckMapSurface.js +1 -1
  17. package/dist/DeckMapSurface.js.map +1 -1
  18. package/dist/MapSettings.d.ts +14 -0
  19. package/dist/MapSettings.d.ts.map +1 -1
  20. package/dist/MapSettings.js +547 -192
  21. package/dist/MapSettings.js.map +1 -1
  22. package/dist/MapSettingsControls.d.ts +8 -1
  23. package/dist/MapSettingsControls.d.ts.map +1 -1
  24. package/dist/MapSettingsControls.js +24 -2
  25. package/dist/MapSettingsControls.js.map +1 -1
  26. package/dist/ai.d.ts.map +1 -1
  27. package/dist/ai.js +6 -3
  28. package/dist/ai.js.map +1 -1
  29. package/dist/aiNormalize.d.ts.map +1 -1
  30. package/dist/aiNormalize.js +2 -1
  31. package/dist/aiNormalize.js.map +1 -1
  32. package/dist/block.d.ts +1 -1
  33. package/dist/block.d.ts.map +1 -1
  34. package/dist/block.js +1 -1
  35. package/dist/block.js.map +1 -1
  36. package/dist/createOrUpdateDeckMapResource.d.ts +6 -2
  37. package/dist/createOrUpdateDeckMapResource.d.ts.map +1 -1
  38. package/dist/createOrUpdateDeckMapResource.js +57 -4
  39. package/dist/createOrUpdateDeckMapResource.js.map +1 -1
  40. package/dist/datasets/PreparedDatasetStore.d.ts +3 -4
  41. package/dist/datasets/PreparedDatasetStore.d.ts.map +1 -1
  42. package/dist/datasets/PreparedDatasetStore.js +4 -8
  43. package/dist/datasets/PreparedDatasetStore.js.map +1 -1
  44. package/dist/datasets/helpers.d.ts +39 -2
  45. package/dist/datasets/helpers.d.ts.map +1 -1
  46. package/dist/datasets/helpers.js +86 -3
  47. package/dist/datasets/helpers.js.map +1 -1
  48. package/dist/datasets/usePreparedDatasetStates.d.ts.map +1 -1
  49. package/dist/datasets/usePreparedDatasetStates.js +12 -8
  50. package/dist/datasets/usePreparedDatasetStates.js.map +1 -1
  51. package/dist/index.d.ts +2 -2
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +1 -1
  54. package/dist/index.js.map +1 -1
  55. package/dist/json/colorScaleFunction.d.ts +12 -4
  56. package/dist/json/colorScaleFunction.d.ts.map +1 -1
  57. package/dist/json/colorScaleFunction.js.map +1 -1
  58. package/dist/json/compileColorScale.d.ts +3 -2
  59. package/dist/json/compileColorScale.d.ts.map +1 -1
  60. package/dist/json/compileColorScale.js +16 -1
  61. package/dist/json/compileColorScale.js.map +1 -1
  62. package/dist/json/createDeckJsonConfiguration.d.ts.map +1 -1
  63. package/dist/json/createDeckJsonConfiguration.js +235 -175
  64. package/dist/json/createDeckJsonConfiguration.js.map +1 -1
  65. package/dist/json/defaultClasses.d.ts.map +1 -1
  66. package/dist/json/defaultClasses.js +3 -3
  67. package/dist/json/defaultClasses.js.map +1 -1
  68. package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
  69. package/dist/json/extractColorScaleLegends.js +41 -26
  70. package/dist/json/extractColorScaleLegends.js.map +1 -1
  71. package/dist/json/heatmapDefaults.d.ts +17 -7
  72. package/dist/json/heatmapDefaults.d.ts.map +1 -1
  73. package/dist/json/heatmapDefaults.js +54 -12
  74. package/dist/json/heatmapDefaults.js.map +1 -1
  75. package/dist/json/layers/DeckHeatmapLayer.d.ts +32 -0
  76. package/dist/json/layers/DeckHeatmapLayer.d.ts.map +1 -0
  77. package/dist/json/layers/DeckHeatmapLayer.js +69 -0
  78. package/dist/json/layers/DeckHeatmapLayer.js.map +1 -0
  79. package/dist/json/layers/index.d.ts +1 -0
  80. package/dist/json/layers/index.d.ts.map +1 -1
  81. package/dist/json/layers/index.js +1 -0
  82. package/dist/json/layers/index.js.map +1 -1
  83. package/dist/json/rewriteGeoArrowAccessors.d.ts.map +1 -1
  84. package/dist/json/rewriteGeoArrowAccessors.js +13 -5
  85. package/dist/json/rewriteGeoArrowAccessors.js.map +1 -1
  86. package/dist/json/scaleFunction.d.ts +5 -8
  87. package/dist/json/scaleFunction.d.ts.map +1 -1
  88. package/dist/json/scaleFunction.js +30 -5
  89. package/dist/json/scaleFunction.js.map +1 -1
  90. package/dist/mapAiConfig.d.ts +6 -0
  91. package/dist/mapAiConfig.d.ts.map +1 -1
  92. package/dist/mapAiConfig.js +7 -0
  93. package/dist/mapAiConfig.js.map +1 -1
  94. package/dist/mapAiSharedInstructions.d.ts +1 -1
  95. package/dist/mapAiSharedInstructions.d.ts.map +1 -1
  96. package/dist/mapAiSharedInstructions.js +3 -3
  97. package/dist/mapAiSharedInstructions.js.map +1 -1
  98. package/dist/mapConfig.d.ts +1 -1
  99. package/dist/mapConfig.d.ts.map +1 -1
  100. package/dist/mapConfig.js.map +1 -1
  101. package/dist/mapConfigUtils.d.ts +22 -0
  102. package/dist/mapConfigUtils.d.ts.map +1 -1
  103. package/dist/mapConfigUtils.js +145 -3
  104. package/dist/mapConfigUtils.js.map +1 -1
  105. package/dist/mapLayerConfigUtils.d.ts +55 -0
  106. package/dist/mapLayerConfigUtils.d.ts.map +1 -1
  107. package/dist/mapLayerConfigUtils.js +222 -11
  108. package/dist/mapLayerConfigUtils.js.map +1 -1
  109. package/dist/mapResourceAuthoring.d.ts +1 -1
  110. package/dist/mapResourceAuthoring.d.ts.map +1 -1
  111. package/dist/mapResourceAuthoring.js +14 -7
  112. package/dist/mapResourceAuthoring.js.map +1 -1
  113. package/dist/prepare/prepareDeckDataset.d.ts.map +1 -1
  114. package/dist/prepare/prepareDeckDataset.js +1 -0
  115. package/dist/prepare/prepareDeckDataset.js.map +1 -1
  116. package/dist/prepare/types.d.ts +3 -0
  117. package/dist/prepare/types.d.ts.map +1 -1
  118. package/dist/prepare/types.js.map +1 -1
  119. package/dist/prepare/wkbDecoder.d.ts.map +1 -1
  120. package/dist/prepare/wkbDecoder.js +62 -16
  121. package/dist/prepare/wkbDecoder.js.map +1 -1
  122. package/dist/prepare/wkbParser.d.ts +2 -0
  123. package/dist/prepare/wkbParser.d.ts.map +1 -1
  124. package/dist/prepare/wkbParser.js +1 -0
  125. package/dist/prepare/wkbParser.js.map +1 -1
  126. package/package.json +9 -9
package/README.md CHANGED
@@ -4,7 +4,7 @@ preparation.
4
4
 
5
5
  ## Map resources and dashboard adapters
6
6
 
7
- Worksheet maps are first-class `deckMaps` resources. The root package export
7
+ Document maps are first-class `deckMaps` resources. The root package export
8
8
  contains the resource slice, renderer, settings, direct DuckDB data adapter,
9
9
  and resource orchestration APIs. It does not require Mosaic.
10
10
 
@@ -14,14 +14,14 @@ selection, and issue translation inside that adapter boundary.
14
14
 
15
15
  `DeckMapSettingsPanel` is the shared host-neutral editor for both surfaces. It
16
16
  receives a map config, selected table, available tables, and edit callbacks;
17
- worksheet resources and Mosaic panels only adapt their respective stores to
17
+ document resources and Mosaic panels only adapt their respective stores to
18
18
  that contract. Layer, binding, style, extrusion, and code-view controls therefore
19
- stay consistent without putting Mosaic APIs in the worksheet settings path.
19
+ stay consistent without putting Mosaic APIs in the document settings path.
20
20
 
21
21
  Use `getDeckMapDataPolicy(...)` to resolve a map config into the exported
22
22
  `DeckMapDataPolicy` runtime row-limit policy.
23
23
 
24
- Worksheet map runtime issues distinguish dataset SQL failures (`sql-error`)
24
+ Document map runtime issues distinguish dataset SQL failures (`sql-error`)
25
25
  from fit-to-data bounds failures (`fit-error`), so each issue is cleared only
26
26
  after its corresponding operation recovers.
27
27
 
@@ -29,7 +29,7 @@ after its corresponding operation recovers.
29
29
  fit-to-data bounds queries. The direct adapter uses the authored source for
30
30
  bounds while applying the configured row-limit policy only to rendered rows.
31
31
 
32
- Worksheet maps deliberately use independent selection semantics. Their direct
32
+ Document maps deliberately use independent selection semantics. Their direct
33
33
  data adapter executes each configured SQL/table dataset through the room's
34
34
  DuckDB connector and neither reads nor publishes Mosaic selections. This drops
35
35
  the old incidental intra-map cross-filtering between datasets; a future
@@ -268,11 +268,11 @@ Runtime issue recovery can call `deckMaps.clearMapIssue(mapId, kind)` to clear
268
268
  only a matching issue kind; omit `kind` when the map state should clear any
269
269
  stale issue. Replacing a map config clears its prior render issue, while data
270
270
  issues remain until the corresponding dataset recovery is reported.
271
- Direct worksheet maps automatically fit the configured dataset when the map or
271
+ Direct document maps automatically fit the configured dataset when the map or
272
272
  its source first becomes ready; the header action remains available for manual
273
273
  refitting.
274
274
 
275
- Hosts that expose direct worksheet-map AI capability should include
275
+ Hosts that expose direct document-map AI capability should include
276
276
  `getDeckMapResourceAiInstructions()` in the responsible agent and tool
277
277
  instructions. `createOrUpdateDeckMapResource(...)` validates the fully merged
278
278
  resource before any durable block or map write: each dataset needs a
@@ -334,6 +334,11 @@ const result = await createOrUpdateDeckMapResource(
334
334
  blockDocumentId,
335
335
  mapId,
336
336
  config,
337
+ pointBinding: {
338
+ dataset: 'places',
339
+ longitudeColumn: 'longitude',
340
+ latitudeColumn: 'latitude',
341
+ },
337
342
  tableName,
338
343
  title,
339
344
  intent,
@@ -355,10 +360,22 @@ title and uses it as the default block caption. Block metadata is written only
355
360
  after the map write succeeds.
356
361
 
357
362
  Map authoring helpers such as `normalizeDeckMapPointConfig(...)`,
358
- `normalizeDeckMapFillColor(...)`, `regenerateMapConfigForTable(...)`, and
363
+ `applyDeckMapPointBinding(...)`, `normalizeDeckMapFillColor(...)`,
364
+ `regenerateMapConfigForTable(...)`, and
359
365
  dataset-source helpers such as `getFirstDatasetSourceTableName(...)` are
360
366
  exported so hosts can normalize AI-authored configs before calling
361
- `createOrUpdateDeckMapResource(...)`. `normalizeDeckMapPointConfig(...)` only adds
367
+ `createOrUpdateDeckMapResource(...)`. Passing structured `pointBinding` to the
368
+ resource helper applies `applyDeckMapPointBinding(...)`: it generates canonical
369
+ WKB point SQL through `createDeckMapPointTransformSql(...)` and aligns the target
370
+ dataset, point layers, brush interaction, and fit binding. The host table lookup
371
+ also supplies source columns so missing coordinate columns and a generated
372
+ geometry alias that would duplicate an existing column are rejected before
373
+ durable state is written. For a single table-backed dataset, its canonical table
374
+ identity must also match the selected table because that selection overrides the
375
+ authored dataset source at render time. This is the preferred path for standard
376
+ table-backed longitude/latitude maps; raw `transformSql` remains available for
377
+ custom spatial transforms.
378
+ `normalizeDeckMapPointConfig(...)` only adds
362
379
  the standard lon/lat point transform to table-backed datasets that do not
363
380
  already declare `geometryColumn`, `source.sqlQuery`, or `source.transformSql`
364
381
  and whose resolved table does not expose a native geometry column; native
@@ -540,6 +557,21 @@ getFillColor: {
540
557
  }
541
558
  ```
542
559
 
560
+ Optional `opacity` (0–1) is a SQLRooms `colorScale` extension. The compiler
561
+ multiplies it into the color's alpha so fill, stroke, and arc endpoints can be
562
+ dimmed independently of deck.gl `layer.opacity`:
563
+
564
+ ```tsx
565
+ getFillColor: {
566
+ '@@function': 'colorScale',
567
+ field: 'Magnitude',
568
+ type: 'sequential',
569
+ scheme: 'YlOrRd',
570
+ domain: 'auto',
571
+ opacity: 0.6,
572
+ }
573
+ ```
574
+
543
575
  Discrete numeric palettes are supported too:
544
576
 
545
577
  ```tsx
@@ -597,6 +629,10 @@ scenes. It accepts resolved Arrow tables with geometry stored as:
597
629
  - WKB / GeoArrow WKB
598
630
  - WKT / GeoArrow WKT
599
631
 
632
+ The returned `PreparedDeckDataset` records the dataset-level
633
+ `datasetGeometryColumn` and `datasetGeometryEncodingHint` used to prepare
634
+ and identify that payload.
635
+
600
636
  It then produces canonical deck-facing geometry outputs for:
601
637
 
602
638
  - GeoArrow-native layers such as `GeoArrowScatterplotLayer`
@@ -624,7 +660,6 @@ The current curated layer set is:
624
660
  - `GeoArrowColumnLayer`
625
661
  - `GeoArrowPathLayer`
626
662
  - `GeoArrowPolygonLayer`
627
- - `GeoArrowSolidPolygonLayer`
628
663
  - `GeoArrowArcLayer`
629
664
  - `GeoArrowTripsLayer`
630
665
  - `GeoArrowH3HexagonLayer`
@@ -634,7 +669,7 @@ GeoArrow-native geometry columns are the efficient path. WKB/WKT geometry falls
634
669
  back to decoding and GeoJSON-binary preparation, with promotion available
635
670
  for point-focused GeoArrow layers such as `GeoArrowScatterplotLayer`,
636
671
  `GeoArrowHeatmapLayer`, and `GeoArrowColumnLayer`, plus Polygon promotion for
637
- `GeoArrowPolygonLayer` and `GeoArrowSolidPolygonLayer`. WKB/WKT MultiPolygon
672
+ `GeoArrowPolygonLayer`. WKB/WKT MultiPolygon
638
673
  uses the GeoJSON-binary path so separate polygon parts retain their nesting.
639
674
 
640
675
  The GeoArrow layer implementations themselves come from
@@ -674,8 +709,9 @@ helpers exported from `@sqlrooms/deck`:
674
709
  (aliases may be transform-only).
675
710
 
676
711
  Durable resource writes also run `getDeckMapResourceConfigIssues` /
677
- `assertDeckMapResourceConfig` for syntax and type/scheme compatibility
678
- (e.g. `quantile` + `Viridis` is rejected). Native `GEOMETRY` columns are
712
+ `assertDeckMapResourceConfig` for syntax, supported layer types, and type/scheme
713
+ compatibility (e.g. `quantile` + `Viridis` is rejected; layer `@@type` must be
714
+ one of the settings picker classes). Native `GEOMETRY` columns are
679
715
  normalized to WKB by the dataset pipeline (not by SQL-string validation).
680
716
 
681
717
  ## Runtime Props and Children
@@ -1 +1 @@
1
- {"version":3,"file":"BlockMapSettings.d.ts","sourceRoot":"","sources":["../src/BlockMapSettings.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,2BAA2B,EAEjC,MAAM,qBAAqB,CAAC;AAS7B,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,WAAW,EACX,eAAe,EACf,OAAO,EACP,QAAQ,GACT,EAAE,2BAA2B,2CA0G7B"}
1
+ {"version":3,"file":"BlockMapSettings.d.ts","sourceRoot":"","sources":["../src/BlockMapSettings.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,2BAA2B,EAEjC,MAAM,qBAAqB,CAAC;AAM7B,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,WAAW,EACX,eAAe,EACf,OAAO,EACP,QAAQ,GACT,EAAE,2BAA2B,2CA2E7B"}
@@ -1,13 +1,10 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { getTableIdentity } from '@sqlrooms/duckdb';
3
3
  import { blockDocumentContentToBlocks, useStoreWithBlockDocuments, } from '@sqlrooms/documents';
4
- import { Button } from '@sqlrooms/ui';
5
- import { XIcon } from 'lucide-react';
6
4
  import { useCallback, useMemo } from 'react';
7
5
  import { useStoreWithDeckMaps } from './DeckMapsSlice';
8
6
  import { DeckMapSettingsPanel } from './MapSettings';
9
- import { regenerateMapConfigForTable } from './mapConfigUtils';
10
- import { getDeckMapResourceConfigIssues } from './mapResourceAuthoring';
7
+ import { applyDeckMapTableSelection } from './mapConfigUtils';
11
8
  export function DeckMapBlockSettings({ blockId, dashboardId, blockInstanceId, onClose, readOnly, }) {
12
9
  const mapId = blockInstanceId ?? blockId;
13
10
  const map = useStoreWithDeckMaps((state) => state.deckMaps.config.mapsById[mapId]);
@@ -22,7 +19,6 @@ export function DeckMapBlockSettings({ blockId, dashboardId, blockInstanceId, on
22
19
  candidate.type === 'statefulBlock' &&
23
20
  candidate.blockType === 'map')
24
21
  : undefined, [artifact, blockId]);
25
- const configIssues = useMemo(() => map ? getDeckMapResourceConfigIssues(map.config, { allowEmpty: true }) : [], [map]);
26
22
  const handleTitleChange = useCallback((title) => {
27
23
  if (readOnly)
28
24
  return;
@@ -37,21 +33,13 @@ export function DeckMapBlockSettings({ blockId, dashboardId, blockInstanceId, on
37
33
  const handleTableChange = useCallback((table) => {
38
34
  if (readOnly || !map)
39
35
  return;
40
- const config = regenerateMapConfigForTable({ config: map.config }, table);
41
- if (config === map.config)
42
- return;
43
36
  updateMap(mapId, {
44
37
  selectedTable: getTableIdentity(table.table),
45
- config: config,
38
+ config: applyDeckMapTableSelection(map.config, table),
46
39
  });
47
40
  }, [map, mapId, readOnly, updateMap]);
48
41
  if (!map)
49
42
  return (_jsx("div", { className: "text-muted-foreground p-4 text-sm", children: "Map settings not available" }));
50
- if (configIssues.length > 0 || map.config.configMode === 'custom') {
51
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-3 py-1.5 text-xs font-medium", children: [_jsx("span", { children: "Map settings" }), onClose ? (_jsx(Button, { variant: "ghost", size: "icon", className: "h-5 w-5", onClick: onClose, "aria-label": "Close", children: _jsx(XIcon, { className: "h-3.5 w-3.5" }) })) : null] }), _jsx("div", { className: "text-muted-foreground flex flex-1 items-center justify-center p-4 text-center text-sm", children: configIssues.length > 0
52
- ? `Invalid map configuration: ${configIssues[0].path}: ${configIssues[0].message}`
53
- : 'This custom map configuration cannot be safely edited with the basic settings controls.' })] }));
54
- }
55
- return (_jsx(DeckMapSettingsPanel, { title: block?.caption ?? map.title, selectedTable: map.selectedTable, config: map.config, tables: tables.filter((table) => table.columns.length > 0), onClose: onClose, onTitleChange: handleTitleChange, onTableChange: handleTableChange, onConfigChange: (config) => updateMap(mapId, { config }), readOnly: readOnly }));
43
+ return (_jsx(DeckMapSettingsPanel, { title: block?.caption ?? map.title, selectedTable: map.selectedTable, config: map.config, tables: tables.filter((table) => table.columns.length > 0), onClose: onClose, onTitleChange: handleTitleChange, onTableChange: handleTableChange, onConfigChange: (config) => updateMap(mapId, { config }), readOnly: readOnly, customConfig: map.config.configMode === 'custom', preferDatasetSource: true }));
56
44
  }
57
45
  //# sourceMappingURL=BlockMapSettings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlockMapSettings.js","sourceRoot":"","sources":["../src/BlockMapSettings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {getTableIdentity, type DataTable} from '@sqlrooms/duckdb';\nimport {\n blockDocumentContentToBlocks,\n type BlockDocumentStatefulBlockBlock,\n type BlockSettingsComponentProps,\n useStoreWithBlockDocuments,\n} from '@sqlrooms/documents';\nimport {Button} from '@sqlrooms/ui';\nimport {XIcon} from 'lucide-react';\nimport {useCallback, useMemo} from 'react';\nimport {useStoreWithDeckMaps} from './DeckMapsSlice';\nimport {DeckMapSettingsPanel} from './MapSettings';\nimport {regenerateMapConfigForTable} from './mapConfigUtils';\nimport {getDeckMapResourceConfigIssues} from './mapResourceAuthoring';\n\nexport function DeckMapBlockSettings({\n blockId,\n dashboardId,\n blockInstanceId,\n onClose,\n readOnly,\n}: BlockSettingsComponentProps) {\n const mapId = blockInstanceId ?? blockId;\n const map = useStoreWithDeckMaps(\n (state) => state.deckMaps.config.mapsById[mapId],\n );\n const tables = useStoreWithDeckMaps((state) => state.db.tables);\n const updateMap = useStoreWithDeckMaps((state) => state.deckMaps.updateMap);\n const artifact = useStoreWithBlockDocuments((state) =>\n dashboardId\n ? state.blockDocuments.config.artifacts[dashboardId]\n : undefined,\n );\n const updateBlock = useStoreWithBlockDocuments(\n (state) => state.blockDocuments.updateBlock,\n );\n const block = useMemo(\n () =>\n artifact\n ? blockDocumentContentToBlocks(artifact.content).find(\n (candidate): candidate is BlockDocumentStatefulBlockBlock =>\n candidate.id === blockId &&\n candidate.type === 'statefulBlock' &&\n candidate.blockType === 'map',\n )\n : undefined,\n [artifact, blockId],\n );\n const configIssues = useMemo(\n () =>\n map ? getDeckMapResourceConfigIssues(map.config, {allowEmpty: true}) : [],\n [map],\n );\n\n const handleTitleChange = useCallback(\n (title: string) => {\n if (readOnly) return;\n updateMap(mapId, {title});\n if (dashboardId && block) {\n updateBlock(dashboardId, blockId, {\n ...block,\n caption: title || undefined,\n });\n }\n },\n [block, blockId, dashboardId, mapId, readOnly, updateBlock, updateMap],\n );\n\n const handleTableChange = useCallback(\n (table: DataTable) => {\n if (readOnly || !map) return;\n const config = regenerateMapConfigForTable({config: map.config}, table);\n if (config === map.config) return;\n updateMap(mapId, {\n selectedTable: getTableIdentity(table.table),\n config: config as typeof map.config,\n });\n },\n [map, mapId, readOnly, updateMap],\n );\n\n if (!map)\n return (\n <div className=\"text-muted-foreground p-4 text-sm\">\n Map settings not available\n </div>\n );\n\n if (configIssues.length > 0 || map.config.configMode === 'custom') {\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between border-b px-3 py-1.5 text-xs font-medium\">\n <span>Map settings</span>\n {onClose ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-5 w-5\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n <XIcon className=\"h-3.5 w-3.5\" />\n </Button>\n ) : null}\n </div>\n <div className=\"text-muted-foreground flex flex-1 items-center justify-center p-4 text-center text-sm\">\n {configIssues.length > 0\n ? `Invalid map configuration: ${configIssues[0]!.path}: ${configIssues[0]!.message}`\n : 'This custom map configuration cannot be safely edited with the basic settings controls.'}\n </div>\n </div>\n );\n }\n\n return (\n <DeckMapSettingsPanel\n title={block?.caption ?? map.title}\n selectedTable={map.selectedTable}\n config={map.config}\n tables={tables.filter((table) => table.columns.length > 0)}\n onClose={onClose}\n onTitleChange={handleTitleChange}\n onTableChange={handleTableChange}\n onConfigChange={(config) => updateMap(mapId, {config})}\n readOnly={readOnly}\n />\n );\n}\n"]}
1
+ {"version":3,"file":"BlockMapSettings.js","sourceRoot":"","sources":["../src/BlockMapSettings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {getTableIdentity, type DataTable} from '@sqlrooms/duckdb';\nimport {\n blockDocumentContentToBlocks,\n type BlockDocumentStatefulBlockBlock,\n type BlockSettingsComponentProps,\n useStoreWithBlockDocuments,\n} from '@sqlrooms/documents';\nimport {useCallback, useMemo} from 'react';\nimport {useStoreWithDeckMaps} from './DeckMapsSlice';\nimport {DeckMapSettingsPanel} from './MapSettings';\nimport {applyDeckMapTableSelection} from './mapConfigUtils';\n\nexport function DeckMapBlockSettings({\n blockId,\n dashboardId,\n blockInstanceId,\n onClose,\n readOnly,\n}: BlockSettingsComponentProps) {\n const mapId = blockInstanceId ?? blockId;\n const map = useStoreWithDeckMaps(\n (state) => state.deckMaps.config.mapsById[mapId],\n );\n const tables = useStoreWithDeckMaps((state) => state.db.tables);\n const updateMap = useStoreWithDeckMaps((state) => state.deckMaps.updateMap);\n const artifact = useStoreWithBlockDocuments((state) =>\n dashboardId\n ? state.blockDocuments.config.artifacts[dashboardId]\n : undefined,\n );\n const updateBlock = useStoreWithBlockDocuments(\n (state) => state.blockDocuments.updateBlock,\n );\n const block = useMemo(\n () =>\n artifact\n ? blockDocumentContentToBlocks(artifact.content).find(\n (candidate): candidate is BlockDocumentStatefulBlockBlock =>\n candidate.id === blockId &&\n candidate.type === 'statefulBlock' &&\n candidate.blockType === 'map',\n )\n : undefined,\n [artifact, blockId],\n );\n\n const handleTitleChange = useCallback(\n (title: string) => {\n if (readOnly) return;\n updateMap(mapId, {title});\n if (dashboardId && block) {\n updateBlock(dashboardId, blockId, {\n ...block,\n caption: title || undefined,\n });\n }\n },\n [block, blockId, dashboardId, mapId, readOnly, updateBlock, updateMap],\n );\n\n const handleTableChange = useCallback(\n (table: DataTable) => {\n if (readOnly || !map) return;\n updateMap(mapId, {\n selectedTable: getTableIdentity(table.table),\n config: applyDeckMapTableSelection(map.config, table),\n });\n },\n [map, mapId, readOnly, updateMap],\n );\n\n if (!map)\n return (\n <div className=\"text-muted-foreground p-4 text-sm\">\n Map settings not available\n </div>\n );\n\n return (\n <DeckMapSettingsPanel\n title={block?.caption ?? map.title}\n selectedTable={map.selectedTable}\n config={map.config}\n tables={tables.filter((table) => table.columns.length > 0)}\n onClose={onClose}\n onTitleChange={handleTitleChange}\n onTableChange={handleTableChange}\n onConfigChange={(config) => updateMap(mapId, {config})}\n readOnly={readOnly}\n customConfig={map.config.configMode === 'custom'}\n preferDatasetSource\n />\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardMapSettings.d.ts","sourceRoot":"","sources":["../src/DashboardMapSettings.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,qBAAqB,CAAC;AASrE,OAAO,EAAC,KAAK,EAAE,EAAc,MAAM,OAAO,CAAC;AAQ3C;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,EAAE,CAAC,2BAA2B,CAoHpE,CAAC"}
1
+ {"version":3,"file":"DashboardMapSettings.d.ts","sourceRoot":"","sources":["../src/DashboardMapSettings.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,qBAAqB,CAAC;AAOrE,OAAO,EAAC,KAAK,EAAE,EAAc,MAAM,OAAO,CAAC;AAQ3C;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,EAAE,CAAC,2BAA2B,CA+FpE,CAAC"}
@@ -1,8 +1,6 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { getTableIdentity } from '@sqlrooms/duckdb';
3
3
  import { ConfirmDatasetChangeDialog, useConfirmDatasetChange, useStoreWithMosaicDashboard, useTablesWithColumns, } from '@sqlrooms/mosaic';
4
- import { Button } from '@sqlrooms/ui';
5
- import { XIcon } from 'lucide-react';
6
4
  import { useCallback } from 'react';
7
5
  import { DeckMapSettingsPanel } from './MapSettings';
8
6
  import { DECK_MAP_DASHBOARD_PANEL_TYPE, } from './dashboardConfig';
@@ -36,17 +34,16 @@ export const DeckMapDashboardSettings = ({ blockId, dashboardId, onClose, readOn
36
34
  });
37
35
  }, [blockId, dashboardId, readOnly, updatePanel]);
38
36
  const { handleChangeRequest, handleConfirm, handleCancel, isDialogOpen } = useConfirmDatasetChange(handleTableChange);
37
+ const panel = dashboard?.panels.find((candidate) => candidate.id === blockId);
38
+ const mapConfig = panel?.type === DECK_MAP_DASHBOARD_PANEL_TYPE
39
+ ? panel.config
40
+ : undefined;
39
41
  if (!dashboard) {
40
42
  return (_jsx("div", { className: "flex h-full items-center justify-center p-4", children: _jsx("p", { className: "text-muted-foreground text-sm", children: "Dashboard not found" }) }));
41
43
  }
42
- const panel = dashboard.panels.find((candidate) => candidate.id === blockId);
43
- if (!panel || panel.type !== DECK_MAP_DASHBOARD_PANEL_TYPE) {
44
+ if (!panel || !mapConfig) {
44
45
  return (_jsx("div", { className: "flex h-full items-center justify-center p-4", children: _jsx("p", { className: "text-muted-foreground text-sm", children: "Map panel not found" }) }));
45
46
  }
46
- const mapConfig = panel.config;
47
- if (mapConfig.configMode === 'custom') {
48
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-3 py-1.5 text-xs font-medium", children: [_jsx("span", { children: "Map settings" }), onClose ? (_jsx(Button, { variant: "ghost", size: "icon", className: "h-5 w-5", onClick: onClose, "aria-label": "Close", children: _jsx(XIcon, { className: "h-3.5 w-3.5" }) })) : null] }), _jsx("div", { className: "text-muted-foreground flex flex-1 items-center justify-center p-4 text-center text-sm", children: "This custom map configuration cannot be safely edited with the basic settings controls." })] }));
49
- }
50
- return (_jsxs(_Fragment, { children: [_jsx(DeckMapSettingsPanel, { title: panel.title, selectedTable: dashboard.selectedTable, config: mapConfig, tables: tables, onClose: onClose, onTableChange: handleChangeRequest, onTitleChange: handleTitleChange, onConfigChange: handleConfigChange, readOnly: readOnly }), _jsx(ConfirmDatasetChangeDialog, { open: isDialogOpen, onConfirm: handleConfirm, onCancel: handleCancel })] }));
47
+ return (_jsxs(_Fragment, { children: [_jsx(DeckMapSettingsPanel, { title: panel.title, selectedTable: dashboard.selectedTable, config: mapConfig, tables: tables, onClose: onClose, onTableChange: handleChangeRequest, onTitleChange: handleTitleChange, onConfigChange: handleConfigChange, readOnly: readOnly, customConfig: mapConfig.configMode === 'custom' }), _jsx(ConfirmDatasetChangeDialog, { open: isDialogOpen, onConfirm: handleConfirm, onCancel: handleCancel })] }));
51
48
  };
52
49
  //# sourceMappingURL=DashboardMapSettings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardMapSettings.js","sourceRoot":"","sources":["../src/DashboardMapSettings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {getTableIdentity, type DataTable} from '@sqlrooms/duckdb';\nimport type {BlockSettingsComponentProps} from '@sqlrooms/documents';\nimport {\n ConfirmDatasetChangeDialog,\n useConfirmDatasetChange,\n useStoreWithMosaicDashboard,\n useTablesWithColumns,\n} from '@sqlrooms/mosaic';\nimport {Button} from '@sqlrooms/ui';\nimport {XIcon} from 'lucide-react';\nimport {type FC, useCallback} from 'react';\nimport {DeckMapSettingsPanel} from './MapSettings';\nimport {\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n type DeckMapDashboardPanelConfig,\n} from './dashboardConfig';\nimport type {DeckMapConfig} from './mapConfig';\n\n/**\n * Settings adapter for a Deck map panel inside a Mosaic dashboard.\n */\nexport const DeckMapDashboardSettings: FC<BlockSettingsComponentProps> = ({\n blockId,\n dashboardId,\n onClose,\n readOnly,\n}) => {\n const dashboard = useStoreWithMosaicDashboard((state) =>\n dashboardId ? state.mosaicDashboard.getDashboard(dashboardId) : undefined,\n );\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n const setSelectedTable = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.setSelectedTable,\n );\n const tables = useTablesWithColumns();\n\n const handleTableChange = useCallback(\n (table: DataTable) => {\n if (readOnly) return;\n\n if (dashboardId) {\n setSelectedTable(dashboardId, getTableIdentity(table.table));\n }\n },\n [dashboardId, readOnly, setSelectedTable],\n );\n\n const handleTitleChange = useCallback(\n (title: string) => {\n if (readOnly) return;\n\n if (dashboardId) {\n updatePanel(dashboardId, blockId, {title: title || undefined});\n }\n },\n [dashboardId, blockId, readOnly, updatePanel],\n );\n\n const handleConfigChange = useCallback(\n (config: DeckMapConfig) => {\n if (readOnly || !dashboardId) return;\n updatePanel(dashboardId, blockId, {\n config: config as unknown as Record<string, unknown>,\n });\n },\n [blockId, dashboardId, readOnly, updatePanel],\n );\n\n const {handleChangeRequest, handleConfirm, handleCancel, isDialogOpen} =\n useConfirmDatasetChange(handleTableChange);\n\n if (!dashboard) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <p className=\"text-muted-foreground text-sm\">Dashboard not found</p>\n </div>\n );\n }\n\n const panel = dashboard.panels.find((candidate) => candidate.id === blockId);\n\n if (!panel || panel.type !== DECK_MAP_DASHBOARD_PANEL_TYPE) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <p className=\"text-muted-foreground text-sm\">Map panel not found</p>\n </div>\n );\n }\n\n const mapConfig = panel.config as DeckMapDashboardPanelConfig;\n if (mapConfig.configMode === 'custom') {\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between border-b px-3 py-1.5 text-xs font-medium\">\n <span>Map settings</span>\n {onClose ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-5 w-5\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n <XIcon className=\"h-3.5 w-3.5\" />\n </Button>\n ) : null}\n </div>\n <div className=\"text-muted-foreground flex flex-1 items-center justify-center p-4 text-center text-sm\">\n This custom map configuration cannot be safely edited with the basic\n settings controls.\n </div>\n </div>\n );\n }\n\n return (\n <>\n <DeckMapSettingsPanel\n title={panel.title}\n selectedTable={dashboard.selectedTable}\n config={mapConfig}\n tables={tables}\n onClose={onClose}\n onTableChange={handleChangeRequest}\n onTitleChange={handleTitleChange}\n onConfigChange={handleConfigChange}\n readOnly={readOnly}\n />\n <ConfirmDatasetChangeDialog\n open={isDialogOpen}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n </>\n );\n};\n"]}
1
+ {"version":3,"file":"DashboardMapSettings.js","sourceRoot":"","sources":["../src/DashboardMapSettings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {getTableIdentity, type DataTable} from '@sqlrooms/duckdb';\nimport type {BlockSettingsComponentProps} from '@sqlrooms/documents';\nimport {\n ConfirmDatasetChangeDialog,\n useConfirmDatasetChange,\n useStoreWithMosaicDashboard,\n useTablesWithColumns,\n} from '@sqlrooms/mosaic';\nimport {type FC, useCallback} from 'react';\nimport {DeckMapSettingsPanel} from './MapSettings';\nimport {\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n type DeckMapDashboardPanelConfig,\n} from './dashboardConfig';\nimport type {DeckMapConfig} from './mapConfig';\n\n/**\n * Settings adapter for a Deck map panel inside a Mosaic dashboard.\n */\nexport const DeckMapDashboardSettings: FC<BlockSettingsComponentProps> = ({\n blockId,\n dashboardId,\n onClose,\n readOnly,\n}) => {\n const dashboard = useStoreWithMosaicDashboard((state) =>\n dashboardId ? state.mosaicDashboard.getDashboard(dashboardId) : undefined,\n );\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n const setSelectedTable = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.setSelectedTable,\n );\n const tables = useTablesWithColumns();\n\n const handleTableChange = useCallback(\n (table: DataTable) => {\n if (readOnly) return;\n\n if (dashboardId) {\n setSelectedTable(dashboardId, getTableIdentity(table.table));\n }\n },\n [dashboardId, readOnly, setSelectedTable],\n );\n\n const handleTitleChange = useCallback(\n (title: string) => {\n if (readOnly) return;\n\n if (dashboardId) {\n updatePanel(dashboardId, blockId, {title: title || undefined});\n }\n },\n [dashboardId, blockId, readOnly, updatePanel],\n );\n\n const handleConfigChange = useCallback(\n (config: DeckMapConfig) => {\n if (readOnly || !dashboardId) return;\n updatePanel(dashboardId, blockId, {\n config: config as unknown as Record<string, unknown>,\n });\n },\n [blockId, dashboardId, readOnly, updatePanel],\n );\n\n const {handleChangeRequest, handleConfirm, handleCancel, isDialogOpen} =\n useConfirmDatasetChange(handleTableChange);\n\n const panel = dashboard?.panels.find((candidate) => candidate.id === blockId);\n const mapConfig =\n panel?.type === DECK_MAP_DASHBOARD_PANEL_TYPE\n ? (panel.config as DeckMapDashboardPanelConfig)\n : undefined;\n\n if (!dashboard) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <p className=\"text-muted-foreground text-sm\">Dashboard not found</p>\n </div>\n );\n }\n\n if (!panel || !mapConfig) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <p className=\"text-muted-foreground text-sm\">Map panel not found</p>\n </div>\n );\n }\n\n return (\n <>\n <DeckMapSettingsPanel\n title={panel.title}\n selectedTable={dashboard.selectedTable}\n config={mapConfig}\n tables={tables}\n onClose={onClose}\n onTableChange={handleChangeRequest}\n onTitleChange={handleTitleChange}\n onConfigChange={handleConfigChange}\n readOnly={readOnly}\n customConfig={mapConfig.configMode === 'custom'}\n />\n <ConfirmDatasetChangeDialog\n open={isDialogOpen}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n </>\n );\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"DeckJsonMap.d.ts","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"AAIA,OAAO,kCAAkC,CAAC;AAyB1C,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,SAAS,CAAC;AAgPjB,eAAO,MAAM,WAAW,gHA0VvB,CAAC"}
1
+ {"version":3,"file":"DeckJsonMap.d.ts","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"AAYA,OAAO,kCAAkC,CAAC;AAyB1C,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,SAAS,CAAC;AA+QjB,eAAO,MAAM,WAAW,gHAuVvB,CAAC"}
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { JSONConverter } from '@deck.gl/json';
3
3
  import { MapboxOverlay } from '@deck.gl/mapbox';
4
4
  import { ColorScaleLegend } from '@sqlrooms/color-scales';
5
- import { cn, useTheme } from '@sqlrooms/ui';
5
+ import { cn, Collapsible, CollapsibleContent, CollapsibleTrigger, useTheme, } from '@sqlrooms/ui';
6
+ import { ChevronRightIcon } from 'lucide-react';
6
7
  import 'maplibre-gl/dist/maplibre-gl.css';
7
8
  import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
8
9
  import { forwardRef } from 'react';
@@ -103,6 +104,14 @@ const TripsTimeControl = ({ currentTime, maxTime, playing, onPlayPause, onSeek }
103
104
  }
104
105
  return (_jsxs("div", { className: "bg-background/90 border-border/70 pointer-events-auto relative flex items-center gap-1.5 rounded-md border px-2 py-1.5 pr-7 shadow-sm backdrop-blur-sm", children: [_jsx("button", { type: "button", onClick: onPlayPause, className: "text-foreground hover:bg-accent flex h-5 w-5 shrink-0 items-center justify-center rounded", title: playing ? 'Pause' : 'Play', children: playing ? (_jsxs("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "currentColor", children: [_jsx("rect", { x: "1", y: "1", width: "3", height: "8" }), _jsx("rect", { x: "6", y: "1", width: "3", height: "8" })] })) : (_jsx("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "currentColor", children: _jsx("polygon", { points: "2,1 9,5 2,9" }) })) }), _jsx("input", { type: "range", min: 0, max: 1000, value: Math.round(progress * 1000), onChange: (e) => onSeek((Number(e.target.value) / 1000) * maxTime), className: "h-1 w-24 flex-1 cursor-pointer" }), _jsx("button", { type: "button", onClick: () => setCollapsed(true), className: "text-muted-foreground hover:text-foreground absolute top-1.5 right-1.5 flex h-4 w-4 items-center justify-center rounded-sm transition-colors", title: "Collapse", children: _jsx("svg", { width: "8", height: "8", viewBox: "0 0 8 8", children: _jsx("path", { d: "M1 1L7 7M7 1L1 7", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })] }));
105
106
  };
107
+ function getDeckLayerTypeName(layer) {
108
+ if (!layer || typeof layer !== 'object')
109
+ return '?';
110
+ const ctor = layer.constructor;
111
+ // Prefer static layerName: table-to-RecordBatch adapters all share
112
+ // constructor.name "Adapter", which would miss heatmap ↔ scatterplot swaps.
113
+ return ctor?.layerName ?? ctor?.name ?? '?';
114
+ }
106
115
  // Workaround for deck.gl HeatmapLayer not releasing its WebGL framebuffer
107
116
  // when replaced by another layer type (e.g. switching heatmap → scatterplot).
108
117
  // We detect layer class changes and clear layers for one animation frame,
@@ -114,14 +123,7 @@ function DeckOverlayControl({ interleaved, ...deckProps }) {
114
123
  const [clearing, setClearing] = useState(false);
115
124
  const layers = deckProps.layers;
116
125
  const layerKey = Array.isArray(layers)
117
- ? layers
118
- .map((l) => {
119
- if (!l || typeof l !== 'object')
120
- return '?';
121
- const ctor = l.constructor;
122
- return ctor?.name ?? '?';
123
- })
124
- .join(',')
126
+ ? layers.map(getDeckLayerTypeName).join(',')
125
127
  : '';
126
128
  useEffect(() => {
127
129
  if (prevLayerKeyRef.current &&
@@ -142,9 +144,13 @@ function DeckOverlayControl({ interleaved, ...deckProps }) {
142
144
  }
143
145
  return null;
144
146
  }
147
+ function DeckMapRenderingErrorOverlay({ error }) {
148
+ return (_jsx("div", { className: "absolute inset-0 z-10 flex items-center justify-center p-4", children: _jsx("div", { className: "max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm", children: _jsxs(Collapsible, { children: [_jsxs("div", { className: "flex items-start gap-1", children: [_jsx("span", { children: "Map couldn't be rendered" }), _jsx(CollapsibleTrigger, { className: "group mt-0.5 shrink-0 rounded p-0.5 hover:bg-red-100", "aria-label": "Show error details", children: _jsx(ChevronRightIcon, { className: "h-3.5 w-3.5 transition-transform group-data-[state=open]:rotate-90" }) })] }), _jsx(CollapsibleContent, { children: _jsx("pre", { className: "mt-2 max-h-40 overflow-auto font-mono text-xs whitespace-pre-wrap", children: error.message }) })] }) }) }));
149
+ }
145
150
  export const DeckJsonMap = forwardRef(function DeckJsonMap({ spec, datasets, mapStyle, interleaved = true, deckProps, mapProps, showLegends = true, className, children, onDatasetStatesChange, onRenderingError, }, ref) {
146
151
  const normalizedDatasets = useMemo(() => normalizeDatasets(datasets), [datasets]);
147
- const datasetIds = useMemo(() => Object.keys(normalizedDatasets), [normalizedDatasets]);
152
+ const datasetIdKey = JSON.stringify(Object.keys(normalizedDatasets).sort());
153
+ const datasetIds = useMemo(() => JSON.parse(datasetIdKey), [datasetIdKey]);
148
154
  const datasetStates = usePreparedDatasetStates(normalizedDatasets);
149
155
  const onDatasetStatesChangeRef = useRef(onDatasetStatesChange);
150
156
  const { spec: parsedSpec, error: specError } = useMemo(() => parseSpec(spec), [spec]);
@@ -358,8 +364,8 @@ export const DeckJsonMap = forwardRef(function DeckJsonMap({ spec, datasets, map
358
364
  datasetIds,
359
365
  datasetStates,
360
366
  })
361
- : [], [availableSpec, datasetIds, datasetStates, showLegends]);
362
- return (_jsxs("div", { className: cn('relative h-full w-full', className), children: [hasRenderingError ? (_jsx("div", { className: "absolute inset-0 z-10 flex items-center justify-center p-4", children: _jsx("div", { className: "max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm", children: `Map couldn't be rendered. Check the console for details.` }) })) : null, _jsxs(Map, { ref: mapRef, ...mergedMapProps, ...(initialViewState
367
+ : [], [availableSpec, datasetIds, showLegends, datasetStates]);
368
+ return (_jsxs("div", { className: cn('relative h-full w-full', className), children: [finalDeckPropsResult.error ? (_jsx(DeckMapRenderingErrorOverlay, { error: finalDeckPropsResult.error })) : null, _jsxs(Map, { ref: mapRef, ...mergedMapProps, ...(initialViewState
363
369
  ? { initialViewState: initialViewState }
364
370
  : {}), onLoad: handleMapLoad, style: { width: '100%', height: '100%', ...mapProps?.style }, children: [_jsx(DeckOverlayControl, { interleaved: interleaved, ...overlayDeckProps }), children] }), renderDatasetErrorOverlay(datasetStates), !hasRenderingError && showLegends ? (_jsxs("div", { className: "pointer-events-none absolute bottom-2 left-2 z-10 max-w-56", children: [hasTripsLayer && tripsMaxTimeValue > 0 ? (_jsx("div", { className: "mb-1", children: _jsx(TripsTimeControl, { currentTime: tripsCurrentTime, maxTime: tripsMaxTimeValue, playing: tripsPlaying, onPlayPause: handleTripsPlayPause, onSeek: handleTripsSeek }) })) : null, _jsx(ColorScaleLegend, { legends: legends })] })) : hasTripsLayer && tripsMaxTimeValue > 0 ? (_jsx("div", { className: "pointer-events-none absolute bottom-2 left-2 z-10", children: _jsx(TripsTimeControl, { currentTime: tripsCurrentTime, maxTime: tripsMaxTimeValue, playing: tripsPlaying, onPlayPause: handleTripsPlayPause, onSeek: handleTripsSeek }) })) : null] }));
365
371
  });
@@ -1 +1 @@
1
- {"version":3,"file":"DeckJsonMap.js","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"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","sourcesContent":["import {JSONConverter} from '@deck.gl/json';\nimport {MapboxOverlay} from '@deck.gl/mapbox';\nimport {ColorScaleLegend} from '@sqlrooms/color-scales';\nimport {cn, ResolvedTheme, useTheme} from '@sqlrooms/ui';\nimport 'maplibre-gl/dist/maplibre-gl.css';\nimport {\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type FC,\n} from 'react';\nimport {forwardRef} from 'react';\nimport Map, {useControl} from 'react-map-gl/maplibre';\nimport {ZodError} from 'zod';\nimport {DeckJsonMapSpec} from './DeckJsonMapSpec';\nimport {\n resolveDeckMapStyle,\n useDeckMapDefaultStyles,\n} from './DeckMapDefaultStylesProvider';\nimport {normalizeDatasets} from './datasets/normalizeDatasets';\nimport {usePreparedDatasetStates} from './datasets/usePreparedDatasetStates';\nimport {createDeckJsonConfiguration} from './json/createDeckJsonConfiguration';\nimport {extractColorScaleLegends} from './json/extractColorScaleLegends';\nimport {getLayerCompatibility} from './json/layerCompatibility';\nimport {resolveDatasetId} from './json/layerConfig';\nimport {buildDeckMapJumpToOptions} from './mapFit';\nimport type {\n DeckJsonMapHandle,\n DeckJsonMapProps,\n PreparedDeckDatasetState,\n} from './types';\n\nconst DEFAULT_MAP_STYLES: Record<ResolvedTheme, string> = {\n light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',\n dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',\n};\n\nfunction parseSpec(spec: DeckJsonMapProps['spec']) {\n try {\n const parsedValue = typeof spec === 'string' ? JSON.parse(spec) : spec;\n const validatedSpec = DeckJsonMapSpec.safeParse(parsedValue);\n if (!validatedSpec.success) {\n return {\n spec: null,\n error: new Error(formatSpecValidationError(validatedSpec.error)),\n };\n }\n\n return {\n spec: validatedSpec.data,\n error: null,\n };\n } catch (error) {\n return {\n spec: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n}\n\nfunction formatSpecValidationError(error: ZodError) {\n const issues = error.issues.map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : 'spec';\n return `${path}: ${issue.message}`;\n });\n\n return `Invalid DeckJsonMap spec. ${issues.join('; ')}`;\n}\n\nfunction extractFallbackDeckProps(spec: Record<string, unknown> | null) {\n if (!spec) {\n return {};\n }\n\n const fallbackProps: Record<string, unknown> = {};\n for (const key of ['initialViewState', 'viewState', 'controller']) {\n if (key in spec) {\n fallbackProps[key] = spec[key];\n }\n }\n\n return fallbackProps;\n}\n\nfunction filterUnavailableLayers(\n spec: Record<string, unknown>,\n datasetIds: string[],\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const layers = Array.isArray(spec.layers) ? spec.layers : [];\n const filteredLayers = layers.filter((layer) => {\n if (!layer || typeof layer !== 'object') {\n return true;\n }\n\n const layerProps = layer as Record<string, unknown>;\n const layerName = String(layerProps['@@type'] ?? '');\n const compatibility = getLayerCompatibility(layerName);\n if (!compatibility) {\n return true;\n }\n\n const datasetId = resolveDatasetId(layerProps, datasetIds);\n if (!datasetId) {\n return true;\n }\n\n const datasetState = datasetStates[datasetId];\n if (!datasetState) {\n return false;\n }\n\n return datasetState.status !== 'error';\n });\n\n return {\n ...spec,\n layers: filteredLayers,\n };\n}\n\nfunction renderDatasetErrorOverlay(\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const failedDatasets = Object.entries(datasetStates).filter(\n (\n entry,\n ): entry is [\n string,\n Extract<PreparedDeckDatasetState, {status: 'error'}>,\n ] => entry[1].status === 'error',\n );\n\n if (!failedDatasets.length) {\n return null;\n }\n\n return (\n <div className=\"pointer-events-none absolute inset-x-4 top-4 z-10 space-y-2\">\n {failedDatasets.map(([datasetId, state]) => (\n <div\n key={datasetId}\n className=\"rounded-md border border-red-200 bg-red-50/95 px-3 py-2 text-sm text-red-700 shadow-sm\"\n >\n {`Dataset \"${datasetId}\" failed: ${state.error.message}`}\n </div>\n ))}\n </div>\n );\n}\n\nconst TripsTimeControl: FC<{\n currentTime: number;\n maxTime: number;\n playing: boolean;\n onPlayPause: () => void;\n onSeek: (time: number) => void;\n}> = ({currentTime, maxTime, playing, onPlayPause, onSeek}) => {\n const [collapsed, setCollapsed] = useState(false);\n const progress = maxTime > 0 ? currentTime / maxTime : 0;\n\n if (collapsed) {\n return (\n <button\n type=\"button\"\n onClick={() => setCollapsed(false)}\n className=\"border-border/70 bg-background/90 text-muted-foreground hover:text-foreground pointer-events-auto flex w-fit items-center gap-1 rounded-md border px-2 py-1 text-[10px] leading-none font-medium shadow-sm backdrop-blur-sm transition-colors\"\n >\n Timeline\n </button>\n );\n }\n\n return (\n <div className=\"bg-background/90 border-border/70 pointer-events-auto relative flex items-center gap-1.5 rounded-md border px-2 py-1.5 pr-7 shadow-sm backdrop-blur-sm\">\n <button\n type=\"button\"\n onClick={onPlayPause}\n className=\"text-foreground hover:bg-accent flex h-5 w-5 shrink-0 items-center justify-center rounded\"\n title={playing ? 'Pause' : 'Play'}\n >\n {playing ? (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\">\n <rect x=\"1\" y=\"1\" width=\"3\" height=\"8\" />\n <rect x=\"6\" y=\"1\" width=\"3\" height=\"8\" />\n </svg>\n ) : (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\">\n <polygon points=\"2,1 9,5 2,9\" />\n </svg>\n )}\n </button>\n <input\n type=\"range\"\n min={0}\n max={1000}\n value={Math.round(progress * 1000)}\n onChange={(e) => onSeek((Number(e.target.value) / 1000) * maxTime)}\n className=\"h-1 w-24 flex-1 cursor-pointer\"\n />\n <button\n type=\"button\"\n onClick={() => setCollapsed(true)}\n className=\"text-muted-foreground hover:text-foreground absolute top-1.5 right-1.5 flex h-4 w-4 items-center justify-center rounded-sm transition-colors\"\n title=\"Collapse\"\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\">\n <path\n d=\"M1 1L7 7M7 1L1 7\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n );\n};\n\n// Workaround for deck.gl HeatmapLayer not releasing its WebGL framebuffer\n// when replaced by another layer type (e.g. switching heatmap → scatterplot).\n// We detect layer class changes and clear layers for one animation frame,\n// giving deck.gl a chance to finalize the old layer's resources before\n// initializing the new one.\nfunction DeckOverlayControl({\n interleaved,\n ...deckProps\n}: {interleaved: boolean} & Record<string, unknown>) {\n const overlay = useControl<MapboxOverlay>(\n () => new MapboxOverlay({interleaved}),\n );\n const prevLayerKeyRef = useRef<string>('');\n const [clearing, setClearing] = useState(false);\n\n const layers = deckProps.layers as unknown[] | undefined;\n const layerKey = Array.isArray(layers)\n ? layers\n .map((l) => {\n if (!l || typeof l !== 'object') return '?';\n const ctor = (l as {constructor?: {name?: string}}).constructor;\n return ctor?.name ?? '?';\n })\n .join(',')\n : '';\n\n useEffect(() => {\n if (\n prevLayerKeyRef.current &&\n prevLayerKeyRef.current !== layerKey &&\n !clearing\n ) {\n setClearing(true);\n }\n prevLayerKeyRef.current = layerKey;\n }, [layerKey, clearing]);\n\n useEffect(() => {\n if (clearing && overlay) {\n overlay.setProps({layers: []});\n requestAnimationFrame(() => setClearing(false));\n }\n }, [clearing, overlay]);\n\n if (!clearing && overlay) {\n overlay.setProps(deckProps);\n }\n\n return null;\n}\n\nexport const DeckJsonMap = forwardRef<DeckJsonMapHandle, DeckJsonMapProps>(\n function DeckJsonMap(\n {\n spec,\n datasets,\n mapStyle,\n interleaved = true,\n deckProps,\n mapProps,\n showLegends = true,\n className,\n children,\n onDatasetStatesChange,\n onRenderingError,\n },\n ref,\n ) {\n const normalizedDatasets = useMemo(\n () => normalizeDatasets(datasets),\n [datasets],\n );\n const datasetIds = useMemo(\n () => Object.keys(normalizedDatasets),\n [normalizedDatasets],\n );\n const datasetStates = usePreparedDatasetStates(normalizedDatasets);\n const onDatasetStatesChangeRef = useRef(onDatasetStatesChange);\n\n const {spec: parsedSpec, error: specError} = useMemo(\n () => parseSpec(spec),\n [spec],\n );\n\n const availableSpec = useMemo(\n () =>\n parsedSpec\n ? filterUnavailableLayers(parsedSpec, datasetIds, datasetStates)\n : null,\n [parsedSpec, datasetIds, datasetStates],\n );\n\n const converter = useMemo(\n () =>\n new JSONConverter({\n configuration: createDeckJsonConfiguration({\n datasetStates,\n datasetIds,\n }),\n onJSONChange: () => {},\n }),\n [datasetIds, datasetStates],\n );\n\n const convertedDeckPropsResult = useMemo(() => {\n if (!availableSpec) {\n return {props: null, error: specError};\n }\n\n try {\n return {\n props: converter.convert(availableSpec) as Record<string, unknown>,\n error: null,\n };\n } catch (error) {\n return {\n props: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }, [availableSpec, converter, specError]);\n\n // Animation for TripsLayer — update currentTime on each frame.\n // Only activate when the trips dataset is ready to avoid spinning the RAF\n // loop while data is still loading.\n const hasTripsLayer = useMemo(() => {\n if (!availableSpec || !Array.isArray(availableSpec.layers)) return false;\n return availableSpec.layers.some((l: unknown) => {\n if (\n !l ||\n typeof l !== 'object' ||\n (l as {'@@type'?: string})['@@type'] !== 'GeoArrowTripsLayer'\n )\n return false;\n const dsId = resolveDatasetId(l as Record<string, unknown>, datasetIds);\n if (!dsId) return true;\n const state = datasetStates[dsId];\n return state?.status === 'ready';\n });\n }, [availableSpec, datasetIds, datasetStates]);\n\n const [tripsTime, setTripsTime] = useState(0);\n const [tripsPlaying, setTripsPlaying] = useState(true);\n const tripsTimeRef = useRef(0);\n\n useEffect(() => {\n if (!hasTripsLayer || !tripsPlaying) return;\n let raf: number;\n let lastFrame = Date.now();\n const tick = () => {\n const now = Date.now();\n tripsTimeRef.current += now - lastFrame;\n lastFrame = now;\n setTripsTime(tripsTimeRef.current);\n raf = requestAnimationFrame(tick);\n };\n lastFrame = Date.now();\n raf = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(raf);\n }, [hasTripsLayer, tripsPlaying]);\n\n const handleTripsPlayPause = useCallback(() => {\n setTripsPlaying((p) => !p);\n }, []);\n\n const handleTripsSeek = useCallback((time: number) => {\n const rawTime = time * 30;\n tripsTimeRef.current = rawTime;\n setTripsTime(rawTime);\n }, []);\n\n const finalDeckPropsResult = convertedDeckPropsResult;\n\n const onRenderingErrorRef = useRef(onRenderingError);\n useEffect(() => {\n onRenderingErrorRef.current = onRenderingError;\n }, [onRenderingError]);\n\n useEffect(() => {\n if (finalDeckPropsResult.error) {\n console.error(finalDeckPropsResult.error);\n onRenderingErrorRef.current?.(finalDeckPropsResult.error);\n }\n }, [finalDeckPropsResult.error]);\n\n useEffect(() => {\n onDatasetStatesChangeRef.current = onDatasetStatesChange;\n }, [onDatasetStatesChange]);\n\n useEffect(() => {\n onDatasetStatesChangeRef.current?.(datasetStates);\n }, [datasetStates]);\n\n const fallbackDeckProps = useMemo(\n () => extractFallbackDeckProps(availableSpec),\n [availableSpec],\n );\n const convertedDeckProps = (finalDeckPropsResult.props ??\n fallbackDeckProps ??\n {}) as Record<string, unknown>;\n const extraDeckProps = (deckProps ?? {}) as Record<string, unknown>;\n const extraMapProps = (mapProps ?? {}) as Record<string, unknown>;\n const hasRenderingError = Boolean(finalDeckPropsResult.error);\n\n // Separate stable layer analysis from per-frame animation to avoid\n // re-running .map() over all layers 60 times per second.\n const baseLayers = useMemo(() => {\n const mergedLayers = hasRenderingError\n ? []\n : (deckProps?.layers ??\n (convertedDeckProps.layers as unknown[] | undefined) ??\n []);\n if (!hasTripsLayer || !Array.isArray(mergedLayers))\n return {layers: mergedLayers, maxTs: 0, tripsIndices: [] as number[]};\n let computedMaxTs = 0;\n const tripsIndices: number[] = [];\n for (let i = 0; i < mergedLayers.length; i++) {\n const layer = mergedLayers[i];\n if (!layer || typeof layer !== 'object') continue;\n const layerObj = layer as {props?: Record<string, unknown>};\n const maxTs = (layerObj.props as Record<string, unknown> | undefined)\n ?._tripsMaxTimestamp as number | undefined;\n if (maxTs && maxTs > 0) {\n computedMaxTs = Math.max(computedMaxTs, maxTs);\n tripsIndices.push(i);\n }\n }\n return {layers: mergedLayers, maxTs: computedMaxTs, tripsIndices};\n }, [\n hasTripsLayer,\n hasRenderingError,\n deckProps?.layers,\n convertedDeckProps.layers,\n ]);\n\n // Per-frame: only clone trips layers with updated currentTime\n const animatedLayers = useMemo(() => {\n const {layers, tripsIndices} = baseLayers;\n if (!tripsIndices.length) return layers;\n if (!Array.isArray(layers)) return layers;\n const result = layers.slice();\n for (const idx of tripsIndices) {\n const layer = result[idx];\n if (!layer || typeof layer !== 'object') continue;\n const layerObj = layer as {\n props?: Record<string, unknown>;\n clone?: (props: Record<string, unknown>) => unknown;\n };\n if (!layerObj.clone) continue;\n const props = layerObj.props as Record<string, unknown> | undefined;\n const maxTs = (props?._tripsMaxTimestamp as number | undefined) ?? 0;\n const trailFraction =\n (props?._trailLengthFactor as number | undefined) ?? 0.4;\n const widthPx = (props?.widthMinPixels as number | undefined) ?? 3;\n const animationSpeed = 30;\n const currentTime = (tripsTime / animationSpeed) % maxTs;\n result[idx] = layerObj.clone({\n currentTime,\n trailLength: maxTs * trailFraction,\n widthMinPixels: widthPx,\n });\n }\n return result;\n }, [baseLayers, tripsTime]);\n const tripsMaxTimeValue = baseLayers.maxTs;\n\n const tripsCurrentTime = useMemo(() => {\n if (!tripsMaxTimeValue || tripsMaxTimeValue <= 0) return 0;\n return (tripsTime / 30) % tripsMaxTimeValue;\n }, [tripsTime, tripsMaxTimeValue]);\n\n const mergedDeckProps = {\n ...convertedDeckProps,\n ...extraDeckProps,\n layers: animatedLayers,\n };\n\n // overlayDeckProps should not contain viewState/initialViewState\n const {\n initialViewState,\n viewState: _vs,\n onViewStateChange: _onViewStateChange,\n ...overlayDeckProps\n } = mergedDeckProps as Record<string, unknown>;\n void _vs;\n void _onViewStateChange;\n\n const mapRef = useRef<{jumpTo: (opts: object) => void} | null>(null);\n const pendingJumpRef = useRef<object | null>(null);\n\n useImperativeHandle(\n ref,\n () => ({\n jumpTo(opts) {\n const jumpOpts = buildDeckMapJumpToOptions(opts);\n if (mapRef.current) {\n mapRef.current.jumpTo(jumpOpts);\n } else {\n pendingJumpRef.current = jumpOpts;\n }\n },\n }),\n [],\n );\n\n const handleMapLoad = useCallback(\n (event?: unknown) => {\n if (pendingJumpRef.current && mapRef.current) {\n mapRef.current.jumpTo(pendingJumpRef.current);\n pendingJumpRef.current = null;\n }\n const externalOnLoad = (\n extraMapProps as {onLoad?: (e?: unknown) => void}\n ).onLoad;\n externalOnLoad?.(event);\n },\n [extraMapProps],\n );\n\n const {resolvedTheme} = useTheme();\n const hostDefaultMapStyles = useDeckMapDefaultStyles();\n\n const mergedMapProps = {\n ...extraMapProps,\n mapStyle: resolveDeckMapStyle({\n mapStyle,\n mapPropsMapStyle: mapProps?.mapStyle,\n hostDefaultStyles: hostDefaultMapStyles,\n resolvedTheme,\n fallbackStyles: DEFAULT_MAP_STYLES,\n }),\n };\n const legends = useMemo(\n () =>\n showLegends\n ? extractColorScaleLegends({\n spec: availableSpec,\n datasetIds,\n datasetStates,\n })\n : [],\n [availableSpec, datasetIds, datasetStates, showLegends],\n );\n\n return (\n <div className={cn('relative h-full w-full', className)}>\n {hasRenderingError ? (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center p-4\">\n <div className=\"max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm\">\n {`Map couldn't be rendered. Check the console for details.`}\n </div>\n </div>\n ) : null}\n\n <Map\n ref={mapRef as any}\n {...(mergedMapProps as object)}\n {...(initialViewState\n ? {initialViewState: initialViewState as object}\n : {})}\n onLoad={handleMapLoad}\n style={{width: '100%', height: '100%', ...mapProps?.style}}\n >\n <DeckOverlayControl interleaved={interleaved} {...overlayDeckProps} />\n {children}\n </Map>\n\n {renderDatasetErrorOverlay(datasetStates)}\n {!hasRenderingError && showLegends ? (\n <div className=\"pointer-events-none absolute bottom-2 left-2 z-10 max-w-56\">\n {hasTripsLayer && tripsMaxTimeValue > 0 ? (\n <div className=\"mb-1\">\n <TripsTimeControl\n currentTime={tripsCurrentTime}\n maxTime={tripsMaxTimeValue}\n playing={tripsPlaying}\n onPlayPause={handleTripsPlayPause}\n onSeek={handleTripsSeek}\n />\n </div>\n ) : null}\n <ColorScaleLegend legends={legends} />\n </div>\n ) : hasTripsLayer && tripsMaxTimeValue > 0 ? (\n <div className=\"pointer-events-none absolute bottom-2 left-2 z-10\">\n <TripsTimeControl\n currentTime={tripsCurrentTime}\n maxTime={tripsMaxTimeValue}\n playing={tripsPlaying}\n onPlayPause={handleTripsPlayPause}\n onSeek={handleTripsSeek}\n />\n </div>\n ) : null}\n </div>\n );\n },\n);\n"]}
1
+ {"version":3,"file":"DeckJsonMap.js","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"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","sourcesContent":["import {JSONConverter} from '@deck.gl/json';\nimport {MapboxOverlay} from '@deck.gl/mapbox';\nimport {ColorScaleLegend} from '@sqlrooms/color-scales';\nimport {\n cn,\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n ResolvedTheme,\n useTheme,\n} from '@sqlrooms/ui';\nimport {ChevronRightIcon} from 'lucide-react';\nimport 'maplibre-gl/dist/maplibre-gl.css';\nimport {\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type FC,\n} from 'react';\nimport {forwardRef} from 'react';\nimport Map, {useControl} from 'react-map-gl/maplibre';\nimport {ZodError} from 'zod';\nimport {DeckJsonMapSpec} from './DeckJsonMapSpec';\nimport {\n resolveDeckMapStyle,\n useDeckMapDefaultStyles,\n} from './DeckMapDefaultStylesProvider';\nimport {normalizeDatasets} from './datasets/normalizeDatasets';\nimport {usePreparedDatasetStates} from './datasets/usePreparedDatasetStates';\nimport {createDeckJsonConfiguration} from './json/createDeckJsonConfiguration';\nimport {extractColorScaleLegends} from './json/extractColorScaleLegends';\nimport {getLayerCompatibility} from './json/layerCompatibility';\nimport {resolveDatasetId} from './json/layerConfig';\nimport {buildDeckMapJumpToOptions} from './mapFit';\nimport type {\n DeckJsonMapHandle,\n DeckJsonMapProps,\n PreparedDeckDatasetState,\n} from './types';\n\nconst DEFAULT_MAP_STYLES: Record<ResolvedTheme, string> = {\n light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',\n dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',\n};\n\nfunction parseSpec(spec: DeckJsonMapProps['spec']) {\n try {\n const parsedValue = typeof spec === 'string' ? JSON.parse(spec) : spec;\n const validatedSpec = DeckJsonMapSpec.safeParse(parsedValue);\n if (!validatedSpec.success) {\n return {\n spec: null,\n error: new Error(formatSpecValidationError(validatedSpec.error)),\n };\n }\n\n return {\n spec: validatedSpec.data,\n error: null,\n };\n } catch (error) {\n return {\n spec: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n}\n\nfunction formatSpecValidationError(error: ZodError) {\n const issues = error.issues.map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : 'spec';\n return `${path}: ${issue.message}`;\n });\n\n return `Invalid DeckJsonMap spec. ${issues.join('; ')}`;\n}\n\nfunction extractFallbackDeckProps(spec: Record<string, unknown> | null) {\n if (!spec) {\n return {};\n }\n\n const fallbackProps: Record<string, unknown> = {};\n for (const key of ['initialViewState', 'viewState', 'controller']) {\n if (key in spec) {\n fallbackProps[key] = spec[key];\n }\n }\n\n return fallbackProps;\n}\n\nfunction filterUnavailableLayers(\n spec: Record<string, unknown>,\n datasetIds: string[],\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const layers = Array.isArray(spec.layers) ? spec.layers : [];\n const filteredLayers = layers.filter((layer) => {\n if (!layer || typeof layer !== 'object') {\n return true;\n }\n\n const layerProps = layer as Record<string, unknown>;\n const layerName = String(layerProps['@@type'] ?? '');\n const compatibility = getLayerCompatibility(layerName);\n if (!compatibility) {\n return true;\n }\n\n const datasetId = resolveDatasetId(layerProps, datasetIds);\n if (!datasetId) {\n return true;\n }\n\n const datasetState = datasetStates[datasetId];\n if (!datasetState) {\n return false;\n }\n\n return datasetState.status !== 'error';\n });\n\n return {\n ...spec,\n layers: filteredLayers,\n };\n}\n\nfunction renderDatasetErrorOverlay(\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const failedDatasets = Object.entries(datasetStates).filter(\n (\n entry,\n ): entry is [\n string,\n Extract<PreparedDeckDatasetState, {status: 'error'}>,\n ] => entry[1].status === 'error',\n );\n\n if (!failedDatasets.length) {\n return null;\n }\n\n return (\n <div className=\"pointer-events-none absolute inset-x-4 top-4 z-10 space-y-2\">\n {failedDatasets.map(([datasetId, state]) => (\n <div\n key={datasetId}\n className=\"rounded-md border border-red-200 bg-red-50/95 px-3 py-2 text-sm text-red-700 shadow-sm\"\n >\n {`Dataset \"${datasetId}\" failed: ${state.error.message}`}\n </div>\n ))}\n </div>\n );\n}\n\nconst TripsTimeControl: FC<{\n currentTime: number;\n maxTime: number;\n playing: boolean;\n onPlayPause: () => void;\n onSeek: (time: number) => void;\n}> = ({currentTime, maxTime, playing, onPlayPause, onSeek}) => {\n const [collapsed, setCollapsed] = useState(false);\n const progress = maxTime > 0 ? currentTime / maxTime : 0;\n\n if (collapsed) {\n return (\n <button\n type=\"button\"\n onClick={() => setCollapsed(false)}\n className=\"border-border/70 bg-background/90 text-muted-foreground hover:text-foreground pointer-events-auto flex w-fit items-center gap-1 rounded-md border px-2 py-1 text-[10px] leading-none font-medium shadow-sm backdrop-blur-sm transition-colors\"\n >\n Timeline\n </button>\n );\n }\n\n return (\n <div className=\"bg-background/90 border-border/70 pointer-events-auto relative flex items-center gap-1.5 rounded-md border px-2 py-1.5 pr-7 shadow-sm backdrop-blur-sm\">\n <button\n type=\"button\"\n onClick={onPlayPause}\n className=\"text-foreground hover:bg-accent flex h-5 w-5 shrink-0 items-center justify-center rounded\"\n title={playing ? 'Pause' : 'Play'}\n >\n {playing ? (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\">\n <rect x=\"1\" y=\"1\" width=\"3\" height=\"8\" />\n <rect x=\"6\" y=\"1\" width=\"3\" height=\"8\" />\n </svg>\n ) : (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\">\n <polygon points=\"2,1 9,5 2,9\" />\n </svg>\n )}\n </button>\n <input\n type=\"range\"\n min={0}\n max={1000}\n value={Math.round(progress * 1000)}\n onChange={(e) => onSeek((Number(e.target.value) / 1000) * maxTime)}\n className=\"h-1 w-24 flex-1 cursor-pointer\"\n />\n <button\n type=\"button\"\n onClick={() => setCollapsed(true)}\n className=\"text-muted-foreground hover:text-foreground absolute top-1.5 right-1.5 flex h-4 w-4 items-center justify-center rounded-sm transition-colors\"\n title=\"Collapse\"\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\">\n <path\n d=\"M1 1L7 7M7 1L1 7\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n );\n};\n\nfunction getDeckLayerTypeName(layer: unknown): string {\n if (!layer || typeof layer !== 'object') return '?';\n const ctor = (\n layer as {\n constructor?: {layerName?: string; name?: string};\n }\n ).constructor;\n // Prefer static layerName: table-to-RecordBatch adapters all share\n // constructor.name \"Adapter\", which would miss heatmap ↔ scatterplot swaps.\n return ctor?.layerName ?? ctor?.name ?? '?';\n}\n\n// Workaround for deck.gl HeatmapLayer not releasing its WebGL framebuffer\n// when replaced by another layer type (e.g. switching heatmap → scatterplot).\n// We detect layer class changes and clear layers for one animation frame,\n// giving deck.gl a chance to finalize the old layer's resources before\n// initializing the new one.\nfunction DeckOverlayControl({\n interleaved,\n ...deckProps\n}: {interleaved: boolean} & Record<string, unknown>) {\n const overlay = useControl<MapboxOverlay>(\n () => new MapboxOverlay({interleaved}),\n );\n const prevLayerKeyRef = useRef<string>('');\n const [clearing, setClearing] = useState(false);\n\n const layers = deckProps.layers as unknown[] | undefined;\n const layerKey = Array.isArray(layers)\n ? layers.map(getDeckLayerTypeName).join(',')\n : '';\n\n useEffect(() => {\n if (\n prevLayerKeyRef.current &&\n prevLayerKeyRef.current !== layerKey &&\n !clearing\n ) {\n setClearing(true);\n }\n prevLayerKeyRef.current = layerKey;\n }, [layerKey, clearing]);\n\n useEffect(() => {\n if (clearing && overlay) {\n overlay.setProps({layers: []});\n requestAnimationFrame(() => setClearing(false));\n }\n }, [clearing, overlay]);\n\n if (!clearing && overlay) {\n overlay.setProps(deckProps);\n }\n\n return null;\n}\n\nfunction DeckMapRenderingErrorOverlay({error}: {error: Error}) {\n return (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center p-4\">\n <div className=\"max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm\">\n <Collapsible>\n <div className=\"flex items-start gap-1\">\n <span>{\"Map couldn't be rendered\"}</span>\n <CollapsibleTrigger\n className=\"group mt-0.5 shrink-0 rounded p-0.5 hover:bg-red-100\"\n aria-label=\"Show error details\"\n >\n <ChevronRightIcon className=\"h-3.5 w-3.5 transition-transform group-data-[state=open]:rotate-90\" />\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n <pre className=\"mt-2 max-h-40 overflow-auto font-mono text-xs whitespace-pre-wrap\">\n {error.message}\n </pre>\n </CollapsibleContent>\n </Collapsible>\n </div>\n </div>\n );\n}\n\nexport const DeckJsonMap = forwardRef<DeckJsonMapHandle, DeckJsonMapProps>(\n function DeckJsonMap(\n {\n spec,\n datasets,\n mapStyle,\n interleaved = true,\n deckProps,\n mapProps,\n showLegends = true,\n className,\n children,\n onDatasetStatesChange,\n onRenderingError,\n },\n ref,\n ) {\n const normalizedDatasets = useMemo(\n () => normalizeDatasets(datasets),\n [datasets],\n );\n const datasetIdKey = JSON.stringify(Object.keys(normalizedDatasets).sort());\n const datasetIds = useMemo(\n () => JSON.parse(datasetIdKey) as string[],\n [datasetIdKey],\n );\n const datasetStates = usePreparedDatasetStates(normalizedDatasets);\n const onDatasetStatesChangeRef = useRef(onDatasetStatesChange);\n\n const {spec: parsedSpec, error: specError} = useMemo(\n () => parseSpec(spec),\n [spec],\n );\n\n const availableSpec = useMemo(\n () =>\n parsedSpec\n ? filterUnavailableLayers(parsedSpec, datasetIds, datasetStates)\n : null,\n [parsedSpec, datasetIds, datasetStates],\n );\n\n const converter = useMemo(\n () =>\n new JSONConverter({\n configuration: createDeckJsonConfiguration({\n datasetStates,\n datasetIds,\n }),\n onJSONChange: () => {},\n }),\n [datasetIds, datasetStates],\n );\n\n const convertedDeckPropsResult = useMemo(() => {\n if (!availableSpec) {\n return {props: null, error: specError};\n }\n\n try {\n return {\n props: converter.convert(availableSpec) as Record<string, unknown>,\n error: null,\n };\n } catch (error) {\n return {\n props: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }, [availableSpec, converter, specError]);\n\n // Animation for TripsLayer — update currentTime on each frame.\n // Only activate when the trips dataset is ready to avoid spinning the RAF\n // loop while data is still loading.\n const hasTripsLayer = useMemo(() => {\n if (!availableSpec || !Array.isArray(availableSpec.layers)) return false;\n return availableSpec.layers.some((l: unknown) => {\n if (\n !l ||\n typeof l !== 'object' ||\n (l as {'@@type'?: string})['@@type'] !== 'GeoArrowTripsLayer'\n )\n return false;\n const dsId = resolveDatasetId(l as Record<string, unknown>, datasetIds);\n if (!dsId) return true;\n const state = datasetStates[dsId];\n return state?.status === 'ready';\n });\n }, [availableSpec, datasetIds, datasetStates]);\n\n const [tripsTime, setTripsTime] = useState(0);\n const [tripsPlaying, setTripsPlaying] = useState(true);\n const tripsTimeRef = useRef(0);\n\n useEffect(() => {\n if (!hasTripsLayer || !tripsPlaying) return;\n let raf: number;\n let lastFrame = Date.now();\n const tick = () => {\n const now = Date.now();\n tripsTimeRef.current += now - lastFrame;\n lastFrame = now;\n setTripsTime(tripsTimeRef.current);\n raf = requestAnimationFrame(tick);\n };\n lastFrame = Date.now();\n raf = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(raf);\n }, [hasTripsLayer, tripsPlaying]);\n\n const handleTripsPlayPause = useCallback(() => {\n setTripsPlaying((p) => !p);\n }, []);\n\n const handleTripsSeek = useCallback((time: number) => {\n const rawTime = time * 30;\n tripsTimeRef.current = rawTime;\n setTripsTime(rawTime);\n }, []);\n\n const finalDeckPropsResult = convertedDeckPropsResult;\n\n const onRenderingErrorRef = useRef(onRenderingError);\n useEffect(() => {\n onRenderingErrorRef.current = onRenderingError;\n }, [onRenderingError]);\n\n useEffect(() => {\n if (finalDeckPropsResult.error) {\n console.error(finalDeckPropsResult.error);\n onRenderingErrorRef.current?.(finalDeckPropsResult.error);\n }\n }, [finalDeckPropsResult.error]);\n\n useEffect(() => {\n onDatasetStatesChangeRef.current = onDatasetStatesChange;\n }, [onDatasetStatesChange]);\n\n useEffect(() => {\n onDatasetStatesChangeRef.current?.(datasetStates);\n }, [datasetStates]);\n\n const fallbackDeckProps = useMemo(\n () => extractFallbackDeckProps(availableSpec),\n [availableSpec],\n );\n const convertedDeckProps = (finalDeckPropsResult.props ??\n fallbackDeckProps ??\n {}) as Record<string, unknown>;\n const extraDeckProps = (deckProps ?? {}) as Record<string, unknown>;\n const extraMapProps = (mapProps ?? {}) as Record<string, unknown>;\n const hasRenderingError = Boolean(finalDeckPropsResult.error);\n\n // Separate stable layer analysis from per-frame animation to avoid\n // re-running .map() over all layers 60 times per second.\n const baseLayers = useMemo(() => {\n const mergedLayers = hasRenderingError\n ? []\n : (deckProps?.layers ??\n (convertedDeckProps.layers as unknown[] | undefined) ??\n []);\n if (!hasTripsLayer || !Array.isArray(mergedLayers))\n return {layers: mergedLayers, maxTs: 0, tripsIndices: [] as number[]};\n let computedMaxTs = 0;\n const tripsIndices: number[] = [];\n for (let i = 0; i < mergedLayers.length; i++) {\n const layer = mergedLayers[i];\n if (!layer || typeof layer !== 'object') continue;\n const layerObj = layer as {props?: Record<string, unknown>};\n const maxTs = (layerObj.props as Record<string, unknown> | undefined)\n ?._tripsMaxTimestamp as number | undefined;\n if (maxTs && maxTs > 0) {\n computedMaxTs = Math.max(computedMaxTs, maxTs);\n tripsIndices.push(i);\n }\n }\n return {layers: mergedLayers, maxTs: computedMaxTs, tripsIndices};\n }, [\n hasTripsLayer,\n hasRenderingError,\n deckProps?.layers,\n convertedDeckProps.layers,\n ]);\n\n // Per-frame: only clone trips layers with updated currentTime\n const animatedLayers = useMemo(() => {\n const {layers, tripsIndices} = baseLayers;\n if (!tripsIndices.length) return layers;\n if (!Array.isArray(layers)) return layers;\n const result = layers.slice();\n for (const idx of tripsIndices) {\n const layer = result[idx];\n if (!layer || typeof layer !== 'object') continue;\n const layerObj = layer as {\n props?: Record<string, unknown>;\n clone?: (props: Record<string, unknown>) => unknown;\n };\n if (!layerObj.clone) continue;\n const props = layerObj.props as Record<string, unknown> | undefined;\n const maxTs = (props?._tripsMaxTimestamp as number | undefined) ?? 0;\n const trailFraction =\n (props?._trailLengthFactor as number | undefined) ?? 0.4;\n const widthPx = (props?.widthMinPixels as number | undefined) ?? 3;\n const animationSpeed = 30;\n const currentTime = (tripsTime / animationSpeed) % maxTs;\n result[idx] = layerObj.clone({\n currentTime,\n trailLength: maxTs * trailFraction,\n widthMinPixels: widthPx,\n });\n }\n return result;\n }, [baseLayers, tripsTime]);\n const tripsMaxTimeValue = baseLayers.maxTs;\n\n const tripsCurrentTime = useMemo(() => {\n if (!tripsMaxTimeValue || tripsMaxTimeValue <= 0) return 0;\n return (tripsTime / 30) % tripsMaxTimeValue;\n }, [tripsTime, tripsMaxTimeValue]);\n\n const mergedDeckProps = {\n ...convertedDeckProps,\n ...extraDeckProps,\n layers: animatedLayers,\n };\n\n // overlayDeckProps should not contain viewState/initialViewState\n const {\n initialViewState,\n viewState: _vs,\n onViewStateChange: _onViewStateChange,\n ...overlayDeckProps\n } = mergedDeckProps as Record<string, unknown>;\n void _vs;\n void _onViewStateChange;\n\n const mapRef = useRef<{jumpTo: (opts: object) => void} | null>(null);\n const pendingJumpRef = useRef<object | null>(null);\n\n useImperativeHandle(\n ref,\n () => ({\n jumpTo(opts) {\n const jumpOpts = buildDeckMapJumpToOptions(opts);\n if (mapRef.current) {\n mapRef.current.jumpTo(jumpOpts);\n } else {\n pendingJumpRef.current = jumpOpts;\n }\n },\n }),\n [],\n );\n\n const handleMapLoad = useCallback(\n (event?: unknown) => {\n if (pendingJumpRef.current && mapRef.current) {\n mapRef.current.jumpTo(pendingJumpRef.current);\n pendingJumpRef.current = null;\n }\n const externalOnLoad = (\n extraMapProps as {onLoad?: (e?: unknown) => void}\n ).onLoad;\n externalOnLoad?.(event);\n },\n [extraMapProps],\n );\n\n const {resolvedTheme} = useTheme();\n const hostDefaultMapStyles = useDeckMapDefaultStyles();\n\n const mergedMapProps = {\n ...extraMapProps,\n mapStyle: resolveDeckMapStyle({\n mapStyle,\n mapPropsMapStyle: mapProps?.mapStyle,\n hostDefaultStyles: hostDefaultMapStyles,\n resolvedTheme,\n fallbackStyles: DEFAULT_MAP_STYLES,\n }),\n };\n const legends = useMemo(\n () =>\n showLegends\n ? extractColorScaleLegends({\n spec: availableSpec,\n datasetIds,\n datasetStates,\n })\n : [],\n [availableSpec, datasetIds, showLegends, datasetStates],\n );\n\n return (\n <div className={cn('relative h-full w-full', className)}>\n {finalDeckPropsResult.error ? (\n <DeckMapRenderingErrorOverlay error={finalDeckPropsResult.error} />\n ) : null}\n\n <Map\n ref={mapRef as any}\n {...(mergedMapProps as object)}\n {...(initialViewState\n ? {initialViewState: initialViewState as object}\n : {})}\n onLoad={handleMapLoad}\n style={{width: '100%', height: '100%', ...mapProps?.style}}\n >\n <DeckOverlayControl interleaved={interleaved} {...overlayDeckProps} />\n {children}\n </Map>\n\n {renderDatasetErrorOverlay(datasetStates)}\n {!hasRenderingError && showLegends ? (\n <div className=\"pointer-events-none absolute bottom-2 left-2 z-10 max-w-56\">\n {hasTripsLayer && tripsMaxTimeValue > 0 ? (\n <div className=\"mb-1\">\n <TripsTimeControl\n currentTime={tripsCurrentTime}\n maxTime={tripsMaxTimeValue}\n playing={tripsPlaying}\n onPlayPause={handleTripsPlayPause}\n onSeek={handleTripsSeek}\n />\n </div>\n ) : null}\n <ColorScaleLegend legends={legends} />\n </div>\n ) : hasTripsLayer && tripsMaxTimeValue > 0 ? (\n <div className=\"pointer-events-none absolute bottom-2 left-2 z-10\">\n <TripsTimeControl\n currentTime={tripsCurrentTime}\n maxTime={tripsMaxTimeValue}\n playing={tripsPlaying}\n onPlayPause={handleTripsPlayPause}\n onSeek={handleTripsSeek}\n />\n </div>\n ) : null}\n </div>\n );\n },\n);\n"]}