@sqlrooms/deck 0.29.0-rc.4 → 0.29.0-rc.6

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 (75) hide show
  1. package/README.md +24 -2
  2. package/dist/DeckJsonMap.d.ts +1 -1
  3. package/dist/DeckJsonMap.d.ts.map +1 -1
  4. package/dist/DeckJsonMap.js +16 -11
  5. package/dist/DeckJsonMap.js.map +1 -1
  6. package/dist/LatitudeSelector.d.ts +11 -0
  7. package/dist/LatitudeSelector.d.ts.map +1 -0
  8. package/dist/LatitudeSelector.js +25 -0
  9. package/dist/LatitudeSelector.js.map +1 -0
  10. package/dist/LongitudeSelector.d.ts +11 -0
  11. package/dist/LongitudeSelector.d.ts.map +1 -0
  12. package/dist/LongitudeSelector.js +27 -0
  13. package/dist/LongitudeSelector.js.map +1 -0
  14. package/dist/MapSettings.d.ts +10 -0
  15. package/dist/MapSettings.d.ts.map +1 -0
  16. package/dist/MapSettings.js +96 -0
  17. package/dist/MapSettings.js.map +1 -0
  18. package/dist/ai.d.ts +168 -0
  19. package/dist/ai.d.ts.map +1 -0
  20. package/dist/ai.js +232 -0
  21. package/dist/ai.js.map +1 -0
  22. package/dist/dashboard.d.ts.map +1 -1
  23. package/dist/dashboard.js +72 -105
  24. package/dist/dashboard.js.map +1 -1
  25. package/dist/dashboardConfig.d.ts +22 -6
  26. package/dist/dashboardConfig.d.ts.map +1 -1
  27. package/dist/dashboardConfig.js +2 -5
  28. package/dist/dashboardConfig.js.map +1 -1
  29. package/dist/dashboardIntegration.d.ts +3 -0
  30. package/dist/dashboardIntegration.d.ts.map +1 -0
  31. package/dist/dashboardIntegration.js +16 -0
  32. package/dist/dashboardIntegration.js.map +1 -0
  33. package/dist/datasets/PreparedDatasetStore.js +2 -1
  34. package/dist/datasets/PreparedDatasetStore.js.map +1 -1
  35. package/dist/index.d.ts +8 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +5 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/json/colorScaleFunction.d.ts +1 -1
  40. package/dist/json/colorScaleFunction.d.ts.map +1 -1
  41. package/dist/json/colorScaleFunction.js +7 -1
  42. package/dist/json/colorScaleFunction.js.map +1 -1
  43. package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
  44. package/dist/json/extractColorScaleLegends.js +0 -1
  45. package/dist/json/extractColorScaleLegends.js.map +1 -1
  46. package/dist/json/layerCompatibility.d.ts.map +1 -1
  47. package/dist/json/layerCompatibility.js +2 -0
  48. package/dist/json/layerCompatibility.js.map +1 -1
  49. package/dist/mapConfigUtils.d.ts +62 -0
  50. package/dist/mapConfigUtils.d.ts.map +1 -0
  51. package/dist/mapConfigUtils.js +233 -0
  52. package/dist/mapConfigUtils.js.map +1 -0
  53. package/dist/mapDataPolicy.d.ts +4 -0
  54. package/dist/mapDataPolicy.d.ts.map +1 -0
  55. package/dist/mapDataPolicy.js +25 -0
  56. package/dist/mapDataPolicy.js.map +1 -0
  57. package/dist/mapLayerConfigUtils.d.ts +38 -0
  58. package/dist/mapLayerConfigUtils.d.ts.map +1 -0
  59. package/dist/mapLayerConfigUtils.js +185 -0
  60. package/dist/mapLayerConfigUtils.js.map +1 -0
  61. package/dist/prepare/wkbDecoder.d.ts.map +1 -1
  62. package/dist/prepare/wkbDecoder.js +266 -67
  63. package/dist/prepare/wkbDecoder.js.map +1 -1
  64. package/dist/prepare/wkbParser.d.ts +19 -0
  65. package/dist/prepare/wkbParser.d.ts.map +1 -0
  66. package/dist/prepare/wkbParser.js +115 -0
  67. package/dist/prepare/wkbParser.js.map +1 -0
  68. package/dist/types.d.ts +8 -0
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/types.js.map +1 -1
  71. package/package.json +8 -7
  72. package/dist/useDeckLayersReadyRedraw.d.ts +0 -13
  73. package/dist/useDeckLayersReadyRedraw.d.ts.map +0 -1
  74. package/dist/useDeckLayersReadyRedraw.js +0 -35
  75. package/dist/useDeckLayersReadyRedraw.js.map +0 -1
package/README.md CHANGED
@@ -204,6 +204,7 @@ payload in React.
204
204
 
205
205
  - `spec`: a JSON-like deck.gl spec object or JSON string
206
206
  - `datasets`: a dataset registry keyed by dataset id
207
+ - `interleaved`: when true, deck layers insert into MapLibre's layer stack (requires WebGL2). Default: `false`
207
208
  - `deckProps`: runtime-only deck props such as `getTooltip`, `onHover`, `onClick`
208
209
  - `mapProps`: runtime-only MapLibre props
209
210
  - `showLegends`: whether SQLRooms-generated color legends should render
@@ -211,6 +212,15 @@ payload in React.
211
212
  `spec` stays serializable; callbacks and runtime behavior belong in `deckProps`
212
213
  or `mapProps`.
213
214
 
215
+ By default, MapLibre is the root and deck.gl renders in a separate overlay
216
+ canvas via `MapboxOverlay`. MapLibre controls and attribution remain accessible.
217
+ Set `interleaved` to `true` to insert deck layers into MapLibre's layer stack
218
+ (e.g. render points under map labels). This requires WebGL2 (MapLibre GL v3+).
219
+
220
+ ```tsx
221
+ <DeckJsonMap spec={spec} datasets={datasets} interleaved />
222
+ ```
223
+
214
224
  ### Dataset Registry
215
225
 
216
226
  Each SQLRooms-managed layer binds to exactly one dataset through
@@ -259,6 +269,17 @@ For in-memory Arrow datasets, `arrowTable` may be temporarily `undefined` while
259
269
  data is still loading. `DeckJsonMap` will keep rendering the basemap and treat
260
270
  that dataset as loading until a table is provided.
261
271
 
272
+ Use `onDatasetStatesChange` when the surrounding UI needs dataset loading,
273
+ ready, or error state:
274
+
275
+ ```tsx
276
+ <DeckJsonMap
277
+ spec={spec}
278
+ datasets={datasets}
279
+ onDatasetStatesChange={(states) => setDatasetStates(states)}
280
+ />
281
+ ```
282
+
262
283
  ## SQLRooms Layer Bindings
263
284
 
264
285
  SQLRooms-specific layer metadata lives under `_sqlroomsBinding`:
@@ -403,9 +424,10 @@ The current curated layer set is:
403
424
  - `GeoJsonLayer`
404
425
 
405
426
  GeoArrow-native geometry columns are the efficient path. WKB/WKT geometry falls
406
- back to decoding and GeoJSON-binary preparation, with point promotion available
427
+ back to decoding and GeoJSON-binary preparation, with promotion available
407
428
  for point-focused GeoArrow layers such as `GeoArrowScatterplotLayer`,
408
- `GeoArrowHeatmapLayer`, and `GeoArrowColumnLayer`.
429
+ `GeoArrowHeatmapLayer`, and `GeoArrowColumnLayer`, plus polygon promotion for
430
+ `GeoArrowPolygonLayer` and `GeoArrowSolidPolygonLayer`.
409
431
 
410
432
  The GeoArrow layer implementations themselves come from
411
433
  [`@geoarrow/deck.gl-layers`](https://github.com/geoarrow/deck.gl-layers).
@@ -1,4 +1,4 @@
1
1
  import 'maplibre-gl/dist/maplibre-gl.css';
2
2
  import type { DeckJsonMapProps } from './types';
3
- export declare function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, showLegends, className, children, }: DeckJsonMapProps): import("react/jsx-runtime").JSX.Element;
3
+ export declare function DeckJsonMap({ spec, datasets, mapStyle, interleaved, deckProps, mapProps, showLegends, className, children, onDatasetStatesChange, }: DeckJsonMapProps): import("react/jsx-runtime").JSX.Element;
4
4
  //# sourceMappingURL=DeckJsonMap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DeckJsonMap.d.ts","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"AAKA,OAAO,kCAAkC,CAAC;AAW1C,OAAO,KAAK,EAAC,gBAAgB,EAA2B,MAAM,SAAS,CAAC;AA0HxE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAkB,EAClB,SAAS,EACT,QAAQ,GACT,EAAE,gBAAgB,2CAiIlB"}
1
+ {"version":3,"file":"DeckJsonMap.d.ts","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"AAIA,OAAO,kCAAkC,CAAC;AAW1C,OAAO,KAAK,EAAC,gBAAgB,EAA2B,MAAM,SAAS,CAAC;AAoIxE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,WAAmB,EACnB,SAAS,EACT,QAAQ,EACR,WAAkB,EAClB,SAAS,EACT,QAAQ,EACR,qBAAqB,GACtB,EAAE,gBAAgB,2CAwIlB"}
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { JSONConverter } from '@deck.gl/json';
3
- import DeckGL from '@deck.gl/react';
3
+ import { MapboxOverlay } from '@deck.gl/mapbox';
4
4
  import { ColorScaleLegend } from '@sqlrooms/color-scales';
5
5
  import { cn, useTheme } from '@sqlrooms/ui';
6
6
  import 'maplibre-gl/dist/maplibre-gl.css';
7
7
  import { useEffect, useMemo, useRef } from 'react';
8
- import Map from 'react-map-gl/maplibre';
8
+ import Map, { useControl } from 'react-map-gl/maplibre';
9
9
  import { DeckJsonMapSpec } from './DeckJsonMapSpec';
10
10
  import { normalizeDatasets } from './datasets/normalizeDatasets';
11
11
  import { usePreparedDatasetStates } from './datasets/usePreparedDatasetStates';
@@ -13,7 +13,6 @@ import { createDeckJsonConfiguration } from './json/createDeckJsonConfiguration'
13
13
  import { extractColorScaleLegends } from './json/extractColorScaleLegends';
14
14
  import { getLayerCompatibility } from './json/layerCompatibility';
15
15
  import { resolveDatasetId } from './json/layerConfig';
16
- import { useDeckLayersReadyRedraw } from './useDeckLayersReadyRedraw';
17
16
  const DEFAULT_MAP_STYLES = {
18
17
  light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
19
18
  dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
@@ -93,10 +92,16 @@ function renderDatasetErrorOverlay(datasetStates) {
93
92
  }
94
93
  return (_jsx("div", { className: "pointer-events-none absolute inset-x-4 top-4 z-10 space-y-2", children: failedDatasets.map(([datasetId, state]) => (_jsx("div", { className: "rounded-md border border-red-200 bg-red-50/95 px-3 py-2 text-sm text-red-700 shadow-sm", children: `Dataset "${datasetId}" failed: ${state.error.message}` }, datasetId))) }));
95
94
  }
96
- export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, showLegends = true, className, children, }) {
95
+ function DeckOverlayControl({ interleaved, ...deckProps }) {
96
+ const overlay = useControl(() => new MapboxOverlay({ interleaved }));
97
+ overlay.setProps(deckProps);
98
+ return null;
99
+ }
100
+ export function DeckJsonMap({ spec, datasets, mapStyle, interleaved = false, deckProps, mapProps, showLegends = true, className, children, onDatasetStatesChange, }) {
97
101
  const normalizedDatasets = useMemo(() => normalizeDatasets(datasets), [datasets]);
98
102
  const datasetIds = useMemo(() => Object.keys(normalizedDatasets), [normalizedDatasets]);
99
103
  const datasetStates = usePreparedDatasetStates(normalizedDatasets);
104
+ const onDatasetStatesChangeRef = useRef(onDatasetStatesChange);
100
105
  const { spec: parsedSpec, error: specError } = useMemo(() => parseSpec(spec), [spec]);
101
106
  const availableSpec = useMemo(() => parsedSpec
102
107
  ? filterUnavailableLayers(parsedSpec, datasetIds, datasetStates)
@@ -130,6 +135,12 @@ export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, sho
130
135
  console.error(convertedDeckPropsResult.error);
131
136
  }
132
137
  }, [convertedDeckPropsResult.error]);
138
+ useEffect(() => {
139
+ onDatasetStatesChangeRef.current = onDatasetStatesChange;
140
+ }, [onDatasetStatesChange]);
141
+ useEffect(() => {
142
+ onDatasetStatesChangeRef.current?.(datasetStates);
143
+ }, [datasetStates]);
133
144
  const fallbackDeckProps = useMemo(() => extractFallbackDeckProps(availableSpec), [availableSpec]);
134
145
  const convertedDeckProps = (convertedDeckPropsResult.props ??
135
146
  fallbackDeckProps ??
@@ -137,17 +148,11 @@ export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, sho
137
148
  const extraDeckProps = (deckProps ?? {});
138
149
  const extraMapProps = (mapProps ?? {});
139
150
  const hasRenderingError = Boolean(convertedDeckPropsResult.error);
140
- const deckRef = useRef(null);
141
151
  const mergedLayers = hasRenderingError
142
152
  ? []
143
153
  : (deckProps?.layers ??
144
154
  convertedDeckProps.layers ??
145
155
  []);
146
- useDeckLayersReadyRedraw({
147
- deckRef,
148
- hasRenderingError,
149
- layers: mergedLayers,
150
- });
151
156
  const mergedDeckProps = {
152
157
  ...convertedDeckProps,
153
158
  ...extraDeckProps,
@@ -165,6 +170,6 @@ export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, sho
165
170
  datasetStates,
166
171
  })
167
172
  : [], [availableSpec, datasetIds, datasetStates, showLegends]);
168
- 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, _jsx(DeckGL, { ref: deckRef, ...mergedDeckProps, children: _jsx(Map, { ...mergedMapProps, children: children }) }), renderDatasetErrorOverlay(datasetStates), !hasRenderingError && showLegends ? (_jsx("div", { className: "pointer-events-none absolute bottom-2 left-2 z-10 max-w-56", children: _jsx(ColorScaleLegend, { legends: legends }) })) : null] }));
173
+ 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, { ...mergedMapProps, style: { width: '100%', height: '100%', ...mapProps?.style }, children: [_jsx(DeckOverlayControl, { interleaved: interleaved, ...mergedDeckProps }), children] }), renderDatasetErrorOverlay(datasetStates), !hasRenderingError && showLegends ? (_jsx("div", { className: "pointer-events-none absolute bottom-2 left-2 z-10 max-w-56", children: _jsx(ColorScaleLegend, { legends: legends }) })) : null] }));
169
174
  }
170
175
  //# sourceMappingURL=DeckJsonMap.js.map
@@ -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 type {DeckGLRef} from '@deck.gl/react';\nimport DeckGL from '@deck.gl/react';\nimport {ColorScaleLegend} from '@sqlrooms/color-scales';\nimport {cn, ResolvedTheme, useTheme} from '@sqlrooms/ui';\nimport 'maplibre-gl/dist/maplibre-gl.css';\nimport {useEffect, useMemo, useRef} from 'react';\nimport Map from 'react-map-gl/maplibre';\nimport {ZodError} from 'zod';\nimport {DeckJsonMapSpec} from './DeckJsonMapSpec';\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 type {DeckJsonMapProps, PreparedDeckDatasetState} from './types';\nimport {useDeckLayersReadyRedraw} from './useDeckLayersReadyRedraw';\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 === 'ready';\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\nexport function DeckJsonMap({\n spec,\n datasets,\n mapStyle,\n deckProps,\n mapProps,\n showLegends = true,\n className,\n children,\n}: DeckJsonMapProps) {\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\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 useEffect(() => {\n if (convertedDeckPropsResult.error) {\n console.error(convertedDeckPropsResult.error);\n }\n }, [convertedDeckPropsResult.error]);\n\n const fallbackDeckProps = useMemo(\n () => extractFallbackDeckProps(availableSpec),\n [availableSpec],\n );\n const convertedDeckProps = (convertedDeckPropsResult.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(convertedDeckPropsResult.error);\n const deckRef = useRef<DeckGLRef>(null);\n const mergedLayers = hasRenderingError\n ? []\n : (deckProps?.layers ??\n (convertedDeckProps.layers as unknown[] | undefined) ??\n []);\n useDeckLayersReadyRedraw({\n deckRef,\n hasRenderingError,\n layers: mergedLayers,\n });\n\n const mergedDeckProps = {\n ...convertedDeckProps,\n ...extraDeckProps,\n layers: mergedLayers,\n };\n\n const {resolvedTheme} = useTheme();\n\n const mergedMapProps = {\n ...extraMapProps,\n mapStyle:\n mapStyle ?? mapProps?.mapStyle ?? DEFAULT_MAP_STYLES[resolvedTheme],\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 <DeckGL ref={deckRef} {...(mergedDeckProps as object)}>\n <Map {...(mergedMapProps as object)}>{children}</Map>\n </DeckGL>\n\n {renderDatasetErrorOverlay(datasetStates)}\n {!hasRenderingError && showLegends ? (\n <div className=\"pointer-events-none absolute bottom-2 left-2 z-10 max-w-56\">\n <ColorScaleLegend legends={legends} />\n </div>\n ) : null}\n </div>\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 {cn, ResolvedTheme, useTheme} from '@sqlrooms/ui';\nimport 'maplibre-gl/dist/maplibre-gl.css';\nimport {useEffect, useMemo, useRef} from 'react';\nimport Map, {useControl} from 'react-map-gl/maplibre';\nimport {ZodError} from 'zod';\nimport {DeckJsonMapSpec} from './DeckJsonMapSpec';\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 type {DeckJsonMapProps, PreparedDeckDatasetState} 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 === 'ready';\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\nfunction DeckOverlayControl({\n interleaved,\n ...deckProps\n}: {interleaved: boolean} & Record<string, unknown>) {\n const overlay = useControl<MapboxOverlay>(\n () => new MapboxOverlay({interleaved}),\n );\n overlay.setProps(deckProps);\n return null;\n}\n\nexport function DeckJsonMap({\n spec,\n datasets,\n mapStyle,\n interleaved = false,\n deckProps,\n mapProps,\n showLegends = true,\n className,\n children,\n onDatasetStatesChange,\n}: DeckJsonMapProps) {\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 useEffect(() => {\n if (convertedDeckPropsResult.error) {\n console.error(convertedDeckPropsResult.error);\n }\n }, [convertedDeckPropsResult.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 = (convertedDeckPropsResult.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(convertedDeckPropsResult.error);\n const mergedLayers = hasRenderingError\n ? []\n : (deckProps?.layers ??\n (convertedDeckProps.layers as unknown[] | undefined) ??\n []);\n\n const mergedDeckProps = {\n ...convertedDeckProps,\n ...extraDeckProps,\n layers: mergedLayers,\n };\n\n const {resolvedTheme} = useTheme();\n\n const mergedMapProps = {\n ...extraMapProps,\n mapStyle:\n mapStyle ?? mapProps?.mapStyle ?? DEFAULT_MAP_STYLES[resolvedTheme],\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 {...(mergedMapProps as object)}\n style={{width: '100%', height: '100%', ...mapProps?.style}}\n >\n <DeckOverlayControl interleaved={interleaved} {...mergedDeckProps} />\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 <ColorScaleLegend legends={legends} />\n </div>\n ) : null}\n </div>\n );\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { FC } from 'react';
2
+ import type { MosaicDashboardPanelConfigType } from '@sqlrooms/mosaic';
3
+ import type { DataTable } from '@sqlrooms/duckdb';
4
+ interface LatitudeSelectorProps {
5
+ dashboardId: string;
6
+ panel: MosaicDashboardPanelConfigType;
7
+ currentTable: DataTable;
8
+ }
9
+ export declare const LatitudeSelector: FC<LatitudeSelectorProps>;
10
+ export {};
11
+ //# sourceMappingURL=LatitudeSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LatitudeSelector.d.ts","sourceRoot":"","sources":["../src/LatitudeSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAc,MAAM,OAAO,CAAC;AAEtC,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAIhD,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,8BAA8B,CAAC;IACtC,YAAY,EAAE,SAAS,CAAC;CACzB;AAED,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CA0CtD,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback } from 'react';
3
+ import { useStoreWithMosaicDashboard, ColumnSelector } from '@sqlrooms/mosaic';
4
+ import { regenerateMapConfigForTable } from './mapConfigUtils';
5
+ export const LatitudeSelector = ({ dashboardId, panel, currentTable, }) => {
6
+ const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
7
+ const mapConfig = panel.config;
8
+ const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;
9
+ const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;
10
+ const handleChange = useCallback((latitudeColumn) => {
11
+ const newConfig = regenerateMapConfigForTable(panel, currentTable, currentLongitudeColumn, latitudeColumn);
12
+ updatePanel(dashboardId, panel.id, {
13
+ config: { ...newConfig, settingsOpen: mapConfig?.settingsOpen },
14
+ });
15
+ }, [
16
+ currentLongitudeColumn,
17
+ panel,
18
+ currentTable,
19
+ updatePanel,
20
+ dashboardId,
21
+ mapConfig?.settingsOpen,
22
+ ]);
23
+ return (_jsx(ColumnSelector.Numeric, { value: currentLatitudeColumn, onChange: handleChange }));
24
+ };
25
+ //# sourceMappingURL=LatitudeSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LatitudeSelector.js","sourceRoot":"","sources":["../src/LatitudeSelector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAK,WAAW,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,2BAA2B,EAAE,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAG7E,OAAO,EAAC,2BAA2B,EAAC,MAAM,kBAAkB,CAAC;AAS7D,MAAM,CAAC,MAAM,gBAAgB,GAA8B,CAAC,EAC1D,WAAW,EACX,KAAK,EACL,YAAY,GACb,EAAE,EAAE;IACH,MAAM,WAAW,GAAG,2BAA2B,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAC7C,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAqC,CAAC;IAC9D,MAAM,sBAAsB,GAAG,SAAS,EAAE,SAAS,EAAE,eAAe,CAAC;IACrE,MAAM,qBAAqB,GAAG,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC;IAEnE,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,cAAsB,EAAE,EAAE;QACzB,MAAM,SAAS,GAAG,2BAA2B,CAC3C,KAAK,EACL,YAAY,EACZ,sBAAsB,EACtB,cAAc,CACf,CAAC;QAEF,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE;YACjC,MAAM,EAAE,EAAC,GAAG,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAQ;SACrE,CAAC,CAAC;IACL,CAAC,EACD;QACE,sBAAsB;QACtB,KAAK;QACL,YAAY;QACZ,WAAW;QACX,WAAW;QACX,SAAS,EAAE,YAAY;KACxB,CACF,CAAC;IAEF,OAAO,CACL,KAAC,cAAc,CAAC,OAAO,IACrB,KAAK,EAAE,qBAAqB,EAC5B,QAAQ,EAAE,YAAY,GACtB,CACH,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {FC, useCallback} from 'react';\nimport {useStoreWithMosaicDashboard, ColumnSelector} from '@sqlrooms/mosaic';\nimport type {MosaicDashboardPanelConfigType} from '@sqlrooms/mosaic';\nimport type {DataTable} from '@sqlrooms/duckdb';\nimport {regenerateMapConfigForTable} from './mapConfigUtils';\nimport {DeckMapDashboardPanelConfig} from './dashboardConfig';\n\ninterface LatitudeSelectorProps {\n dashboardId: string;\n panel: MosaicDashboardPanelConfigType;\n currentTable: DataTable;\n}\n\nexport const LatitudeSelector: FC<LatitudeSelectorProps> = ({\n dashboardId,\n panel,\n currentTable,\n}) => {\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n\n const mapConfig = panel.config as DeckMapDashboardPanelConfig;\n const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;\n const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;\n\n const handleChange = useCallback(\n (latitudeColumn: string) => {\n const newConfig = regenerateMapConfigForTable(\n panel,\n currentTable,\n currentLongitudeColumn,\n latitudeColumn,\n );\n\n updatePanel(dashboardId, panel.id, {\n config: {...newConfig, settingsOpen: mapConfig?.settingsOpen} as any,\n });\n },\n [\n currentLongitudeColumn,\n panel,\n currentTable,\n updatePanel,\n dashboardId,\n mapConfig?.settingsOpen,\n ],\n );\n\n return (\n <ColumnSelector.Numeric\n value={currentLatitudeColumn}\n onChange={handleChange}\n />\n );\n};\n"]}
@@ -0,0 +1,11 @@
1
+ import { FC } from 'react';
2
+ import type { MosaicDashboardPanelConfigType } from '@sqlrooms/mosaic';
3
+ import type { DataTable } from '@sqlrooms/duckdb';
4
+ interface LongitudeSelectorProps {
5
+ dashboardId: string;
6
+ panel: MosaicDashboardPanelConfigType;
7
+ currentTable: DataTable;
8
+ }
9
+ export declare const LongitudeSelector: FC<LongitudeSelectorProps>;
10
+ export {};
11
+ //# sourceMappingURL=LongitudeSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LongitudeSelector.d.ts","sourceRoot":"","sources":["../src/LongitudeSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAc,MAAM,OAAO,CAAC;AAEtC,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAIhD,UAAU,sBAAsB;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,8BAA8B,CAAC;IACtC,YAAY,EAAE,SAAS,CAAC;CACzB;AAED,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CA4CxD,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback } from 'react';
3
+ import { useStoreWithMosaicDashboard, ColumnSelector } from '@sqlrooms/mosaic';
4
+ import { regenerateMapConfigForTable } from './mapConfigUtils';
5
+ export const LongitudeSelector = ({ dashboardId, panel, currentTable, }) => {
6
+ const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
7
+ const mapConfig = panel.config;
8
+ const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;
9
+ const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;
10
+ const handleChange = useCallback((longitudeColumn) => {
11
+ if (!currentLatitudeColumn)
12
+ return;
13
+ const newConfig = regenerateMapConfigForTable(panel, currentTable, longitudeColumn, currentLatitudeColumn);
14
+ updatePanel(dashboardId, panel.id, {
15
+ config: { ...newConfig, settingsOpen: mapConfig?.settingsOpen },
16
+ });
17
+ }, [
18
+ currentLatitudeColumn,
19
+ panel,
20
+ currentTable,
21
+ updatePanel,
22
+ dashboardId,
23
+ mapConfig?.settingsOpen,
24
+ ]);
25
+ return (_jsx(ColumnSelector.Numeric, { value: currentLongitudeColumn, onChange: handleChange }));
26
+ };
27
+ //# sourceMappingURL=LongitudeSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LongitudeSelector.js","sourceRoot":"","sources":["../src/LongitudeSelector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAK,WAAW,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,2BAA2B,EAAE,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAG7E,OAAO,EAAC,2BAA2B,EAAC,MAAM,kBAAkB,CAAC;AAS7D,MAAM,CAAC,MAAM,iBAAiB,GAA+B,CAAC,EAC5D,WAAW,EACX,KAAK,EACL,YAAY,GACb,EAAE,EAAE;IACH,MAAM,WAAW,GAAG,2BAA2B,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAC7C,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAqC,CAAC;IAC9D,MAAM,sBAAsB,GAAG,SAAS,EAAE,SAAS,EAAE,eAAe,CAAC;IACrE,MAAM,qBAAqB,GAAG,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC;IAEnE,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,eAAuB,EAAE,EAAE;QAC1B,IAAI,CAAC,qBAAqB;YAAE,OAAO;QAEnC,MAAM,SAAS,GAAG,2BAA2B,CAC3C,KAAK,EACL,YAAY,EACZ,eAAe,EACf,qBAAqB,CACtB,CAAC;QAEF,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE;YACjC,MAAM,EAAE,EAAC,GAAG,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAQ;SACrE,CAAC,CAAC;IACL,CAAC,EACD;QACE,qBAAqB;QACrB,KAAK;QACL,YAAY;QACZ,WAAW;QACX,WAAW;QACX,SAAS,EAAE,YAAY;KACxB,CACF,CAAC;IAEF,OAAO,CACL,KAAC,cAAc,CAAC,OAAO,IACrB,KAAK,EAAE,sBAAsB,EAC7B,QAAQ,EAAE,YAAY,GACtB,CACH,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {FC, useCallback} from 'react';\nimport {useStoreWithMosaicDashboard, ColumnSelector} from '@sqlrooms/mosaic';\nimport type {MosaicDashboardPanelConfigType} from '@sqlrooms/mosaic';\nimport type {DataTable} from '@sqlrooms/duckdb';\nimport {regenerateMapConfigForTable} from './mapConfigUtils';\nimport {DeckMapDashboardPanelConfig} from './dashboardConfig';\n\ninterface LongitudeSelectorProps {\n dashboardId: string;\n panel: MosaicDashboardPanelConfigType;\n currentTable: DataTable;\n}\n\nexport const LongitudeSelector: FC<LongitudeSelectorProps> = ({\n dashboardId,\n panel,\n currentTable,\n}) => {\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n\n const mapConfig = panel.config as DeckMapDashboardPanelConfig;\n const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;\n const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;\n\n const handleChange = useCallback(\n (longitudeColumn: string) => {\n if (!currentLatitudeColumn) return;\n\n const newConfig = regenerateMapConfigForTable(\n panel,\n currentTable,\n longitudeColumn,\n currentLatitudeColumn,\n );\n\n updatePanel(dashboardId, panel.id, {\n config: {...newConfig, settingsOpen: mapConfig?.settingsOpen} as any,\n });\n },\n [\n currentLatitudeColumn,\n panel,\n currentTable,\n updatePanel,\n dashboardId,\n mapConfig?.settingsOpen,\n ],\n );\n\n return (\n <ColumnSelector.Numeric\n value={currentLongitudeColumn}\n onChange={handleChange}\n />\n );\n};\n"]}
@@ -0,0 +1,10 @@
1
+ import { FC } from 'react';
2
+ import type { MosaicDashboardPanelConfigType } from '@sqlrooms/mosaic';
3
+ interface MapSettingsPanelProps {
4
+ dashboardId: string;
5
+ panel: MosaicDashboardPanelConfigType;
6
+ onClose?: () => void;
7
+ }
8
+ export declare const MapSettingsPanel: FC<MapSettingsPanelProps>;
9
+ export {};
10
+ //# sourceMappingURL=MapSettings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapSettings.d.ts","sourceRoot":"","sources":["../src/MapSettings.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAiC,MAAM,OAAO,CAAC;AAOzD,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,kBAAkB,CAAC;AAwCrE,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,8BAA8B,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAeD,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAuUtD,CAAC"}
@@ -0,0 +1,96 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useMemo, useState } from 'react';
3
+ import { Field, ColumnSelector, ColumnsProvider, useStoreWithMosaicDashboard, } from '@sqlrooms/mosaic';
4
+ import { useStoreWithDuckDb } from '@sqlrooms/duckdb';
5
+ import { binnedNumericSchemes, categoricalSchemes, continuousDivergingSchemes, continuousSequentialSchemes, } from '@sqlrooms/color-scales';
6
+ import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, } from '@sqlrooms/ui';
7
+ import { XIcon } from 'lucide-react';
8
+ import { LatitudeSelector } from './LatitudeSelector';
9
+ import { LongitudeSelector } from './LongitudeSelector';
10
+ import { DEFAULT_DECK_MAP_MAX_DATA_POINTS } from './dashboardConfig';
11
+ import { clearDeckMapLayerColorScale, createDeckMapLayerColorScale, DECK_MAP_COLOR_SCALE_TYPE_OPTIONS, DECK_MAP_LAYER_TYPE_OPTIONS, getDeckMapColorAccessorOptions, getDeckMapLayerDatasetId, getDeckMapLayerColorScale, getDeckMapLayerRecords, setDeckMapLayerColorScale, setDeckMapLayerGeometryColumn, setDeckMapLayerType, usesGeometryColumnSetting, } from './mapLayerConfigUtils';
12
+ function getSchemeOptions(type) {
13
+ if (type === 'categorical') {
14
+ return categoricalSchemes;
15
+ }
16
+ if (type === 'diverging') {
17
+ return continuousDivergingSchemes;
18
+ }
19
+ if (type === 'sequential') {
20
+ return continuousSequentialSchemes;
21
+ }
22
+ return binnedNumericSchemes;
23
+ }
24
+ export const MapSettingsPanel = ({ dashboardId, panel, onClose, }) => {
25
+ const [layerIndex, setLayerIndex] = useState(0);
26
+ const [colorAccessor, setColorAccessor] = useState('getFillColor');
27
+ const tables = useStoreWithDuckDb((state) => state.db.tables);
28
+ const tableName = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.config.dashboardsById[dashboardId]?.selectedTable);
29
+ const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
30
+ const currentTable = useMemo(() => tables.find((t) => t.table.table === tableName), [tables, tableName]);
31
+ const mapConfig = panel.config;
32
+ const layers = getDeckMapLayerRecords(mapConfig);
33
+ const activeLayerIndex = Math.min(layerIndex, Math.max(layers.length - 1, 0));
34
+ const activeLayer = layers[activeLayerIndex];
35
+ const activeLayerDatasetId = getDeckMapLayerDatasetId(activeLayer);
36
+ const activeLayerDataset = activeLayerDatasetId
37
+ ? mapConfig.datasets?.[activeLayerDatasetId]
38
+ : undefined;
39
+ const showGeometryColumnSetting = usesGeometryColumnSetting(activeLayer?.['@@type']);
40
+ const colorAccessorOptions = getDeckMapColorAccessorOptions(activeLayer?.['@@type']);
41
+ const effectiveColorAccessor = colorAccessorOptions.find((option) => option.value === colorAccessor)
42
+ ?.value ?? colorAccessorOptions[0]?.value;
43
+ const colorScale = effectiveColorAccessor
44
+ ? getDeckMapLayerColorScale(activeLayer, effectiveColorAccessor)
45
+ : undefined;
46
+ const colorScaleType = colorScale?.type ?? 'sequential';
47
+ const schemeOptions = getSchemeOptions(colorScaleType);
48
+ const firstColumnName = currentTable?.columns[0]?.name;
49
+ const maxRows = mapConfig.dataPolicy?.maxRows ?? DEFAULT_DECK_MAP_MAX_DATA_POINTS;
50
+ const applyConfig = useCallback((config) => {
51
+ updatePanel(dashboardId, panel.id, {
52
+ config: { ...config, settingsOpen: mapConfig.settingsOpen },
53
+ });
54
+ }, [dashboardId, mapConfig.settingsOpen, panel.id, updatePanel]);
55
+ const updateColorScale = (patch) => {
56
+ const field = patch.field ?? colorScale?.field ?? firstColumnName;
57
+ if (!field || !effectiveColorAccessor)
58
+ return;
59
+ const type = patch.type ?? colorScale?.type ?? 'sequential';
60
+ const scheme = patch.scheme ??
61
+ (patch.type && patch.type !== colorScale?.type
62
+ ? undefined
63
+ : colorScale?.scheme);
64
+ applyConfig(setDeckMapLayerColorScale(mapConfig, activeLayerIndex, effectiveColorAccessor, createDeckMapLayerColorScale({
65
+ field,
66
+ type,
67
+ scheme,
68
+ title: field,
69
+ })));
70
+ };
71
+ 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("div", { className: "flex items-center", 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" }) }))] }), _jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-2", children: [layers.length > 0 && (_jsxs("div", { className: "flex flex-col gap-3", children: [layers.length > 1 && (_jsx(Field, { label: "Layer", children: _jsxs(Select, { value: String(activeLayerIndex), onValueChange: (value) => setLayerIndex(Number(value)), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: layers.map((layer, index) => (_jsx(SelectItem, { value: String(index), children: String(layer.id ?? `Layer ${index + 1}`) }, index))) })] }) })), _jsx(Field, { label: "Layer type", children: _jsxs(Select, { value: typeof activeLayer?.['@@type'] === 'string'
72
+ ? activeLayer['@@type']
73
+ : undefined, onValueChange: (value) => applyConfig(setDeckMapLayerType(mapConfig, activeLayerIndex, value)), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: "Select layer type" }) }), _jsx(SelectContent, { children: DECK_MAP_LAYER_TYPE_OPTIONS.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }) }), _jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Color scale" }), _jsx(Switch, { checked: Boolean(colorScale), onCheckedChange: (checked) => {
74
+ if (!effectiveColorAccessor)
75
+ return;
76
+ if (checked) {
77
+ updateColorScale({});
78
+ return;
79
+ }
80
+ applyConfig(clearDeckMapLayerColorScale(mapConfig, activeLayerIndex, effectiveColorAccessor));
81
+ }, disabled: !firstColumnName || !effectiveColorAccessor })] }), effectiveColorAccessor && (_jsx(Field, { label: "Color property", children: _jsxs(Select, { value: effectiveColorAccessor, onValueChange: (value) => setColorAccessor(value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: colorAccessorOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }) })), colorScale && currentTable && (_jsx(ColumnsProvider, { columns: currentTable.columns, tableName: tableName, children: _jsx(Field, { label: "Color field", required: true, children: colorScaleType === 'categorical' ? (_jsx(ColumnSelector.Categorical, { value: colorScale.field, onChange: (field) => updateColorScale({ field }) })) : (_jsx(ColumnSelector.Quantitative, { value: colorScale.field, onChange: (field) => updateColorScale({ field }) })) }) })), colorScale && (_jsxs(_Fragment, { children: [_jsx(Field, { label: "Scale type", children: _jsxs(Select, { value: colorScaleType, onValueChange: (value) => updateColorScale({
82
+ type: value,
83
+ }), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: DECK_MAP_COLOR_SCALE_TYPE_OPTIONS.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }) }), _jsx(Field, { label: "Scheme", children: _jsxs(Select, { value: colorScale.scheme, onValueChange: (value) => updateColorScale({ scheme: value }), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: schemeOptions.map((scheme) => (_jsx(SelectItem, { value: scheme, children: scheme }, scheme))) })] }) })] }))] })] })), currentTable && showGeometryColumnSetting && (_jsx(ColumnsProvider, { columns: currentTable.columns, tableName: tableName, children: _jsx(Field, { label: "Geometry column", required: true, children: _jsx(ColumnSelector, { value: activeLayerDataset?.geometryColumn, onChange: (geometryColumn) => applyConfig(setDeckMapLayerGeometryColumn(mapConfig, activeLayerIndex, geometryColumn)), placeholder: "Select geometry column..." }) }) })), currentTable && !showGeometryColumnSetting && (_jsxs(ColumnsProvider, { columns: currentTable.columns, tableName: tableName, children: [_jsx(Field, { label: "Latitude column", required: true, children: _jsx(LatitudeSelector, { dashboardId: dashboardId, panel: panel, currentTable: currentTable }) }), _jsx(Field, { label: "Longitude column", required: true, children: _jsx(LongitudeSelector, { dashboardId: dashboardId, panel: panel, currentTable: currentTable }) })] })), _jsx(Field, { label: "Max rows", children: _jsx(Input, { type: "number", min: 1, value: maxRows, className: "no-spinner", onChange: (event) => {
84
+ const parsed = Number.parseInt(event.target.value, 10);
85
+ if (!Number.isFinite(parsed) || parsed < 1)
86
+ return;
87
+ applyConfig({
88
+ ...mapConfig,
89
+ dataPolicy: {
90
+ ...mapConfig.dataPolicy,
91
+ maxRows: parsed,
92
+ },
93
+ });
94
+ }, placeholder: String(DEFAULT_DECK_MAP_MAX_DATA_POINTS) }) })] })] }));
95
+ };
96
+ //# sourceMappingURL=MapSettings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapSettings.js","sourceRoot":"","sources":["../src/MapSettings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {FC, useCallback, useMemo, useState} from 'react';\nimport {\n Field,\n ColumnSelector,\n ColumnsProvider,\n useStoreWithMosaicDashboard,\n} from '@sqlrooms/mosaic';\nimport type {MosaicDashboardPanelConfigType} from '@sqlrooms/mosaic';\nimport {useStoreWithDuckDb} from '@sqlrooms/duckdb';\nimport {\n binnedNumericSchemes,\n categoricalSchemes,\n continuousDivergingSchemes,\n continuousSequentialSchemes,\n} from '@sqlrooms/color-scales';\nimport type {ColorScaleConfig, ColorScaleScheme} from '@sqlrooms/color-scales';\nimport {\n Button,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Switch,\n} from '@sqlrooms/ui';\nimport {XIcon} from 'lucide-react';\nimport {LatitudeSelector} from './LatitudeSelector';\nimport {LongitudeSelector} from './LongitudeSelector';\nimport type {DeckMapDashboardPanelConfig} from './dashboardConfig';\nimport {DEFAULT_DECK_MAP_MAX_DATA_POINTS} from './dashboardConfig';\nimport {\n clearDeckMapLayerColorScale,\n createDeckMapLayerColorScale,\n DECK_MAP_COLOR_SCALE_TYPE_OPTIONS,\n DECK_MAP_LAYER_TYPE_OPTIONS,\n getDeckMapColorAccessorOptions,\n getDeckMapLayerDatasetId,\n getDeckMapLayerColorScale,\n getDeckMapLayerRecords,\n setDeckMapLayerColorScale,\n setDeckMapLayerGeometryColumn,\n setDeckMapLayerType,\n type DeckMapLayerColorAccessor,\n usesGeometryColumnSetting,\n} from './mapLayerConfigUtils';\n\ninterface MapSettingsPanelProps {\n dashboardId: string;\n panel: MosaicDashboardPanelConfigType;\n onClose?: () => void;\n}\n\nfunction getSchemeOptions(type: ColorScaleConfig['type']) {\n if (type === 'categorical') {\n return categoricalSchemes;\n }\n if (type === 'diverging') {\n return continuousDivergingSchemes;\n }\n if (type === 'sequential') {\n return continuousSequentialSchemes;\n }\n return binnedNumericSchemes;\n}\n\nexport const MapSettingsPanel: FC<MapSettingsPanelProps> = ({\n dashboardId,\n panel,\n onClose,\n}) => {\n const [layerIndex, setLayerIndex] = useState(0);\n const [colorAccessor, setColorAccessor] =\n useState<DeckMapLayerColorAccessor>('getFillColor');\n const tables = useStoreWithDuckDb((state) => state.db.tables);\n const tableName = useStoreWithMosaicDashboard(\n (state) =>\n state.mosaicDashboard.config.dashboardsById[dashboardId]?.selectedTable,\n );\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n const currentTable = useMemo(\n () => tables.find((t) => t.table.table === tableName),\n [tables, tableName],\n );\n const mapConfig = panel.config as DeckMapDashboardPanelConfig;\n const layers = getDeckMapLayerRecords(mapConfig);\n const activeLayerIndex = Math.min(layerIndex, Math.max(layers.length - 1, 0));\n const activeLayer = layers[activeLayerIndex];\n const activeLayerDatasetId = getDeckMapLayerDatasetId(activeLayer);\n const activeLayerDataset = activeLayerDatasetId\n ? mapConfig.datasets?.[activeLayerDatasetId]\n : undefined;\n const showGeometryColumnSetting = usesGeometryColumnSetting(\n activeLayer?.['@@type'],\n );\n const colorAccessorOptions = getDeckMapColorAccessorOptions(\n activeLayer?.['@@type'],\n );\n const effectiveColorAccessor =\n colorAccessorOptions.find((option) => option.value === colorAccessor)\n ?.value ?? colorAccessorOptions[0]?.value;\n const colorScale = effectiveColorAccessor\n ? getDeckMapLayerColorScale(activeLayer, effectiveColorAccessor)\n : undefined;\n const colorScaleType = colorScale?.type ?? 'sequential';\n const schemeOptions = getSchemeOptions(colorScaleType);\n const firstColumnName = currentTable?.columns[0]?.name;\n const maxRows =\n mapConfig.dataPolicy?.maxRows ?? DEFAULT_DECK_MAP_MAX_DATA_POINTS;\n\n const applyConfig = useCallback(\n (config: DeckMapDashboardPanelConfig) => {\n updatePanel(dashboardId, panel.id, {\n config: {...config, settingsOpen: mapConfig.settingsOpen} as any,\n });\n },\n [dashboardId, mapConfig.settingsOpen, panel.id, updatePanel],\n );\n\n const updateColorScale = (patch: {\n field?: string;\n type?: ColorScaleConfig['type'];\n scheme?: ColorScaleScheme;\n }) => {\n const field = patch.field ?? colorScale?.field ?? firstColumnName;\n if (!field || !effectiveColorAccessor) return;\n\n const type = patch.type ?? colorScale?.type ?? 'sequential';\n const scheme =\n patch.scheme ??\n (patch.type && patch.type !== colorScale?.type\n ? undefined\n : colorScale?.scheme);\n\n applyConfig(\n setDeckMapLayerColorScale(\n mapConfig,\n activeLayerIndex,\n effectiveColorAccessor,\n createDeckMapLayerColorScale({\n field,\n type,\n scheme,\n title: field,\n }),\n ),\n );\n };\n\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 <div className=\"flex items-center\">Map settings</div>\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 )}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-2\">\n {layers.length > 0 && (\n <div className=\"flex flex-col gap-3\">\n {layers.length > 1 && (\n <Field label=\"Layer\">\n <Select\n value={String(activeLayerIndex)}\n onValueChange={(value) => setLayerIndex(Number(value))}\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {layers.map((layer, index) => (\n <SelectItem key={index} value={String(index)}>\n {String(layer.id ?? `Layer ${index + 1}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n )}\n\n <Field label=\"Layer type\">\n <Select\n value={\n typeof activeLayer?.['@@type'] === 'string'\n ? activeLayer['@@type']\n : undefined\n }\n onValueChange={(value) =>\n applyConfig(\n setDeckMapLayerType(mapConfig, activeLayerIndex, value),\n )\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder=\"Select layer type\" />\n </SelectTrigger>\n <SelectContent>\n {DECK_MAP_LAYER_TYPE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n\n <div className=\"flex flex-col gap-2 rounded-md border p-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"text-xs font-medium\">Color scale</span>\n <Switch\n checked={Boolean(colorScale)}\n onCheckedChange={(checked) => {\n if (!effectiveColorAccessor) return;\n if (checked) {\n updateColorScale({});\n return;\n }\n applyConfig(\n clearDeckMapLayerColorScale(\n mapConfig,\n activeLayerIndex,\n effectiveColorAccessor,\n ),\n );\n }}\n disabled={!firstColumnName || !effectiveColorAccessor}\n />\n </div>\n\n {effectiveColorAccessor && (\n <Field label=\"Color property\">\n <Select\n value={effectiveColorAccessor}\n onValueChange={(value) =>\n setColorAccessor(value as DeckMapLayerColorAccessor)\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {colorAccessorOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n )}\n\n {colorScale && currentTable && (\n <ColumnsProvider\n columns={currentTable.columns}\n tableName={tableName}\n >\n <Field label=\"Color field\" required>\n {colorScaleType === 'categorical' ? (\n <ColumnSelector.Categorical\n value={colorScale.field}\n onChange={(field) => updateColorScale({field})}\n />\n ) : (\n <ColumnSelector.Quantitative\n value={colorScale.field}\n onChange={(field) => updateColorScale({field})}\n />\n )}\n </Field>\n </ColumnsProvider>\n )}\n\n {colorScale && (\n <>\n <Field label=\"Scale type\">\n <Select\n value={colorScaleType}\n onValueChange={(value) =>\n updateColorScale({\n type: value as ColorScaleConfig['type'],\n })\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DECK_MAP_COLOR_SCALE_TYPE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n\n <Field label=\"Scheme\">\n <Select\n value={colorScale.scheme}\n onValueChange={(value) =>\n updateColorScale({scheme: value as ColorScaleScheme})\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {schemeOptions.map((scheme) => (\n <SelectItem key={scheme} value={scheme}>\n {scheme}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n </>\n )}\n </div>\n </div>\n )}\n\n {currentTable && showGeometryColumnSetting && (\n <ColumnsProvider columns={currentTable.columns} tableName={tableName}>\n <Field label=\"Geometry column\" required>\n <ColumnSelector\n value={activeLayerDataset?.geometryColumn}\n onChange={(geometryColumn) =>\n applyConfig(\n setDeckMapLayerGeometryColumn(\n mapConfig,\n activeLayerIndex,\n geometryColumn,\n ),\n )\n }\n placeholder=\"Select geometry column...\"\n />\n </Field>\n </ColumnsProvider>\n )}\n\n {currentTable && !showGeometryColumnSetting && (\n <ColumnsProvider columns={currentTable.columns} tableName={tableName}>\n <Field label=\"Latitude column\" required>\n <LatitudeSelector\n dashboardId={dashboardId}\n panel={panel}\n currentTable={currentTable}\n />\n </Field>\n <Field label=\"Longitude column\" required>\n <LongitudeSelector\n dashboardId={dashboardId}\n panel={panel}\n currentTable={currentTable}\n />\n </Field>\n </ColumnsProvider>\n )}\n\n <Field label=\"Max rows\">\n <Input\n type=\"number\"\n min={1}\n value={maxRows}\n className=\"no-spinner\"\n onChange={(event) => {\n const parsed = Number.parseInt(event.target.value, 10);\n if (!Number.isFinite(parsed) || parsed < 1) return;\n applyConfig({\n ...mapConfig,\n dataPolicy: {\n ...mapConfig.dataPolicy,\n maxRows: parsed,\n },\n });\n }}\n placeholder={String(DEFAULT_DECK_MAP_MAX_DATA_POINTS)}\n />\n </Field>\n </div>\n </div>\n );\n};\n"]}