@sqlrooms/mosaic 0.29.0-rc.0 → 0.29.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -2
- package/dist/MosaicChart.d.ts +20 -0
- package/dist/MosaicChart.d.ts.map +1 -0
- package/dist/MosaicChart.js +25 -0
- package/dist/MosaicChart.js.map +1 -0
- package/dist/MosaicChartBuilder.d.ts +32 -0
- package/dist/MosaicChartBuilder.d.ts.map +1 -0
- package/dist/MosaicChartBuilder.js +35 -0
- package/dist/MosaicChartBuilder.js.map +1 -0
- package/dist/MosaicColorLegend.d.ts +18 -0
- package/dist/MosaicColorLegend.d.ts.map +1 -0
- package/dist/MosaicColorLegend.js +117 -0
- package/dist/MosaicColorLegend.js.map +1 -0
- package/dist/MosaicSlice.d.ts +16 -13
- package/dist/MosaicSlice.d.ts.map +1 -1
- package/dist/MosaicSlice.js +67 -32
- package/dist/MosaicSlice.js.map +1 -1
- package/dist/VgPlotChart.d.ts +8 -0
- package/dist/VgPlotChart.d.ts.map +1 -1
- package/dist/VgPlotChart.js +26 -6
- package/dist/VgPlotChart.js.map +1 -1
- package/dist/chart-builders/ChartBuilderContent.d.ts +26 -0
- package/dist/chart-builders/ChartBuilderContent.d.ts.map +1 -0
- package/dist/chart-builders/ChartBuilderContent.js +59 -0
- package/dist/chart-builders/ChartBuilderContent.js.map +1 -0
- package/dist/chart-builders/ChartBuilderContext.d.ts +11 -0
- package/dist/chart-builders/ChartBuilderContext.d.ts.map +1 -0
- package/dist/chart-builders/ChartBuilderContext.js +10 -0
- package/dist/chart-builders/ChartBuilderContext.js.map +1 -0
- package/dist/chart-builders/ChartBuilderDialog.d.ts +23 -0
- package/dist/chart-builders/ChartBuilderDialog.d.ts.map +1 -0
- package/dist/chart-builders/ChartBuilderDialog.js +15 -0
- package/dist/chart-builders/ChartBuilderDialog.js.map +1 -0
- package/dist/chart-builders/FieldSelectorInput.d.ts +13 -0
- package/dist/chart-builders/FieldSelectorInput.d.ts.map +1 -0
- package/dist/chart-builders/FieldSelectorInput.js +19 -0
- package/dist/chart-builders/FieldSelectorInput.js.map +1 -0
- package/dist/chart-builders/builders.d.ts +7 -0
- package/dist/chart-builders/builders.d.ts.map +1 -0
- package/dist/chart-builders/builders.js +280 -0
- package/dist/chart-builders/builders.js.map +1 -0
- package/dist/chart-builders/chartSpecTitle.d.ts +7 -0
- package/dist/chart-builders/chartSpecTitle.d.ts.map +1 -0
- package/dist/chart-builders/chartSpecTitle.js +10 -0
- package/dist/chart-builders/chartSpecTitle.js.map +1 -0
- package/dist/chart-builders/createMosaicChartTool.d.ts +45 -0
- package/dist/chart-builders/createMosaicChartTool.d.ts.map +1 -0
- package/dist/chart-builders/createMosaicChartTool.js +109 -0
- package/dist/chart-builders/createMosaicChartTool.js.map +1 -0
- package/dist/chart-builders/describeChartSpecs.d.ts +7 -0
- package/dist/chart-builders/describeChartSpecs.d.ts.map +1 -0
- package/dist/chart-builders/describeChartSpecs.js +38 -0
- package/dist/chart-builders/describeChartSpecs.js.map +1 -0
- package/dist/chart-builders/types.d.ts +40 -0
- package/dist/chart-builders/types.d.ts.map +1 -0
- package/dist/chart-builders/types.js +2 -0
- package/dist/chart-builders/types.js.map +1 -0
- package/dist/dashboard/MosaicDashboard.d.ts +20 -0
- package/dist/dashboard/MosaicDashboard.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboard.js +68 -0
- package/dist/dashboard/MosaicDashboard.js.map +1 -0
- package/dist/dashboard/MosaicDashboardChartPanel.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardChartPanel.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardChartPanel.js +49 -0
- package/dist/dashboard/MosaicDashboardChartPanel.js.map +1 -0
- package/dist/dashboard/MosaicDashboardCharts.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardCharts.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardCharts.js +45 -0
- package/dist/dashboard/MosaicDashboardCharts.js.map +1 -0
- package/dist/dashboard/MosaicDashboardContext.d.ts +11 -0
- package/dist/dashboard/MosaicDashboardContext.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardContext.js +10 -0
- package/dist/dashboard/MosaicDashboardContext.js.map +1 -0
- package/dist/dashboard/MosaicDashboardProfiler.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardProfiler.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardProfiler.js +21 -0
- package/dist/dashboard/MosaicDashboardProfiler.js.map +1 -0
- package/dist/dashboard/MosaicDashboardSlice.d.ts +68 -0
- package/dist/dashboard/MosaicDashboardSlice.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardSlice.js +230 -0
- package/dist/dashboard/MosaicDashboardSlice.js.map +1 -0
- package/dist/dashboard/MosaicDashboardToolbar.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardToolbar.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardToolbar.js +19 -0
- package/dist/dashboard/MosaicDashboardToolbar.js.map +1 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.d.ts +8 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.d.ts.map +1 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.js +40 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.js.map +1 -0
- package/dist/editor/MosaicChartContainer.d.ts +51 -0
- package/dist/editor/MosaicChartContainer.d.ts.map +1 -0
- package/dist/editor/MosaicChartContainer.js +39 -0
- package/dist/editor/MosaicChartContainer.js.map +1 -0
- package/dist/editor/MosaicChartDisplay.d.ts +18 -0
- package/dist/editor/MosaicChartDisplay.d.ts.map +1 -0
- package/dist/editor/MosaicChartDisplay.js +21 -0
- package/dist/editor/MosaicChartDisplay.js.map +1 -0
- package/dist/editor/MosaicChartEditorActions.d.ts +20 -0
- package/dist/editor/MosaicChartEditorActions.d.ts.map +1 -0
- package/dist/editor/MosaicChartEditorActions.js +18 -0
- package/dist/editor/MosaicChartEditorActions.js.map +1 -0
- package/dist/editor/MosaicCodeMirrorEditor.d.ts +15 -0
- package/dist/editor/MosaicCodeMirrorEditor.d.ts.map +1 -0
- package/dist/editor/MosaicCodeMirrorEditor.js +26 -0
- package/dist/editor/MosaicCodeMirrorEditor.js.map +1 -0
- package/dist/editor/MosaicEditorContext.d.ts +8 -0
- package/dist/editor/MosaicEditorContext.d.ts.map +1 -0
- package/dist/editor/MosaicEditorContext.js +14 -0
- package/dist/editor/MosaicEditorContext.js.map +1 -0
- package/dist/editor/MosaicSpecEditorPanel.d.ts +20 -0
- package/dist/editor/MosaicSpecEditorPanel.d.ts.map +1 -0
- package/dist/editor/MosaicSpecEditorPanel.js +25 -0
- package/dist/editor/MosaicSpecEditorPanel.js.map +1 -0
- package/dist/editor/mosaicSchema.d.ts +20 -0
- package/dist/editor/mosaicSchema.d.ts.map +1 -0
- package/dist/editor/mosaicSchema.js +57 -0
- package/dist/editor/mosaicSchema.js.map +1 -0
- package/dist/editor/types.d.ts +72 -0
- package/dist/editor/types.d.ts.map +1 -0
- package/dist/editor/types.js +2 -0
- package/dist/editor/types.js.map +1 -0
- package/dist/editor/useMosaicChartEditor.d.ts +9 -0
- package/dist/editor/useMosaicChartEditor.d.ts.map +1 -0
- package/dist/editor/useMosaicChartEditor.js +199 -0
- package/dist/editor/useMosaicChartEditor.js.map +1 -0
- package/dist/index.d.ts +27 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/profiler/MosaicProfiler.d.ts +32 -0
- package/dist/profiler/MosaicProfiler.d.ts.map +1 -0
- package/dist/profiler/MosaicProfiler.js +57 -0
- package/dist/profiler/MosaicProfiler.js.map +1 -0
- package/dist/profiler/MosaicProfilerHeader.d.ts +7 -0
- package/dist/profiler/MosaicProfilerHeader.d.ts.map +1 -0
- package/dist/profiler/MosaicProfilerHeader.js +196 -0
- package/dist/profiler/MosaicProfilerHeader.js.map +1 -0
- package/dist/profiler/MosaicProfilerRows.d.ts +9 -0
- package/dist/profiler/MosaicProfilerRows.d.ts.map +1 -0
- package/dist/profiler/MosaicProfilerRows.js +65 -0
- package/dist/profiler/MosaicProfilerRows.js.map +1 -0
- package/dist/profiler/MosaicProfilerStatusBar.d.ts +9 -0
- package/dist/profiler/MosaicProfilerStatusBar.d.ts.map +1 -0
- package/dist/profiler/MosaicProfilerStatusBar.js +28 -0
- package/dist/profiler/MosaicProfilerStatusBar.js.map +1 -0
- package/dist/profiler/ProfilerCategoryClient.d.ts +50 -0
- package/dist/profiler/ProfilerCategoryClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerCategoryClient.js +121 -0
- package/dist/profiler/ProfilerCategoryClient.js.map +1 -0
- package/dist/profiler/ProfilerCountClient.d.ts +28 -0
- package/dist/profiler/ProfilerCountClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerCountClient.js +51 -0
- package/dist/profiler/ProfilerCountClient.js.map +1 -0
- package/dist/profiler/ProfilerHistogramClient.d.ts +69 -0
- package/dist/profiler/ProfilerHistogramClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerHistogramClient.js +179 -0
- package/dist/profiler/ProfilerHistogramClient.js.map +1 -0
- package/dist/profiler/ProfilerPageClient.d.ts +37 -0
- package/dist/profiler/ProfilerPageClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerPageClient.js +65 -0
- package/dist/profiler/ProfilerPageClient.js.map +1 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.d.ts +24 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.js +51 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.js.map +1 -0
- package/dist/profiler/createProfilerStore.d.ts +45 -0
- package/dist/profiler/createProfilerStore.d.ts.map +1 -0
- package/dist/profiler/createProfilerStore.js +120 -0
- package/dist/profiler/createProfilerStore.js.map +1 -0
- package/dist/profiler/layout.d.ts +7 -0
- package/dist/profiler/layout.d.ts.map +1 -0
- package/dist/profiler/layout.js +13 -0
- package/dist/profiler/layout.js.map +1 -0
- package/dist/profiler/profilerController.d.ts +64 -0
- package/dist/profiler/profilerController.d.ts.map +1 -0
- package/dist/profiler/profilerController.js +123 -0
- package/dist/profiler/profilerController.js.map +1 -0
- package/dist/profiler/types.d.ts +86 -0
- package/dist/profiler/types.d.ts.map +1 -0
- package/dist/profiler/types.js +2 -0
- package/dist/profiler/types.js.map +1 -0
- package/dist/profiler/useMosaicProfiler.d.ts +7 -0
- package/dist/profiler/useMosaicProfiler.d.ts.map +1 -0
- package/dist/profiler/useMosaicProfiler.js +339 -0
- package/dist/profiler/useMosaicProfiler.js.map +1 -0
- package/dist/profiler/utils.d.ts +61 -0
- package/dist/profiler/utils.d.ts.map +1 -0
- package/dist/profiler/utils.js +347 -0
- package/dist/profiler/utils.js.map +1 -0
- package/dist/tableInterop.d.ts +30 -0
- package/dist/tableInterop.d.ts.map +1 -0
- package/dist/tableInterop.js +85 -0
- package/dist/tableInterop.js.map +1 -0
- package/dist/use-mosaic.d.ts +11 -0
- package/dist/use-mosaic.d.ts.map +1 -0
- package/dist/use-mosaic.js +42 -0
- package/dist/use-mosaic.js.map +1 -0
- package/dist/useMosaicClient.d.ts +5 -4
- package/dist/useMosaicClient.d.ts.map +1 -1
- package/dist/useMosaicClient.js +13 -3
- package/dist/useMosaicClient.js.map +1 -1
- package/package.json +24 -6
package/README.md
CHANGED
|
@@ -68,10 +68,9 @@ The `useMosaicClient` hook creates a Mosaic client that automatically queries da
|
|
|
68
68
|
|
|
69
69
|
```tsx
|
|
70
70
|
import {Query, useMosaicClient} from '@sqlrooms/mosaic';
|
|
71
|
-
import {Table} from 'apache-arrow';
|
|
72
71
|
|
|
73
72
|
function MapView() {
|
|
74
|
-
const {data, isLoading, client} = useMosaicClient
|
|
73
|
+
const {data, isLoading, client} = useMosaicClient({
|
|
75
74
|
selectionName: 'brush', // Named selection for cross-filtering
|
|
76
75
|
query: (filter: any) => {
|
|
77
76
|
return Query.from('earthquakes')
|
|
@@ -89,6 +88,11 @@ function MapView() {
|
|
|
89
88
|
}
|
|
90
89
|
```
|
|
91
90
|
|
|
91
|
+
`useMosaicClient` returns an Apache Arrow table. Mosaic still uses its native
|
|
92
|
+
table runtime internally, but that detail is hidden at the hook boundary so
|
|
93
|
+
custom SQLRooms views can work with the same Arrow shape used by the DuckDB and
|
|
94
|
+
deck packages.
|
|
95
|
+
|
|
92
96
|
The hook accepts the following options:
|
|
93
97
|
|
|
94
98
|
- `id` - Optional unique identifier for this client (auto-generated if not provided)
|
|
@@ -98,6 +102,41 @@ The hook accepts the following options:
|
|
|
98
102
|
- `queryResult` - Optional callback when query results are received
|
|
99
103
|
- `enabled` - Whether to automatically connect when mosaic is ready (default: `true`)
|
|
100
104
|
|
|
105
|
+
### Mosaic Profiler Primitives
|
|
106
|
+
|
|
107
|
+
The profiler primitives let you build a Quake-style cross-filtered table with
|
|
108
|
+
per-column summaries on top of `MosaicSlice`.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import {MosaicProfiler} from '@sqlrooms/mosaic';
|
|
112
|
+
import {ScrollArea} from '@sqlrooms/ui';
|
|
113
|
+
import {useMemo} from 'react';
|
|
114
|
+
import {useRoomStore} from './store';
|
|
115
|
+
|
|
116
|
+
function EarthquakeProfiler() {
|
|
117
|
+
const mosaic = useRoomStore((state) => state.mosaic);
|
|
118
|
+
const brush = useMemo(() => mosaic.getSelection('brush'), [mosaic]);
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<MosaicProfiler tableName="earthquakes" selection={brush} pageSize={25}>
|
|
122
|
+
<div className="flex min-h-0 flex-col border">
|
|
123
|
+
<ScrollArea className="min-h-0 flex-1">
|
|
124
|
+
<MosaicProfiler.Table>
|
|
125
|
+
<MosaicProfiler.Header />
|
|
126
|
+
<MosaicProfiler.Rows />
|
|
127
|
+
</MosaicProfiler.Table>
|
|
128
|
+
</ScrollArea>
|
|
129
|
+
<MosaicProfiler.StatusBar />
|
|
130
|
+
</div>
|
|
131
|
+
</MosaicProfiler>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For the common case, prefer the compound `MosaicProfiler` API. `useMosaicProfiler`
|
|
137
|
+
is still available when you need direct access to the profiler state for custom
|
|
138
|
+
layout, sizing, or advanced composition.
|
|
139
|
+
|
|
101
140
|
### Working with Selections
|
|
102
141
|
|
|
103
142
|
Selections enable cross-filtering between multiple visualizations. You can get or create a named selection from the store:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compound component for composable Mosaic chart editing.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* <MosaicChart.Container spec={mySpec} onSpecChange={save}>
|
|
7
|
+
* <MosaicChart.Display />
|
|
8
|
+
* <MosaicChart.SpecEditor />
|
|
9
|
+
* <MosaicChart.Actions />
|
|
10
|
+
* </MosaicChart.Container>
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare const MosaicChart: {
|
|
14
|
+
readonly Container: import("react").FC<import(".").MosaicChartContainerProps>;
|
|
15
|
+
readonly Display: import("react").FC<import(".").MosaicChartDisplayProps>;
|
|
16
|
+
readonly SpecEditor: import("react").FC<import(".").MosaicSpecEditorPanelProps>;
|
|
17
|
+
readonly Actions: import("react").FC<import(".").MosaicChartEditorActionsProps>;
|
|
18
|
+
readonly CodeMirrorEditor: import("react").FC<import(".").MosaicCodeMirrorEditorProps>;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=MosaicChart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MosaicChart.d.ts","sourceRoot":"","sources":["../src/MosaicChart.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW;;;;;;CAMd,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MosaicChartContainer } from './editor/MosaicChartContainer';
|
|
2
|
+
import { MosaicChartDisplay } from './editor/MosaicChartDisplay';
|
|
3
|
+
import { MosaicSpecEditorPanel } from './editor/MosaicSpecEditorPanel';
|
|
4
|
+
import { MosaicChartEditorActions } from './editor/MosaicChartEditorActions';
|
|
5
|
+
import { MosaicCodeMirrorEditor } from './editor/MosaicCodeMirrorEditor';
|
|
6
|
+
/**
|
|
7
|
+
* Compound component for composable Mosaic chart editing.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <MosaicChart.Container spec={mySpec} onSpecChange={save}>
|
|
12
|
+
* <MosaicChart.Display />
|
|
13
|
+
* <MosaicChart.SpecEditor />
|
|
14
|
+
* <MosaicChart.Actions />
|
|
15
|
+
* </MosaicChart.Container>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export const MosaicChart = {
|
|
19
|
+
Container: MosaicChartContainer,
|
|
20
|
+
Display: MosaicChartDisplay,
|
|
21
|
+
SpecEditor: MosaicSpecEditorPanel,
|
|
22
|
+
Actions: MosaicChartEditorActions,
|
|
23
|
+
CodeMirrorEditor: MosaicCodeMirrorEditor,
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=MosaicChart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MosaicChart.js","sourceRoot":"","sources":["../src/MosaicChart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAC,kBAAkB,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAC,qBAAqB,EAAC,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAC,wBAAwB,EAAC,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAC,sBAAsB,EAAC,MAAM,iCAAiC,CAAC;AAEvE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS,EAAE,oBAAoB;IAC/B,OAAO,EAAE,kBAAkB;IAC3B,UAAU,EAAE,qBAAqB;IACjC,OAAO,EAAE,wBAAwB;IACjC,gBAAgB,EAAE,sBAAsB;CAChC,CAAC","sourcesContent":["import {MosaicChartContainer} from './editor/MosaicChartContainer';\nimport {MosaicChartDisplay} from './editor/MosaicChartDisplay';\nimport {MosaicSpecEditorPanel} from './editor/MosaicSpecEditorPanel';\nimport {MosaicChartEditorActions} from './editor/MosaicChartEditorActions';\nimport {MosaicCodeMirrorEditor} from './editor/MosaicCodeMirrorEditor';\n\n/**\n * Compound component for composable Mosaic chart editing.\n *\n * @example\n * ```tsx\n * <MosaicChart.Container spec={mySpec} onSpecChange={save}>\n * <MosaicChart.Display />\n * <MosaicChart.SpecEditor />\n * <MosaicChart.Actions />\n * </MosaicChart.Container>\n * ```\n */\nexport const MosaicChart = {\n Container: MosaicChartContainer,\n Display: MosaicChartDisplay,\n SpecEditor: MosaicSpecEditorPanel,\n Actions: MosaicChartEditorActions,\n CodeMirrorEditor: MosaicCodeMirrorEditor,\n} as const;\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compound component for building Mosaic charts from templates.
|
|
3
|
+
*
|
|
4
|
+
* Use `MosaicChartBuilder.Content` for an inline builder, or
|
|
5
|
+
* `MosaicChartBuilder.Dialog` for a dialog-wrapped version.
|
|
6
|
+
*
|
|
7
|
+
* @example Inline usage
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <MosaicChartBuilder.Content
|
|
10
|
+
* tableName="my_table"
|
|
11
|
+
* columns={columns}
|
|
12
|
+
* onCreateChart={handleCreate}
|
|
13
|
+
* />
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example Dialog usage
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <MosaicChartBuilder.Dialog
|
|
19
|
+
* open={isOpen}
|
|
20
|
+
* onOpenChange={setOpen}
|
|
21
|
+
* tableName="my_table"
|
|
22
|
+
* columns={columns}
|
|
23
|
+
* onCreateChart={handleCreate}
|
|
24
|
+
* />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare const MosaicChartBuilder: {
|
|
28
|
+
readonly Content: import("react").FC<import(".").ChartBuilderContentProps>;
|
|
29
|
+
readonly Dialog: import("react").FC<import(".").ChartBuilderDialogProps>;
|
|
30
|
+
readonly FieldSelector: import("react").FC<import(".").FieldSelectorInputProps>;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=MosaicChartBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MosaicChartBuilder.d.ts","sourceRoot":"","sources":["../src/MosaicChartBuilder.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,kBAAkB;;;;CAIrB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ChartBuilderContent } from './chart-builders/ChartBuilderContent';
|
|
2
|
+
import { ChartBuilderDialog } from './chart-builders/ChartBuilderDialog';
|
|
3
|
+
import { FieldSelectorInput } from './chart-builders/FieldSelectorInput';
|
|
4
|
+
/**
|
|
5
|
+
* Compound component for building Mosaic charts from templates.
|
|
6
|
+
*
|
|
7
|
+
* Use `MosaicChartBuilder.Content` for an inline builder, or
|
|
8
|
+
* `MosaicChartBuilder.Dialog` for a dialog-wrapped version.
|
|
9
|
+
*
|
|
10
|
+
* @example Inline usage
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <MosaicChartBuilder.Content
|
|
13
|
+
* tableName="my_table"
|
|
14
|
+
* columns={columns}
|
|
15
|
+
* onCreateChart={handleCreate}
|
|
16
|
+
* />
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @example Dialog usage
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <MosaicChartBuilder.Dialog
|
|
22
|
+
* open={isOpen}
|
|
23
|
+
* onOpenChange={setOpen}
|
|
24
|
+
* tableName="my_table"
|
|
25
|
+
* columns={columns}
|
|
26
|
+
* onCreateChart={handleCreate}
|
|
27
|
+
* />
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export const MosaicChartBuilder = {
|
|
31
|
+
Content: ChartBuilderContent,
|
|
32
|
+
Dialog: ChartBuilderDialog,
|
|
33
|
+
FieldSelector: FieldSelectorInput,
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=MosaicChartBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MosaicChartBuilder.js","sourceRoot":"","sources":["../src/MosaicChartBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAC,MAAM,sCAAsC,CAAC;AACzE,OAAO,EAAC,kBAAkB,EAAC,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAC,kBAAkB,EAAC,MAAM,qCAAqC,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,OAAO,EAAE,mBAAmB;IAC5B,MAAM,EAAE,kBAAkB;IAC1B,aAAa,EAAE,kBAAkB;CACzB,CAAC","sourcesContent":["import {ChartBuilderContent} from './chart-builders/ChartBuilderContent';\nimport {ChartBuilderDialog} from './chart-builders/ChartBuilderDialog';\nimport {FieldSelectorInput} from './chart-builders/FieldSelectorInput';\n\n/**\n * Compound component for building Mosaic charts from templates.\n *\n * Use `MosaicChartBuilder.Content` for an inline builder, or\n * `MosaicChartBuilder.Dialog` for a dialog-wrapped version.\n *\n * @example Inline usage\n * ```tsx\n * <MosaicChartBuilder.Content\n * tableName=\"my_table\"\n * columns={columns}\n * onCreateChart={handleCreate}\n * />\n * ```\n *\n * @example Dialog usage\n * ```tsx\n * <MosaicChartBuilder.Dialog\n * open={isOpen}\n * onOpenChange={setOpen}\n * tableName=\"my_table\"\n * columns={columns}\n * onCreateChart={handleCreate}\n * />\n * ```\n */\nexport const MosaicChartBuilder = {\n Content: ChartBuilderContent,\n Dialog: ChartBuilderDialog,\n FieldSelector: FieldSelectorInput,\n} as const;\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ColorScaleConfig } from '@sqlrooms/color-scales';
|
|
2
|
+
import { Selection } from '@uwdata/mosaic-core';
|
|
3
|
+
type LegendDomainValue = string | number | Date;
|
|
4
|
+
type CreateMosaicColorLegendPlotOptions = {
|
|
5
|
+
colorScale: ColorScaleConfig;
|
|
6
|
+
selection?: Selection;
|
|
7
|
+
domain?: ReadonlyArray<LegendDomainValue>;
|
|
8
|
+
title?: string;
|
|
9
|
+
width?: number;
|
|
10
|
+
tickFormat?: string;
|
|
11
|
+
};
|
|
12
|
+
export type MosaicColorLegendProps = CreateMosaicColorLegendPlotOptions & {
|
|
13
|
+
className?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function createMosaicColorLegendPlot({ colorScale, selection, domain, title, width, tickFormat, }: CreateMosaicColorLegendPlotOptions): any;
|
|
16
|
+
export declare function MosaicColorLegend({ colorScale, selection, domain, title, width, tickFormat, className, }: MosaicColorLegendProps): import("react/jsx-runtime").JSX.Element | null;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=MosaicColorLegend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MosaicColorLegend.d.ts","sourceRoot":"","sources":["../src/MosaicColorLegend.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAG7D,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAK9C,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAEhD,KAAK,kCAAkC,GAAG;IACxC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,kCAAkC,GAAG;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAuDF,wBAAgB,2BAA2B,CAAC,EAC1C,UAAU,EACV,SAAS,EACT,MAAM,EACN,KAAK,EACL,KAAW,EACX,UAAkB,GACnB,EAAE,kCAAkC,OAiDpC;AAED,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,SAAS,EACT,MAAM,EACN,KAAK,EACL,KAAK,EACL,UAAU,EACV,SAAS,GACV,EAAE,sBAAsB,kDAgDxB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { resolveColorLegendTitle } from '@sqlrooms/color-scales';
|
|
3
|
+
import { cn, getResolvedTheme, useTheme } from '@sqlrooms/ui';
|
|
4
|
+
import * as vg from '@uwdata/vgplot';
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
import { VgPlotChart } from './VgPlotChart';
|
|
7
|
+
function isExplicitNumericDomain(domain) {
|
|
8
|
+
return domain !== 'auto';
|
|
9
|
+
}
|
|
10
|
+
function resolveLegendDomain(colorScale, domain) {
|
|
11
|
+
if ((colorScale.type === 'sequential' ||
|
|
12
|
+
colorScale.type === 'diverging' ||
|
|
13
|
+
colorScale.type === 'quantize') &&
|
|
14
|
+
isExplicitNumericDomain(colorScale.domain)) {
|
|
15
|
+
return colorScale.domain;
|
|
16
|
+
}
|
|
17
|
+
return domain;
|
|
18
|
+
}
|
|
19
|
+
function getVgColorScaleType(colorScale) {
|
|
20
|
+
switch (colorScale.type) {
|
|
21
|
+
case 'sequential':
|
|
22
|
+
return 'linear';
|
|
23
|
+
case 'diverging':
|
|
24
|
+
return 'diverging';
|
|
25
|
+
case 'quantize':
|
|
26
|
+
return 'quantize';
|
|
27
|
+
case 'quantile':
|
|
28
|
+
return 'quantile';
|
|
29
|
+
case 'threshold':
|
|
30
|
+
return 'threshold';
|
|
31
|
+
case 'categorical':
|
|
32
|
+
return 'categorical';
|
|
33
|
+
default: {
|
|
34
|
+
const _exhaustive = colorScale;
|
|
35
|
+
throw new Error(`Unknown color scale type: ${_exhaustive.type}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function supportsInteractiveLegend(colorScale) {
|
|
40
|
+
return (colorScale.type === 'sequential' ||
|
|
41
|
+
colorScale.type === 'diverging' ||
|
|
42
|
+
colorScale.type === 'categorical');
|
|
43
|
+
}
|
|
44
|
+
export function createMosaicColorLegendPlot({ colorScale, selection, domain, title, width = 220, tickFormat = '.1f', }) {
|
|
45
|
+
const resolvedDomain = resolveLegendDomain(colorScale, domain);
|
|
46
|
+
const legendTitle = resolveColorLegendTitle(colorScale, title);
|
|
47
|
+
const plotAttributes = [
|
|
48
|
+
vg.colorScale(getVgColorScaleType(colorScale)),
|
|
49
|
+
vg.colorScheme(colorScale.scheme),
|
|
50
|
+
vg.colorLabel(legendTitle),
|
|
51
|
+
vg.marginTop(0),
|
|
52
|
+
vg.marginRight(0),
|
|
53
|
+
vg.marginBottom(0),
|
|
54
|
+
vg.marginLeft(0),
|
|
55
|
+
];
|
|
56
|
+
if ('clamp' in colorScale && colorScale.clamp !== undefined) {
|
|
57
|
+
plotAttributes.push(vg.colorClamp(colorScale.clamp));
|
|
58
|
+
}
|
|
59
|
+
if ('reverse' in colorScale && colorScale.reverse !== undefined) {
|
|
60
|
+
plotAttributes.push(vg.colorReverse(colorScale.reverse));
|
|
61
|
+
}
|
|
62
|
+
if (colorScale.type === 'diverging') {
|
|
63
|
+
if (Array.isArray(resolvedDomain) && resolvedDomain.length === 3) {
|
|
64
|
+
plotAttributes.push(vg.colorDomain([resolvedDomain[0], resolvedDomain[2]]), vg.colorPivot(resolvedDomain[1]));
|
|
65
|
+
}
|
|
66
|
+
else if (Array.isArray(resolvedDomain) && resolvedDomain.length === 2) {
|
|
67
|
+
plotAttributes.push(vg.colorDomain(resolvedDomain));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (colorScale.type === 'threshold') {
|
|
71
|
+
plotAttributes.push(vg.colorDomain(colorScale.thresholds));
|
|
72
|
+
}
|
|
73
|
+
else if (resolvedDomain) {
|
|
74
|
+
plotAttributes.push(vg.colorDomain(resolvedDomain));
|
|
75
|
+
}
|
|
76
|
+
if (colorScale.type === 'quantize' || colorScale.type === 'quantile') {
|
|
77
|
+
plotAttributes.push(vg.colorN(colorScale.bins ?? 5));
|
|
78
|
+
}
|
|
79
|
+
const backingPlot = vg.plot(...plotAttributes);
|
|
80
|
+
return vg.colorLegend({
|
|
81
|
+
for: backingPlot,
|
|
82
|
+
as: supportsInteractiveLegend(colorScale) ? selection : undefined,
|
|
83
|
+
field: colorScale.field,
|
|
84
|
+
width,
|
|
85
|
+
tickFormat,
|
|
86
|
+
label: legendTitle,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export function MosaicColorLegend({ colorScale, selection, domain, title, width, tickFormat, className, }) {
|
|
90
|
+
const { theme } = useTheme();
|
|
91
|
+
const resolvedTheme = getResolvedTheme(theme);
|
|
92
|
+
const legendSpecKey = JSON.stringify({
|
|
93
|
+
colorScale,
|
|
94
|
+
domain,
|
|
95
|
+
title,
|
|
96
|
+
width,
|
|
97
|
+
tickFormat,
|
|
98
|
+
});
|
|
99
|
+
// eslint-disable-next-line react-hooks/preserve-manual-memoization
|
|
100
|
+
const plot = useMemo(() => createMosaicColorLegendPlot({
|
|
101
|
+
colorScale,
|
|
102
|
+
selection,
|
|
103
|
+
domain,
|
|
104
|
+
title,
|
|
105
|
+
width,
|
|
106
|
+
tickFormat,
|
|
107
|
+
}),
|
|
108
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- deep-equal via serialized key instead of object refs
|
|
109
|
+
[legendSpecKey, selection]);
|
|
110
|
+
if (!plot) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return (_jsx("div", { className: cn('pointer-events-auto rounded-md border px-3 py-2 shadow-lg backdrop-blur-sm', 'border-slate-200 bg-white/95 text-slate-900', 'dark:border-slate-700 dark:bg-[#1f1d1b]/90 dark:text-slate-100', '[&_svg]:block [&_svg]:overflow-visible', '[&_svg_line]:stroke-current [&_svg_path]:stroke-current [&_svg_text]:fill-current', resolvedTheme === 'dark' &&
|
|
114
|
+
'[&_svg_.domain]:stroke-slate-500 [&_svg_line]:stroke-slate-500', resolvedTheme === 'light' &&
|
|
115
|
+
'[&_svg_.domain]:stroke-slate-400 [&_svg_line]:stroke-slate-400', className), children: _jsx(VgPlotChart, { plot: plot }) }));
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=MosaicColorLegend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MosaicColorLegend.js","sourceRoot":"","sources":["../src/MosaicColorLegend.tsx"],"names":[],"mappings":"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","sourcesContent":["import type {ColorScaleConfig} from '@sqlrooms/color-scales';\nimport {resolveColorLegendTitle} from '@sqlrooms/color-scales';\nimport {cn, getResolvedTheme, useTheme} from '@sqlrooms/ui';\nimport {Selection} from '@uwdata/mosaic-core';\nimport * as vg from '@uwdata/vgplot';\nimport {useMemo} from 'react';\nimport {VgPlotChart} from './VgPlotChart';\n\ntype LegendDomainValue = string | number | Date;\n\ntype CreateMosaicColorLegendPlotOptions = {\n colorScale: ColorScaleConfig;\n selection?: Selection;\n domain?: ReadonlyArray<LegendDomainValue>;\n title?: string;\n width?: number;\n tickFormat?: string;\n};\n\nexport type MosaicColorLegendProps = CreateMosaicColorLegendPlotOptions & {\n className?: string;\n};\n\nfunction isExplicitNumericDomain(\n domain: 'auto' | [number, number] | [number, number, number],\n): domain is [number, number] | [number, number, number] {\n return domain !== 'auto';\n}\n\nfunction resolveLegendDomain(\n colorScale: ColorScaleConfig,\n domain?: ReadonlyArray<LegendDomainValue>,\n) {\n if (\n (colorScale.type === 'sequential' ||\n colorScale.type === 'diverging' ||\n colorScale.type === 'quantize') &&\n isExplicitNumericDomain(colorScale.domain)\n ) {\n return colorScale.domain;\n }\n\n return domain;\n}\n\nfunction getVgColorScaleType(colorScale: ColorScaleConfig) {\n switch (colorScale.type) {\n case 'sequential':\n return 'linear';\n case 'diverging':\n return 'diverging';\n case 'quantize':\n return 'quantize';\n case 'quantile':\n return 'quantile';\n case 'threshold':\n return 'threshold';\n case 'categorical':\n return 'categorical';\n default: {\n const _exhaustive: never = colorScale;\n throw new Error(\n `Unknown color scale type: ${(_exhaustive as ColorScaleConfig).type}`,\n );\n }\n }\n}\n\nfunction supportsInteractiveLegend(colorScale: ColorScaleConfig) {\n return (\n colorScale.type === 'sequential' ||\n colorScale.type === 'diverging' ||\n colorScale.type === 'categorical'\n );\n}\n\nexport function createMosaicColorLegendPlot({\n colorScale,\n selection,\n domain,\n title,\n width = 220,\n tickFormat = '.1f',\n}: CreateMosaicColorLegendPlotOptions) {\n const resolvedDomain = resolveLegendDomain(colorScale, domain);\n const legendTitle = resolveColorLegendTitle(colorScale, title);\n const plotAttributes: Array<(plot: any) => void> = [\n vg.colorScale(getVgColorScaleType(colorScale)),\n vg.colorScheme(colorScale.scheme),\n vg.colorLabel(legendTitle),\n vg.marginTop(0),\n vg.marginRight(0),\n vg.marginBottom(0),\n vg.marginLeft(0),\n ];\n\n if ('clamp' in colorScale && colorScale.clamp !== undefined) {\n plotAttributes.push(vg.colorClamp(colorScale.clamp));\n }\n\n if ('reverse' in colorScale && colorScale.reverse !== undefined) {\n plotAttributes.push(vg.colorReverse(colorScale.reverse));\n }\n\n if (colorScale.type === 'diverging') {\n if (Array.isArray(resolvedDomain) && resolvedDomain.length === 3) {\n plotAttributes.push(\n vg.colorDomain([resolvedDomain[0], resolvedDomain[2]]),\n vg.colorPivot(resolvedDomain[1]),\n );\n } else if (Array.isArray(resolvedDomain) && resolvedDomain.length === 2) {\n plotAttributes.push(vg.colorDomain(resolvedDomain));\n }\n } else if (colorScale.type === 'threshold') {\n plotAttributes.push(vg.colorDomain(colorScale.thresholds));\n } else if (resolvedDomain) {\n plotAttributes.push(vg.colorDomain(resolvedDomain));\n }\n\n if (colorScale.type === 'quantize' || colorScale.type === 'quantile') {\n plotAttributes.push(vg.colorN(colorScale.bins ?? 5));\n }\n\n const backingPlot = vg.plot(...plotAttributes);\n return vg.colorLegend({\n for: backingPlot,\n as: supportsInteractiveLegend(colorScale) ? selection : undefined,\n field: colorScale.field,\n width,\n tickFormat,\n label: legendTitle,\n });\n}\n\nexport function MosaicColorLegend({\n colorScale,\n selection,\n domain,\n title,\n width,\n tickFormat,\n className,\n}: MosaicColorLegendProps) {\n const {theme} = useTheme();\n const resolvedTheme = getResolvedTheme(theme);\n const legendSpecKey = JSON.stringify({\n colorScale,\n domain,\n title,\n width,\n tickFormat,\n });\n\n // eslint-disable-next-line react-hooks/preserve-manual-memoization\n const plot = useMemo(\n () =>\n createMosaicColorLegendPlot({\n colorScale,\n selection,\n domain,\n title,\n width,\n tickFormat,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- deep-equal via serialized key instead of object refs\n [legendSpecKey, selection],\n );\n\n if (!plot) {\n return null;\n }\n\n return (\n <div\n className={cn(\n 'pointer-events-auto rounded-md border px-3 py-2 shadow-lg backdrop-blur-sm',\n 'border-slate-200 bg-white/95 text-slate-900',\n 'dark:border-slate-700 dark:bg-[#1f1d1b]/90 dark:text-slate-100',\n '[&_svg]:block [&_svg]:overflow-visible',\n '[&_svg_line]:stroke-current [&_svg_path]:stroke-current [&_svg_text]:fill-current',\n resolvedTheme === 'dark' &&\n '[&_svg_.domain]:stroke-slate-500 [&_svg_line]:stroke-slate-500',\n resolvedTheme === 'light' &&\n '[&_svg_.domain]:stroke-slate-400 [&_svg_line]:stroke-slate-400',\n className,\n )}\n >\n <VgPlotChart plot={plot} />\n </div>\n );\n}\n"]}
|
package/dist/MosaicSlice.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { DuckDbSliceState } from '@sqlrooms/duckdb';
|
|
1
|
+
import { type DuckDbSliceState } from '@sqlrooms/duckdb';
|
|
2
2
|
import { type SliceFunctions } from '@sqlrooms/room-store';
|
|
3
3
|
import { Connector, Coordinator, makeClient, Selection } from '@uwdata/mosaic-core';
|
|
4
4
|
import { Query } from '@uwdata/mosaic-sql';
|
|
5
|
+
import type { Table as ArrowTable } from 'apache-arrow';
|
|
5
6
|
import { z } from 'zod';
|
|
6
7
|
export declare const MosaicSliceConfig: z.ZodObject<{}, z.core.$strip>;
|
|
7
8
|
export type MosaicSliceConfig = z.infer<typeof MosaicSliceConfig>;
|
|
8
|
-
export type MosaicClientOptions
|
|
9
|
+
export type MosaicClientOptions = {
|
|
9
10
|
/** Unique identifier for this client */
|
|
10
11
|
id?: string;
|
|
11
12
|
/** Selection name for cross-filtering (will create if doesn't exist) */
|
|
@@ -15,16 +16,16 @@ export type MosaicClientOptions<T = unknown> = {
|
|
|
15
16
|
/** Query builder function that receives the current filter */
|
|
16
17
|
query: (filter: unknown) => ReturnType<typeof Query.from>;
|
|
17
18
|
/** Callback when query results are received */
|
|
18
|
-
queryResult?: (result:
|
|
19
|
+
queryResult?: (result: ArrowTable) => void;
|
|
19
20
|
};
|
|
20
|
-
export type TrackedClient
|
|
21
|
+
export type TrackedClient = {
|
|
21
22
|
id: string;
|
|
22
23
|
client: ReturnType<typeof makeClient>;
|
|
23
24
|
createdAt: number;
|
|
24
25
|
isLoading: boolean;
|
|
25
|
-
data:
|
|
26
|
+
data: unknown | null;
|
|
26
27
|
selection?: Selection;
|
|
27
|
-
queryResultCallback?: (result:
|
|
28
|
+
queryResultCallback?: (result: ArrowTable) => void;
|
|
28
29
|
};
|
|
29
30
|
export type MosaicSliceState = {
|
|
30
31
|
mosaic: SliceFunctions & {
|
|
@@ -32,7 +33,7 @@ export type MosaicSliceState = {
|
|
|
32
33
|
status: 'idle' | 'loading';
|
|
33
34
|
} | {
|
|
34
35
|
status: 'ready';
|
|
35
|
-
connector
|
|
36
|
+
connector?: Connector;
|
|
36
37
|
coordinator: Coordinator;
|
|
37
38
|
} | {
|
|
38
39
|
status: 'error';
|
|
@@ -40,18 +41,18 @@ export type MosaicSliceState = {
|
|
|
40
41
|
};
|
|
41
42
|
config: MosaicSliceConfig;
|
|
42
43
|
/** Record of registered clients by id */
|
|
43
|
-
clients: Record<string, TrackedClient
|
|
44
|
+
clients: Record<string, TrackedClient>;
|
|
44
45
|
/** Named selections for cross-filtering (e.g., 'brush', 'hover') */
|
|
45
46
|
selections: Record<string, Selection>;
|
|
46
47
|
initialize: () => Promise<void>;
|
|
47
48
|
/** Get or create a named selection for cross-filtering */
|
|
48
49
|
getSelection: (name: string, type?: 'crossfilter' | 'single' | 'union') => Selection;
|
|
49
50
|
/** Create a mosaic client and register it */
|
|
50
|
-
createClient:
|
|
51
|
+
createClient: (options: MosaicClientOptions) => string;
|
|
51
52
|
/** Ensure a client exists with given options (idempotent - creates or updates as needed) */
|
|
52
|
-
ensureClient:
|
|
53
|
+
ensureClient: (options: MosaicClientOptions & {
|
|
53
54
|
id: string;
|
|
54
|
-
onQueryResult?: (result:
|
|
55
|
+
onQueryResult?: (result: ArrowTable) => void;
|
|
55
56
|
}) => void;
|
|
56
57
|
/** Disconnect and remove a client by id */
|
|
57
58
|
destroyClient: (id: string) => void;
|
|
@@ -60,9 +61,11 @@ export type MosaicSliceState = {
|
|
|
60
61
|
};
|
|
61
62
|
};
|
|
62
63
|
export declare function createDefaultMosaicConfig(props?: Partial<MosaicSliceConfig>): MosaicSliceConfig;
|
|
63
|
-
export
|
|
64
|
+
export type CreateMosaicSliceProps = {
|
|
64
65
|
config?: Partial<MosaicSliceConfig>;
|
|
65
|
-
|
|
66
|
+
coordinator?: Coordinator;
|
|
67
|
+
};
|
|
68
|
+
export declare function createMosaicSlice(props?: CreateMosaicSliceProps): import("zustand").StateCreator<MosaicSliceState>;
|
|
66
69
|
export type DuckDbSliceStateWithMosaic = DuckDbSliceState & MosaicSliceState;
|
|
67
70
|
export declare function useStoreWithMosaic<T>(selector: (state: DuckDbSliceStateWithMosaic) => T): T;
|
|
68
71
|
//# sourceMappingURL=MosaicSlice.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MosaicSlice.d.ts","sourceRoot":"","sources":["../src/MosaicSlice.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"MosaicSlice.d.ts","sourceRoot":"","sources":["../src/MosaicSlice.ts"],"names":[],"mappings":"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"}
|
package/dist/MosaicSlice.js
CHANGED
|
@@ -1,40 +1,45 @@
|
|
|
1
1
|
import { createId } from '@paralleldrive/cuid2';
|
|
2
|
-
import { isWasmDuckDbConnector } from '@sqlrooms/duckdb';
|
|
2
|
+
import { isWasmDuckDbConnector, } from '@sqlrooms/duckdb';
|
|
3
3
|
import { createSlice, useBaseRoomStore, } from '@sqlrooms/room-store';
|
|
4
4
|
import { coordinator, makeClient, Selection, wasmConnector, } from '@uwdata/mosaic-core';
|
|
5
5
|
import { produce } from 'immer';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
+
import { createMosaicTableFromArrowTable, toArrowClientResult, } from './tableInterop';
|
|
7
8
|
export const MosaicSliceConfig = z.object({});
|
|
8
9
|
export function createDefaultMosaicConfig(props) {
|
|
9
10
|
return {
|
|
10
11
|
...props,
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
|
-
export function createMosaicSlice(props) {
|
|
14
|
+
export function createMosaicSlice(props = {}) {
|
|
14
15
|
return createSlice((set, get, store) => ({
|
|
15
16
|
mosaic: {
|
|
16
17
|
config: createDefaultMosaicConfig(props?.config),
|
|
17
|
-
connection: {
|
|
18
|
-
status: 'idle',
|
|
19
|
-
connector: undefined,
|
|
20
|
-
},
|
|
18
|
+
connection: { status: 'idle' },
|
|
21
19
|
clients: {},
|
|
22
20
|
selections: {},
|
|
23
21
|
async initialize() {
|
|
24
22
|
let mosaicConnector;
|
|
23
|
+
let resolvedCoordinator;
|
|
25
24
|
set((state) => produce(state, (draft) => {
|
|
26
25
|
draft.mosaic.connection = { status: 'loading' };
|
|
27
26
|
}));
|
|
28
27
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
if (props.coordinator) {
|
|
29
|
+
resolvedCoordinator = props.coordinator;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const dbConnector = await get().db.getConnector();
|
|
33
|
+
resolvedCoordinator = coordinator();
|
|
34
|
+
mosaicConnector = isWasmDuckDbConnector(dbConnector)
|
|
35
|
+
? await wasmConnector({
|
|
36
|
+
// @ts-expect-error - We install a different version of duckdb-wasm
|
|
37
|
+
duckDb: dbConnector.getDb(),
|
|
38
|
+
connection: dbConnector.getConnection(),
|
|
39
|
+
})
|
|
40
|
+
: createDuckDbMosaicConnector(dbConnector);
|
|
41
|
+
resolvedCoordinator.databaseConnector(mosaicConnector);
|
|
32
42
|
}
|
|
33
|
-
mosaicConnector = await coordinator().databaseConnector(wasmConnector({
|
|
34
|
-
// @ts-expect-error - We install a different version of duckdb-wasm
|
|
35
|
-
duckDb: dbConnector.getDb(),
|
|
36
|
-
connection: dbConnector.getConnection(),
|
|
37
|
-
}));
|
|
38
43
|
}
|
|
39
44
|
catch (error) {
|
|
40
45
|
set((state) => produce(state, (draft) => {
|
|
@@ -42,15 +47,13 @@ export function createMosaicSlice(props) {
|
|
|
42
47
|
}));
|
|
43
48
|
throw error;
|
|
44
49
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}));
|
|
53
|
-
}
|
|
50
|
+
set((state) => produce(state, (draft) => {
|
|
51
|
+
draft.mosaic.connection = {
|
|
52
|
+
status: 'ready',
|
|
53
|
+
connector: mosaicConnector,
|
|
54
|
+
coordinator: resolvedCoordinator,
|
|
55
|
+
};
|
|
56
|
+
}));
|
|
54
57
|
},
|
|
55
58
|
async destroy() {
|
|
56
59
|
get().mosaic.destroyAllClients();
|
|
@@ -82,16 +85,15 @@ export function createMosaicSlice(props) {
|
|
|
82
85
|
: undefined);
|
|
83
86
|
// Wrap queryResult to update store state AND call external callback
|
|
84
87
|
const wrappedQueryResult = (data) => {
|
|
85
|
-
const typedData = data;
|
|
86
88
|
set((state) => produce(state, (draft) => {
|
|
87
89
|
const tracked = draft.mosaic.clients[id];
|
|
88
90
|
if (tracked) {
|
|
89
|
-
tracked.data =
|
|
91
|
+
tracked.data = data;
|
|
90
92
|
tracked.isLoading = false;
|
|
91
93
|
}
|
|
92
94
|
}));
|
|
93
95
|
// Call external callback if provided
|
|
94
|
-
options.queryResult?.(
|
|
96
|
+
options.queryResult?.(toArrowClientResult(data));
|
|
95
97
|
};
|
|
96
98
|
const client = makeClient({
|
|
97
99
|
coordinator: connection.coordinator,
|
|
@@ -108,7 +110,7 @@ export function createMosaicSlice(props) {
|
|
|
108
110
|
data: null,
|
|
109
111
|
selection,
|
|
110
112
|
queryResultCallback: options.queryResult
|
|
111
|
-
? (result) => options.queryResult(result)
|
|
113
|
+
? (result) => options.queryResult(toArrowClientResult(result))
|
|
112
114
|
: undefined,
|
|
113
115
|
};
|
|
114
116
|
}));
|
|
@@ -138,18 +140,18 @@ export function createMosaicSlice(props) {
|
|
|
138
140
|
}
|
|
139
141
|
// Create new client with wrapped queryResult that calls both store update and external callback
|
|
140
142
|
const wrappedQueryResult = (data) => {
|
|
141
|
-
const typedData = data;
|
|
142
143
|
set((state) => produce(state, (draft) => {
|
|
143
144
|
const tracked = draft.mosaic.clients[options.id];
|
|
144
145
|
if (tracked) {
|
|
145
|
-
tracked.data =
|
|
146
|
+
tracked.data = data;
|
|
146
147
|
tracked.isLoading = false;
|
|
147
148
|
}
|
|
148
149
|
}));
|
|
150
|
+
const arrowData = toArrowClientResult(data);
|
|
149
151
|
// Call external callback if provided
|
|
150
|
-
options.onQueryResult?.(
|
|
152
|
+
options.onQueryResult?.(arrowData);
|
|
151
153
|
// Also call original queryResult if provided
|
|
152
|
-
options.queryResult?.(
|
|
154
|
+
options.queryResult?.(arrowData);
|
|
153
155
|
};
|
|
154
156
|
const client = makeClient({
|
|
155
157
|
coordinator: connection.coordinator,
|
|
@@ -165,7 +167,9 @@ export function createMosaicSlice(props) {
|
|
|
165
167
|
isLoading: true,
|
|
166
168
|
data: null,
|
|
167
169
|
selection,
|
|
168
|
-
queryResultCallback: options.onQueryResult
|
|
170
|
+
queryResultCallback: options.onQueryResult
|
|
171
|
+
? (result) => options.onQueryResult(toArrowClientResult(result))
|
|
172
|
+
: undefined,
|
|
169
173
|
};
|
|
170
174
|
}));
|
|
171
175
|
},
|
|
@@ -198,4 +202,35 @@ export function createMosaicSlice(props) {
|
|
|
198
202
|
export function useStoreWithMosaic(selector) {
|
|
199
203
|
return useBaseRoomStore((state) => selector(state));
|
|
200
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Adapts a {@link DuckDbConnector} to the Mosaic {@link Connector} interface.
|
|
207
|
+
*
|
|
208
|
+
* For `'arrow'` queries the Apache Arrow table returned by the connector is
|
|
209
|
+
* converted via {@link createMosaicTableFromArrowTable} into a flechette
|
|
210
|
+
* `Table`, which is the shape Mosaic consumers expect (with `.toColumns()`).
|
|
211
|
+
* For `'json'` queries, rows are materialized with {@link Array.from} which
|
|
212
|
+
* may have performance/memory implications for very large result sets.
|
|
213
|
+
* The `as any` casts on the return type are an intentional adapter trade-off
|
|
214
|
+
* to satisfy the polymorphic {@link Connector['query']} signature.
|
|
215
|
+
*/
|
|
216
|
+
function createDuckDbMosaicConnector(connector) {
|
|
217
|
+
return {
|
|
218
|
+
query: (async (query) => {
|
|
219
|
+
const queryType = query.type ?? 'arrow';
|
|
220
|
+
if (queryType === 'exec') {
|
|
221
|
+
await connector.execute(query.sql);
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
if (queryType === 'json') {
|
|
225
|
+
const rows = await connector.queryJson(query.sql);
|
|
226
|
+
return Array.from(rows);
|
|
227
|
+
}
|
|
228
|
+
if (queryType === 'arrow') {
|
|
229
|
+
const arrowTable = await connector.query(query.sql);
|
|
230
|
+
return createMosaicTableFromArrowTable(arrowTable);
|
|
231
|
+
}
|
|
232
|
+
throw new Error(`Unsupported Mosaic query type "${queryType}".`);
|
|
233
|
+
}),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
201
236
|
//# sourceMappingURL=MosaicSlice.js.map
|