@sqlrooms/mosaic 0.29.0-rc.1 → 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.
Files changed (202) hide show
  1. package/README.md +41 -2
  2. package/dist/MosaicChart.d.ts +20 -0
  3. package/dist/MosaicChart.d.ts.map +1 -0
  4. package/dist/MosaicChart.js +25 -0
  5. package/dist/MosaicChart.js.map +1 -0
  6. package/dist/MosaicChartBuilder.d.ts +32 -0
  7. package/dist/MosaicChartBuilder.d.ts.map +1 -0
  8. package/dist/MosaicChartBuilder.js +35 -0
  9. package/dist/MosaicChartBuilder.js.map +1 -0
  10. package/dist/MosaicColorLegend.d.ts +18 -0
  11. package/dist/MosaicColorLegend.d.ts.map +1 -0
  12. package/dist/MosaicColorLegend.js +117 -0
  13. package/dist/MosaicColorLegend.js.map +1 -0
  14. package/dist/MosaicSlice.d.ts +16 -13
  15. package/dist/MosaicSlice.d.ts.map +1 -1
  16. package/dist/MosaicSlice.js +67 -32
  17. package/dist/MosaicSlice.js.map +1 -1
  18. package/dist/VgPlotChart.d.ts +8 -0
  19. package/dist/VgPlotChart.d.ts.map +1 -1
  20. package/dist/VgPlotChart.js +26 -6
  21. package/dist/VgPlotChart.js.map +1 -1
  22. package/dist/chart-builders/ChartBuilderContent.d.ts +26 -0
  23. package/dist/chart-builders/ChartBuilderContent.d.ts.map +1 -0
  24. package/dist/chart-builders/ChartBuilderContent.js +59 -0
  25. package/dist/chart-builders/ChartBuilderContent.js.map +1 -0
  26. package/dist/chart-builders/ChartBuilderContext.d.ts +11 -0
  27. package/dist/chart-builders/ChartBuilderContext.d.ts.map +1 -0
  28. package/dist/chart-builders/ChartBuilderContext.js +10 -0
  29. package/dist/chart-builders/ChartBuilderContext.js.map +1 -0
  30. package/dist/chart-builders/ChartBuilderDialog.d.ts +23 -0
  31. package/dist/chart-builders/ChartBuilderDialog.d.ts.map +1 -0
  32. package/dist/chart-builders/ChartBuilderDialog.js +15 -0
  33. package/dist/chart-builders/ChartBuilderDialog.js.map +1 -0
  34. package/dist/chart-builders/FieldSelectorInput.d.ts +13 -0
  35. package/dist/chart-builders/FieldSelectorInput.d.ts.map +1 -0
  36. package/dist/chart-builders/FieldSelectorInput.js +19 -0
  37. package/dist/chart-builders/FieldSelectorInput.js.map +1 -0
  38. package/dist/chart-builders/builders.d.ts +7 -0
  39. package/dist/chart-builders/builders.d.ts.map +1 -0
  40. package/dist/chart-builders/builders.js +280 -0
  41. package/dist/chart-builders/builders.js.map +1 -0
  42. package/dist/chart-builders/chartSpecTitle.d.ts +7 -0
  43. package/dist/chart-builders/chartSpecTitle.d.ts.map +1 -0
  44. package/dist/chart-builders/chartSpecTitle.js +10 -0
  45. package/dist/chart-builders/chartSpecTitle.js.map +1 -0
  46. package/dist/chart-builders/createMosaicChartTool.d.ts +45 -0
  47. package/dist/chart-builders/createMosaicChartTool.d.ts.map +1 -0
  48. package/dist/chart-builders/createMosaicChartTool.js +109 -0
  49. package/dist/chart-builders/createMosaicChartTool.js.map +1 -0
  50. package/dist/chart-builders/describeChartSpecs.d.ts +7 -0
  51. package/dist/chart-builders/describeChartSpecs.d.ts.map +1 -0
  52. package/dist/chart-builders/describeChartSpecs.js +38 -0
  53. package/dist/chart-builders/describeChartSpecs.js.map +1 -0
  54. package/dist/chart-builders/types.d.ts +40 -0
  55. package/dist/chart-builders/types.d.ts.map +1 -0
  56. package/dist/chart-builders/types.js +2 -0
  57. package/dist/chart-builders/types.js.map +1 -0
  58. package/dist/dashboard/MosaicDashboard.d.ts +20 -0
  59. package/dist/dashboard/MosaicDashboard.d.ts.map +1 -0
  60. package/dist/dashboard/MosaicDashboard.js +68 -0
  61. package/dist/dashboard/MosaicDashboard.js.map +1 -0
  62. package/dist/dashboard/MosaicDashboardChartPanel.d.ts +3 -0
  63. package/dist/dashboard/MosaicDashboardChartPanel.d.ts.map +1 -0
  64. package/dist/dashboard/MosaicDashboardChartPanel.js +49 -0
  65. package/dist/dashboard/MosaicDashboardChartPanel.js.map +1 -0
  66. package/dist/dashboard/MosaicDashboardCharts.d.ts +3 -0
  67. package/dist/dashboard/MosaicDashboardCharts.d.ts.map +1 -0
  68. package/dist/dashboard/MosaicDashboardCharts.js +45 -0
  69. package/dist/dashboard/MosaicDashboardCharts.js.map +1 -0
  70. package/dist/dashboard/MosaicDashboardContext.d.ts +11 -0
  71. package/dist/dashboard/MosaicDashboardContext.d.ts.map +1 -0
  72. package/dist/dashboard/MosaicDashboardContext.js +10 -0
  73. package/dist/dashboard/MosaicDashboardContext.js.map +1 -0
  74. package/dist/dashboard/MosaicDashboardProfiler.d.ts +3 -0
  75. package/dist/dashboard/MosaicDashboardProfiler.d.ts.map +1 -0
  76. package/dist/dashboard/MosaicDashboardProfiler.js +21 -0
  77. package/dist/dashboard/MosaicDashboardProfiler.js.map +1 -0
  78. package/dist/dashboard/MosaicDashboardSlice.d.ts +68 -0
  79. package/dist/dashboard/MosaicDashboardSlice.d.ts.map +1 -0
  80. package/dist/dashboard/MosaicDashboardSlice.js +230 -0
  81. package/dist/dashboard/MosaicDashboardSlice.js.map +1 -0
  82. package/dist/dashboard/MosaicDashboardToolbar.d.ts +3 -0
  83. package/dist/dashboard/MosaicDashboardToolbar.d.ts.map +1 -0
  84. package/dist/dashboard/MosaicDashboardToolbar.js +19 -0
  85. package/dist/dashboard/MosaicDashboardToolbar.js.map +1 -0
  86. package/dist/dashboard/VgPlotSpecPopoverEditor.d.ts +8 -0
  87. package/dist/dashboard/VgPlotSpecPopoverEditor.d.ts.map +1 -0
  88. package/dist/dashboard/VgPlotSpecPopoverEditor.js +40 -0
  89. package/dist/dashboard/VgPlotSpecPopoverEditor.js.map +1 -0
  90. package/dist/editor/MosaicChartContainer.d.ts +51 -0
  91. package/dist/editor/MosaicChartContainer.d.ts.map +1 -0
  92. package/dist/editor/MosaicChartContainer.js +39 -0
  93. package/dist/editor/MosaicChartContainer.js.map +1 -0
  94. package/dist/editor/MosaicChartDisplay.d.ts +18 -0
  95. package/dist/editor/MosaicChartDisplay.d.ts.map +1 -0
  96. package/dist/editor/MosaicChartDisplay.js +21 -0
  97. package/dist/editor/MosaicChartDisplay.js.map +1 -0
  98. package/dist/editor/MosaicChartEditorActions.d.ts +20 -0
  99. package/dist/editor/MosaicChartEditorActions.d.ts.map +1 -0
  100. package/dist/editor/MosaicChartEditorActions.js +18 -0
  101. package/dist/editor/MosaicChartEditorActions.js.map +1 -0
  102. package/dist/editor/MosaicCodeMirrorEditor.d.ts +15 -0
  103. package/dist/editor/MosaicCodeMirrorEditor.d.ts.map +1 -0
  104. package/dist/editor/MosaicCodeMirrorEditor.js +26 -0
  105. package/dist/editor/MosaicCodeMirrorEditor.js.map +1 -0
  106. package/dist/editor/MosaicEditorContext.d.ts +8 -0
  107. package/dist/editor/MosaicEditorContext.d.ts.map +1 -0
  108. package/dist/editor/MosaicEditorContext.js +14 -0
  109. package/dist/editor/MosaicEditorContext.js.map +1 -0
  110. package/dist/editor/MosaicSpecEditorPanel.d.ts +20 -0
  111. package/dist/editor/MosaicSpecEditorPanel.d.ts.map +1 -0
  112. package/dist/editor/MosaicSpecEditorPanel.js +25 -0
  113. package/dist/editor/MosaicSpecEditorPanel.js.map +1 -0
  114. package/dist/editor/mosaicSchema.d.ts +20 -0
  115. package/dist/editor/mosaicSchema.d.ts.map +1 -0
  116. package/dist/editor/mosaicSchema.js +57 -0
  117. package/dist/editor/mosaicSchema.js.map +1 -0
  118. package/dist/editor/types.d.ts +72 -0
  119. package/dist/editor/types.d.ts.map +1 -0
  120. package/dist/editor/types.js +2 -0
  121. package/dist/editor/types.js.map +1 -0
  122. package/dist/editor/useMosaicChartEditor.d.ts +9 -0
  123. package/dist/editor/useMosaicChartEditor.d.ts.map +1 -0
  124. package/dist/editor/useMosaicChartEditor.js +199 -0
  125. package/dist/editor/useMosaicChartEditor.js.map +1 -0
  126. package/dist/index.d.ts +27 -2
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +18 -1
  129. package/dist/index.js.map +1 -1
  130. package/dist/profiler/MosaicProfiler.d.ts +32 -0
  131. package/dist/profiler/MosaicProfiler.d.ts.map +1 -0
  132. package/dist/profiler/MosaicProfiler.js +57 -0
  133. package/dist/profiler/MosaicProfiler.js.map +1 -0
  134. package/dist/profiler/MosaicProfilerHeader.d.ts +7 -0
  135. package/dist/profiler/MosaicProfilerHeader.d.ts.map +1 -0
  136. package/dist/profiler/MosaicProfilerHeader.js +196 -0
  137. package/dist/profiler/MosaicProfilerHeader.js.map +1 -0
  138. package/dist/profiler/MosaicProfilerRows.d.ts +9 -0
  139. package/dist/profiler/MosaicProfilerRows.d.ts.map +1 -0
  140. package/dist/profiler/MosaicProfilerRows.js +65 -0
  141. package/dist/profiler/MosaicProfilerRows.js.map +1 -0
  142. package/dist/profiler/MosaicProfilerStatusBar.d.ts +9 -0
  143. package/dist/profiler/MosaicProfilerStatusBar.d.ts.map +1 -0
  144. package/dist/profiler/MosaicProfilerStatusBar.js +28 -0
  145. package/dist/profiler/MosaicProfilerStatusBar.js.map +1 -0
  146. package/dist/profiler/ProfilerCategoryClient.d.ts +50 -0
  147. package/dist/profiler/ProfilerCategoryClient.d.ts.map +1 -0
  148. package/dist/profiler/ProfilerCategoryClient.js +121 -0
  149. package/dist/profiler/ProfilerCategoryClient.js.map +1 -0
  150. package/dist/profiler/ProfilerCountClient.d.ts +28 -0
  151. package/dist/profiler/ProfilerCountClient.d.ts.map +1 -0
  152. package/dist/profiler/ProfilerCountClient.js +51 -0
  153. package/dist/profiler/ProfilerCountClient.js.map +1 -0
  154. package/dist/profiler/ProfilerHistogramClient.d.ts +69 -0
  155. package/dist/profiler/ProfilerHistogramClient.d.ts.map +1 -0
  156. package/dist/profiler/ProfilerHistogramClient.js +179 -0
  157. package/dist/profiler/ProfilerHistogramClient.js.map +1 -0
  158. package/dist/profiler/ProfilerPageClient.d.ts +37 -0
  159. package/dist/profiler/ProfilerPageClient.d.ts.map +1 -0
  160. package/dist/profiler/ProfilerPageClient.js +65 -0
  161. package/dist/profiler/ProfilerPageClient.js.map +1 -0
  162. package/dist/profiler/ProfilerUnsupportedSummaryClient.d.ts +24 -0
  163. package/dist/profiler/ProfilerUnsupportedSummaryClient.d.ts.map +1 -0
  164. package/dist/profiler/ProfilerUnsupportedSummaryClient.js +51 -0
  165. package/dist/profiler/ProfilerUnsupportedSummaryClient.js.map +1 -0
  166. package/dist/profiler/createProfilerStore.d.ts +45 -0
  167. package/dist/profiler/createProfilerStore.d.ts.map +1 -0
  168. package/dist/profiler/createProfilerStore.js +120 -0
  169. package/dist/profiler/createProfilerStore.js.map +1 -0
  170. package/dist/profiler/layout.d.ts +7 -0
  171. package/dist/profiler/layout.d.ts.map +1 -0
  172. package/dist/profiler/layout.js +13 -0
  173. package/dist/profiler/layout.js.map +1 -0
  174. package/dist/profiler/profilerController.d.ts +64 -0
  175. package/dist/profiler/profilerController.d.ts.map +1 -0
  176. package/dist/profiler/profilerController.js +123 -0
  177. package/dist/profiler/profilerController.js.map +1 -0
  178. package/dist/profiler/types.d.ts +86 -0
  179. package/dist/profiler/types.d.ts.map +1 -0
  180. package/dist/profiler/types.js +2 -0
  181. package/dist/profiler/types.js.map +1 -0
  182. package/dist/profiler/useMosaicProfiler.d.ts +7 -0
  183. package/dist/profiler/useMosaicProfiler.d.ts.map +1 -0
  184. package/dist/profiler/useMosaicProfiler.js +339 -0
  185. package/dist/profiler/useMosaicProfiler.js.map +1 -0
  186. package/dist/profiler/utils.d.ts +61 -0
  187. package/dist/profiler/utils.d.ts.map +1 -0
  188. package/dist/profiler/utils.js +347 -0
  189. package/dist/profiler/utils.js.map +1 -0
  190. package/dist/tableInterop.d.ts +30 -0
  191. package/dist/tableInterop.d.ts.map +1 -0
  192. package/dist/tableInterop.js +85 -0
  193. package/dist/tableInterop.js.map +1 -0
  194. package/dist/use-mosaic.d.ts +11 -0
  195. package/dist/use-mosaic.d.ts.map +1 -0
  196. package/dist/use-mosaic.js +42 -0
  197. package/dist/use-mosaic.js.map +1 -0
  198. package/dist/useMosaicClient.d.ts +5 -4
  199. package/dist/useMosaicClient.d.ts.map +1 -1
  200. package/dist/useMosaicClient.js +13 -3
  201. package/dist/useMosaicClient.js.map +1 -1
  202. 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<Table>({
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"]}
@@ -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<T = unknown> = {
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: T) => void;
19
+ queryResult?: (result: ArrowTable) => void;
19
20
  };
20
- export type TrackedClient<T = unknown> = {
21
+ export type TrackedClient = {
21
22
  id: string;
22
23
  client: ReturnType<typeof makeClient>;
23
24
  createdAt: number;
24
25
  isLoading: boolean;
25
- data: T | null;
26
+ data: unknown | null;
26
27
  selection?: Selection;
27
- queryResultCallback?: (result: T) => void;
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: 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<unknown>>;
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: <T>(options: MosaicClientOptions<T>) => string;
51
+ createClient: (options: MosaicClientOptions) => string;
51
52
  /** Ensure a client exists with given options (idempotent - creates or updates as needed) */
52
- ensureClient: <T>(options: MosaicClientOptions<T> & {
53
+ ensureClient: (options: MosaicClientOptions & {
53
54
  id: string;
54
- onQueryResult?: (result: T) => void;
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 declare function createMosaicSlice(props?: {
64
+ export type CreateMosaicSliceProps = {
64
65
  config?: Partial<MosaicSliceConfig>;
65
- }): import("zustand").StateCreator<MosaicSliceState>;
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":"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"}
1
+ {"version":3,"file":"MosaicSlice.d.ts","sourceRoot":"","sources":["../src/MosaicSlice.ts"],"names":[],"mappings":"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"}
@@ -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
- const dbConnector = await get().db.getConnector();
30
- if (!isWasmDuckDbConnector(dbConnector)) {
31
- throw new Error('Only WasmDuckDbConnector is currently supported');
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
- finally {
46
- set((state) => produce(state, (draft) => {
47
- draft.mosaic.connection = {
48
- status: 'ready',
49
- connector: mosaicConnector,
50
- coordinator: coordinator(),
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 = typedData;
91
+ tracked.data = data;
90
92
  tracked.isLoading = false;
91
93
  }
92
94
  }));
93
95
  // Call external callback if provided
94
- options.queryResult?.(typedData);
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 = typedData;
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?.(typedData);
152
+ options.onQueryResult?.(arrowData);
151
153
  // Also call original queryResult if provided
152
- options.queryResult?.(typedData);
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