@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
@@ -0,0 +1,230 @@
1
+ import { createId } from '@paralleldrive/cuid2';
2
+ import { LayoutMosaicSubNode as LayoutMosaicSubNodeSchema } from '@sqlrooms/layout-config';
3
+ import { createSlice, useBaseRoomStore, } from '@sqlrooms/room-store';
4
+ import { produce } from 'immer';
5
+ import { z } from 'zod';
6
+ export const DEFAULT_MOSAIC_DASHBOARD_CHART_VGPLOT = JSON.stringify({
7
+ $schema: 'https://idl.uw.edu/mosaic/schema/latest.json',
8
+ meta: {
9
+ title: 'New Chart',
10
+ description: 'Use the chart builder or edit the spec directly to visualize DuckDB tables.',
11
+ },
12
+ data: {
13
+ sample: {
14
+ type: 'table',
15
+ query: `
16
+ SELECT * FROM (
17
+ VALUES
18
+ ('A', 12),
19
+ ('B', 26),
20
+ ('C', 18),
21
+ ('D', 9)
22
+ ) AS t(category, amount)
23
+ `,
24
+ },
25
+ },
26
+ plot: [
27
+ {
28
+ mark: 'barY',
29
+ data: { from: 'sample' },
30
+ x: 'category',
31
+ y: 'amount',
32
+ fill: 'category',
33
+ },
34
+ ],
35
+ xLabel: 'Category',
36
+ yLabel: 'Amount',
37
+ width: 560,
38
+ height: 320,
39
+ }, null, 2);
40
+ export const DEFAULT_MOSAIC_DASHBOARD_CHART_SPEC = JSON.parse(DEFAULT_MOSAIC_DASHBOARD_CHART_VGPLOT);
41
+ export const MosaicDashboardChartConfig = z.object({
42
+ id: z.string(),
43
+ title: z.string().default('Chart'),
44
+ vgplot: z
45
+ .object({})
46
+ .passthrough()
47
+ .default(DEFAULT_MOSAIC_DASHBOARD_CHART_SPEC),
48
+ });
49
+ export const MosaicDashboardEntry = z.object({
50
+ id: z.string(),
51
+ title: z.string().default('Dashboard'),
52
+ selectedTable: z.string().optional(),
53
+ charts: z.array(MosaicDashboardChartConfig).default([]),
54
+ layout: LayoutMosaicSubNodeSchema.nullable().default(null),
55
+ updatedAt: z.number().default(0),
56
+ });
57
+ export const MosaicDashboardSliceConfig = z.object({
58
+ dashboardsById: z.record(z.string(), MosaicDashboardEntry).default({}),
59
+ });
60
+ function appendPanelToLayout(layout, panelId) {
61
+ if (!layout) {
62
+ return panelId;
63
+ }
64
+ return {
65
+ type: 'split',
66
+ direction: 'row',
67
+ children: [layout, panelId],
68
+ };
69
+ }
70
+ function removePanelFromLayout(layout, panelId) {
71
+ if (!layout)
72
+ return null;
73
+ if (typeof layout === 'string') {
74
+ return layout === panelId ? null : layout;
75
+ }
76
+ const nextChildren = layout.children
77
+ .map((child) => removePanelFromLayout(child, panelId))
78
+ .filter((child) => child !== null);
79
+ if (nextChildren.length === 0)
80
+ return null;
81
+ if (nextChildren.length === 1) {
82
+ const onlyChild = nextChildren[0];
83
+ return onlyChild ?? null;
84
+ }
85
+ return {
86
+ ...layout,
87
+ children: nextChildren,
88
+ };
89
+ }
90
+ function collectPanelIds(layout, panelIds = new Set()) {
91
+ if (!layout)
92
+ return panelIds;
93
+ if (typeof layout === 'string') {
94
+ panelIds.add(layout);
95
+ return panelIds;
96
+ }
97
+ for (const child of layout.children) {
98
+ collectPanelIds(child, panelIds);
99
+ }
100
+ return panelIds;
101
+ }
102
+ function ensureLayoutContainsPanels(layout, panelIds) {
103
+ let nextLayout = layout;
104
+ const existing = collectPanelIds(layout);
105
+ for (const panelId of panelIds) {
106
+ if (!existing.has(panelId)) {
107
+ nextLayout = appendPanelToLayout(nextLayout, panelId);
108
+ existing.add(panelId);
109
+ }
110
+ }
111
+ return nextLayout;
112
+ }
113
+ export function getMosaicDashboardPanelId(dashboardId, chartId) {
114
+ return `dashboard:${dashboardId}:chart:${chartId}`;
115
+ }
116
+ export function getMosaicDashboardMosaicId(dashboardId) {
117
+ return `dashboard:${dashboardId}:mosaic`;
118
+ }
119
+ export function getMosaicDashboardSelectionName(dashboardId) {
120
+ return `dashboard:${dashboardId}:brush`;
121
+ }
122
+ export function parseMosaicDashboardChartId(dashboardId, panelId) {
123
+ const prefix = `dashboard:${dashboardId}:chart:`;
124
+ return panelId.startsWith(prefix) ? panelId.slice(prefix.length) : undefined;
125
+ }
126
+ export function createDefaultMosaicDashboardConfig(props) {
127
+ return MosaicDashboardSliceConfig.parse({
128
+ dashboardsById: {},
129
+ ...props,
130
+ });
131
+ }
132
+ export function createMosaicDashboardSlice(props = {}) {
133
+ return createSlice((set, get) => ({
134
+ mosaicDashboard: {
135
+ config: createDefaultMosaicDashboardConfig(props.config),
136
+ createDashboard(title) {
137
+ const dashboardId = createId();
138
+ get().mosaicDashboard.ensureDashboard(dashboardId, title);
139
+ return dashboardId;
140
+ },
141
+ ensureDashboard(dashboardId, title) {
142
+ set((state) => produce(state, (draft) => {
143
+ const existing = draft.mosaicDashboard.config.dashboardsById[dashboardId];
144
+ if (existing) {
145
+ if (title && existing.title !== title) {
146
+ existing.title = title;
147
+ existing.updatedAt = Date.now();
148
+ }
149
+ return;
150
+ }
151
+ draft.mosaicDashboard.config.dashboardsById[dashboardId] = {
152
+ id: dashboardId,
153
+ title: title ?? 'Dashboard',
154
+ selectedTable: undefined,
155
+ charts: [],
156
+ layout: null,
157
+ updatedAt: Date.now(),
158
+ };
159
+ }));
160
+ },
161
+ removeDashboard(dashboardId) {
162
+ set((state) => produce(state, (draft) => {
163
+ delete draft.mosaicDashboard.config.dashboardsById[dashboardId];
164
+ }));
165
+ },
166
+ getDashboard(dashboardId) {
167
+ return get().mosaicDashboard.config.dashboardsById[dashboardId];
168
+ },
169
+ setSelectedTable(dashboardId, tableName) {
170
+ get().mosaicDashboard.ensureDashboard(dashboardId);
171
+ set((state) => produce(state, (draft) => {
172
+ const dashboard = draft.mosaicDashboard.config.dashboardsById[dashboardId];
173
+ if (!dashboard)
174
+ return;
175
+ dashboard.selectedTable = tableName;
176
+ dashboard.updatedAt = Date.now();
177
+ }));
178
+ },
179
+ addChart(dashboardId, chart) {
180
+ get().mosaicDashboard.ensureDashboard(dashboardId);
181
+ set((state) => produce(state, (draft) => {
182
+ const dashboard = draft.mosaicDashboard.config.dashboardsById[dashboardId];
183
+ if (!dashboard)
184
+ return;
185
+ dashboard.charts.push(chart);
186
+ dashboard.layout = appendPanelToLayout(dashboard.layout, getMosaicDashboardPanelId(dashboardId, chart.id));
187
+ dashboard.updatedAt = Date.now();
188
+ }));
189
+ return chart.id;
190
+ },
191
+ updateChart(dashboardId, chartId, patch) {
192
+ set((state) => produce(state, (draft) => {
193
+ const dashboard = draft.mosaicDashboard.config.dashboardsById[dashboardId];
194
+ if (!dashboard)
195
+ return;
196
+ const chart = dashboard.charts.find((item) => item.id === chartId);
197
+ if (!chart)
198
+ return;
199
+ Object.assign(chart, patch);
200
+ dashboard.updatedAt = Date.now();
201
+ }));
202
+ },
203
+ removeChart(dashboardId, chartId) {
204
+ set((state) => produce(state, (draft) => {
205
+ const dashboard = draft.mosaicDashboard.config.dashboardsById[dashboardId];
206
+ if (!dashboard)
207
+ return;
208
+ dashboard.charts = dashboard.charts.filter((chart) => chart.id !== chartId);
209
+ dashboard.layout = removePanelFromLayout(dashboard.layout, getMosaicDashboardPanelId(dashboardId, chartId));
210
+ dashboard.updatedAt = Date.now();
211
+ }));
212
+ },
213
+ setLayout(dashboardId, layout) {
214
+ get().mosaicDashboard.ensureDashboard(dashboardId);
215
+ set((state) => produce(state, (draft) => {
216
+ const dashboard = draft.mosaicDashboard.config.dashboardsById[dashboardId];
217
+ if (!dashboard)
218
+ return;
219
+ const chartPanelIds = dashboard.charts.map((chart) => getMosaicDashboardPanelId(dashboardId, chart.id));
220
+ dashboard.layout = ensureLayoutContainsPanels(layout, chartPanelIds);
221
+ dashboard.updatedAt = Date.now();
222
+ }));
223
+ },
224
+ },
225
+ }));
226
+ }
227
+ export function useStoreWithMosaicDashboard(selector) {
228
+ return useBaseRoomStore((state) => selector(state));
229
+ }
230
+ //# sourceMappingURL=MosaicDashboardSlice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicDashboardSlice.js","sourceRoot":"","sources":["../../src/dashboard/MosaicDashboardSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {createId} from '@paralleldrive/cuid2';\nimport {DbSliceState} from '@sqlrooms/db';\nimport {type DuckDbSliceState} from '@sqlrooms/duckdb';\nimport type {LayoutMosaicSubNode} from '@sqlrooms/layout-config';\nimport {LayoutMosaicSubNode as LayoutMosaicSubNodeSchema} from '@sqlrooms/layout-config';\nimport {LayoutSliceState} from '@sqlrooms/layout';\nimport {\n BaseRoomStoreState,\n createSlice,\n SliceFunctions,\n useBaseRoomStore,\n} from '@sqlrooms/room-store';\nimport {produce} from 'immer';\nimport {z} from 'zod';\nimport {type MosaicSliceState} from '../MosaicSlice';\n\nexport const DEFAULT_MOSAIC_DASHBOARD_CHART_VGPLOT = JSON.stringify(\n {\n $schema: 'https://idl.uw.edu/mosaic/schema/latest.json',\n meta: {\n title: 'New Chart',\n description:\n 'Use the chart builder or edit the spec directly to visualize DuckDB tables.',\n },\n data: {\n sample: {\n type: 'table',\n query: `\n SELECT * FROM (\n VALUES\n ('A', 12),\n ('B', 26),\n ('C', 18),\n ('D', 9)\n ) AS t(category, amount)\n `,\n },\n },\n plot: [\n {\n mark: 'barY',\n data: {from: 'sample'},\n x: 'category',\n y: 'amount',\n fill: 'category',\n },\n ],\n xLabel: 'Category',\n yLabel: 'Amount',\n width: 560,\n height: 320,\n },\n null,\n 2,\n);\n\nexport const DEFAULT_MOSAIC_DASHBOARD_CHART_SPEC = JSON.parse(\n DEFAULT_MOSAIC_DASHBOARD_CHART_VGPLOT,\n) as Record<string, unknown>;\n\nexport const MosaicDashboardChartConfig = z.object({\n id: z.string(),\n title: z.string().default('Chart'),\n vgplot: z\n .object({})\n .passthrough()\n .default(DEFAULT_MOSAIC_DASHBOARD_CHART_SPEC),\n});\nexport type MosaicDashboardChartConfig = z.infer<\n typeof MosaicDashboardChartConfig\n>;\n\nexport const MosaicDashboardEntry = z.object({\n id: z.string(),\n title: z.string().default('Dashboard'),\n selectedTable: z.string().optional(),\n charts: z.array(MosaicDashboardChartConfig).default([]),\n layout: LayoutMosaicSubNodeSchema.nullable().default(null),\n updatedAt: z.number().default(0),\n});\nexport type MosaicDashboardEntry = z.infer<typeof MosaicDashboardEntry>;\n\nexport const MosaicDashboardSliceConfig = z.object({\n dashboardsById: z.record(z.string(), MosaicDashboardEntry).default({}),\n});\nexport type MosaicDashboardSliceConfig = z.infer<\n typeof MosaicDashboardSliceConfig\n>;\n\nexport type MosaicDashboardSliceState = {\n mosaicDashboard: SliceFunctions & {\n config: MosaicDashboardSliceConfig;\n createDashboard: (title?: string) => string;\n ensureDashboard: (dashboardId: string, title?: string) => void;\n removeDashboard: (dashboardId: string) => void;\n getDashboard: (dashboardId: string) => MosaicDashboardEntry | undefined;\n setSelectedTable: (dashboardId: string, tableName: string) => void;\n addChart: (\n dashboardId: string,\n chart: MosaicDashboardChartConfig,\n ) => MosaicDashboardChartConfig['id'];\n updateChart: (\n dashboardId: string,\n chartId: string,\n patch: Partial<Pick<MosaicDashboardChartConfig, 'title' | 'vgplot'>>,\n ) => void;\n removeChart: (dashboardId: string, chartId: string) => void;\n setLayout: (\n dashboardId: string,\n layout: LayoutMosaicSubNode | null,\n ) => void;\n };\n};\n\nexport type MosaicDashboardStoreState = BaseRoomStoreState &\n DbSliceState &\n DuckDbSliceState &\n LayoutSliceState &\n MosaicSliceState &\n MosaicDashboardSliceState;\n\nfunction appendPanelToLayout(\n layout: LayoutMosaicSubNode | null,\n panelId: string,\n): LayoutMosaicSubNode {\n if (!layout) {\n return panelId;\n }\n return {\n type: 'split',\n direction: 'row',\n children: [layout, panelId],\n };\n}\n\nfunction removePanelFromLayout(\n layout: LayoutMosaicSubNode | null,\n panelId: string,\n): LayoutMosaicSubNode | null {\n if (!layout) return null;\n if (typeof layout === 'string') {\n return layout === panelId ? null : layout;\n }\n\n const nextChildren = layout.children\n .map((child: LayoutMosaicSubNode) => removePanelFromLayout(child, panelId))\n .filter((child): child is LayoutMosaicSubNode => child !== null);\n\n if (nextChildren.length === 0) return null;\n if (nextChildren.length === 1) {\n const onlyChild = nextChildren[0];\n return onlyChild ?? null;\n }\n\n return {\n ...layout,\n children: nextChildren,\n };\n}\n\nfunction collectPanelIds(\n layout: LayoutMosaicSubNode | null,\n panelIds = new Set<string>(),\n) {\n if (!layout) return panelIds;\n if (typeof layout === 'string') {\n panelIds.add(layout);\n return panelIds;\n }\n for (const child of layout.children) {\n collectPanelIds(child, panelIds);\n }\n return panelIds;\n}\n\nfunction ensureLayoutContainsPanels(\n layout: LayoutMosaicSubNode | null,\n panelIds: string[],\n): LayoutMosaicSubNode | null {\n let nextLayout = layout;\n const existing = collectPanelIds(layout);\n\n for (const panelId of panelIds) {\n if (!existing.has(panelId)) {\n nextLayout = appendPanelToLayout(nextLayout, panelId);\n existing.add(panelId);\n }\n }\n\n return nextLayout;\n}\n\nexport function getMosaicDashboardPanelId(\n dashboardId: string,\n chartId: string,\n): string {\n return `dashboard:${dashboardId}:chart:${chartId}`;\n}\n\nexport function getMosaicDashboardMosaicId(dashboardId: string): string {\n return `dashboard:${dashboardId}:mosaic`;\n}\n\nexport function getMosaicDashboardSelectionName(dashboardId: string): string {\n return `dashboard:${dashboardId}:brush`;\n}\n\nexport function parseMosaicDashboardChartId(\n dashboardId: string,\n panelId: string,\n): string | undefined {\n const prefix = `dashboard:${dashboardId}:chart:`;\n return panelId.startsWith(prefix) ? panelId.slice(prefix.length) : undefined;\n}\n\nexport function createDefaultMosaicDashboardConfig(\n props?: Partial<MosaicDashboardSliceConfig>,\n): MosaicDashboardSliceConfig {\n return MosaicDashboardSliceConfig.parse({\n dashboardsById: {},\n ...props,\n });\n}\n\nexport function createMosaicDashboardSlice(\n props: {config?: Partial<MosaicDashboardSliceConfig>} = {},\n) {\n return createSlice<MosaicDashboardSliceState, MosaicDashboardStoreState>(\n (set, get) => ({\n mosaicDashboard: {\n config: createDefaultMosaicDashboardConfig(props.config),\n\n createDashboard(title) {\n const dashboardId = createId();\n get().mosaicDashboard.ensureDashboard(dashboardId, title);\n return dashboardId;\n },\n\n ensureDashboard(dashboardId, title) {\n set((state) =>\n produce(state, (draft) => {\n const existing =\n draft.mosaicDashboard.config.dashboardsById[dashboardId];\n if (existing) {\n if (title && existing.title !== title) {\n existing.title = title;\n existing.updatedAt = Date.now();\n }\n return;\n }\n draft.mosaicDashboard.config.dashboardsById[dashboardId] = {\n id: dashboardId,\n title: title ?? 'Dashboard',\n selectedTable: undefined,\n charts: [],\n layout: null,\n updatedAt: Date.now(),\n };\n }),\n );\n },\n\n removeDashboard(dashboardId) {\n set((state) =>\n produce(state, (draft) => {\n delete draft.mosaicDashboard.config.dashboardsById[dashboardId];\n }),\n );\n },\n\n getDashboard(dashboardId) {\n return get().mosaicDashboard.config.dashboardsById[dashboardId];\n },\n\n setSelectedTable(dashboardId, tableName) {\n get().mosaicDashboard.ensureDashboard(dashboardId);\n set((state) =>\n produce(state, (draft) => {\n const dashboard =\n draft.mosaicDashboard.config.dashboardsById[dashboardId];\n if (!dashboard) return;\n dashboard.selectedTable = tableName;\n dashboard.updatedAt = Date.now();\n }),\n );\n },\n\n addChart(dashboardId, chart) {\n get().mosaicDashboard.ensureDashboard(dashboardId);\n set((state) =>\n produce(state, (draft) => {\n const dashboard =\n draft.mosaicDashboard.config.dashboardsById[dashboardId];\n if (!dashboard) return;\n\n dashboard.charts.push(chart);\n dashboard.layout = appendPanelToLayout(\n dashboard.layout,\n getMosaicDashboardPanelId(dashboardId, chart.id),\n );\n dashboard.updatedAt = Date.now();\n }),\n );\n return chart.id;\n },\n\n updateChart(dashboardId, chartId, patch) {\n set((state) =>\n produce(state, (draft) => {\n const dashboard =\n draft.mosaicDashboard.config.dashboardsById[dashboardId];\n if (!dashboard) return;\n\n const chart = dashboard.charts.find(\n (item) => item.id === chartId,\n );\n if (!chart) return;\n\n Object.assign(chart, patch);\n dashboard.updatedAt = Date.now();\n }),\n );\n },\n\n removeChart(dashboardId, chartId) {\n set((state) =>\n produce(state, (draft) => {\n const dashboard =\n draft.mosaicDashboard.config.dashboardsById[dashboardId];\n if (!dashboard) return;\n\n dashboard.charts = dashboard.charts.filter(\n (chart) => chart.id !== chartId,\n );\n dashboard.layout = removePanelFromLayout(\n dashboard.layout,\n getMosaicDashboardPanelId(dashboardId, chartId),\n );\n dashboard.updatedAt = Date.now();\n }),\n );\n },\n\n setLayout(dashboardId, layout) {\n get().mosaicDashboard.ensureDashboard(dashboardId);\n set((state) =>\n produce(state, (draft) => {\n const dashboard =\n draft.mosaicDashboard.config.dashboardsById[dashboardId];\n if (!dashboard) return;\n\n const chartPanelIds = dashboard.charts.map((chart) =>\n getMosaicDashboardPanelId(dashboardId, chart.id),\n );\n\n dashboard.layout = ensureLayoutContainsPanels(\n layout,\n chartPanelIds,\n );\n dashboard.updatedAt = Date.now();\n }),\n );\n },\n },\n }),\n );\n}\n\nexport function useStoreWithMosaicDashboard<T>(\n selector: (state: MosaicDashboardStoreState) => T,\n): T {\n return useBaseRoomStore<BaseRoomStoreState, T>((state) =>\n selector(state as unknown as MosaicDashboardStoreState),\n );\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare const MosaicDashboardToolbar: React.FC;
3
+ //# sourceMappingURL=MosaicDashboardToolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicDashboardToolbar.d.ts","sourceRoot":"","sources":["../../src/dashboard/MosaicDashboardToolbar.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0B,MAAM,OAAO,CAAC;AAI/C,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EA2E1C,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Popover, PopoverContent, PopoverTrigger, } from '@sqlrooms/ui';
3
+ import { Check, ChevronsUpDown, Plus } from 'lucide-react';
4
+ import { useMemo, useState } from 'react';
5
+ import { useMosaicDashboardContext } from './MosaicDashboardContext';
6
+ import { useStoreWithMosaicDashboard } from './MosaicDashboardSlice';
7
+ export const MosaicDashboardToolbar = () => {
8
+ const { dashboardId, canCreateChart, openBuilder } = useMosaicDashboardContext();
9
+ const dashboard = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.config.dashboardsById[dashboardId]);
10
+ const setSelectedTable = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.setSelectedTable);
11
+ const tables = useStoreWithMosaicDashboard((state) => state.db.tables);
12
+ const tablesWithColumns = useMemo(() => tables.filter((table) => table.columns && table.columns.length > 0), [tables]);
13
+ const [tablePickerOpen, setTablePickerOpen] = useState(false);
14
+ return (_jsxs("div", { className: "flex items-center justify-between border-b px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "text-sm font-medium", children: dashboard?.title || 'Dashboard' }), _jsxs(Popover, { open: tablePickerOpen, onOpenChange: setTablePickerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", role: "combobox", "aria-expanded": tablePickerOpen, className: "w-[200px] justify-between", children: [_jsx("span", { className: "truncate", children: dashboard?.selectedTable || 'Select table…' }), _jsx(ChevronsUpDown, { className: "ml-1 h-3.5 w-3.5 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-[220px] p-0", align: "start", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: "Search tables\u2026" }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: "No tables found." }), _jsx(CommandGroup, { children: tablesWithColumns.map((table) => (_jsxs(CommandItem, { value: table.tableName, onSelect: (value) => {
15
+ setSelectedTable(dashboardId, value);
16
+ setTablePickerOpen(false);
17
+ }, children: [_jsx(Check, { className: `mr-2 h-3.5 w-3.5 ${dashboard?.selectedTable === table.tableName ? 'opacity-100' : 'opacity-0'}` }), table.tableName] }, table.tableName))) })] })] }) })] })] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: openBuilder, disabled: !canCreateChart, children: [_jsx(Plus, { className: "mr-1 h-4 w-4" }), "Add Chart"] })] }));
18
+ };
19
+ //# sourceMappingURL=MosaicDashboardToolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicDashboardToolbar.js","sourceRoot":"","sources":["../../src/dashboard/MosaicDashboardToolbar.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Button,\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@sqlrooms/ui';\nimport {Check, ChevronsUpDown, Plus} from 'lucide-react';\nimport React, {useMemo, useState} from 'react';\nimport {useMosaicDashboardContext} from './MosaicDashboardContext';\nimport {useStoreWithMosaicDashboard} from './MosaicDashboardSlice';\n\nexport const MosaicDashboardToolbar: React.FC = () => {\n const {dashboardId, canCreateChart, openBuilder} =\n useMosaicDashboardContext();\n const dashboard = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.config.dashboardsById[dashboardId],\n );\n const setSelectedTable = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.setSelectedTable,\n );\n const tables = useStoreWithMosaicDashboard((state) => state.db.tables);\n const tablesWithColumns = useMemo(\n () => tables.filter((table) => table.columns && table.columns.length > 0),\n [tables],\n );\n const [tablePickerOpen, setTablePickerOpen] = useState(false);\n\n return (\n <div className=\"flex items-center justify-between border-b px-3 py-2\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"text-sm font-medium\">\n {dashboard?.title || 'Dashboard'}\n </h3>\n <Popover open={tablePickerOpen} onOpenChange={setTablePickerOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n size=\"sm\"\n role=\"combobox\"\n aria-expanded={tablePickerOpen}\n className=\"w-[200px] justify-between\"\n >\n <span className=\"truncate\">\n {dashboard?.selectedTable || 'Select table…'}\n </span>\n <ChevronsUpDown className=\"ml-1 h-3.5 w-3.5 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[220px] p-0\" align=\"start\">\n <Command>\n <CommandInput placeholder=\"Search tables…\" />\n <CommandList>\n <CommandEmpty>No tables found.</CommandEmpty>\n <CommandGroup>\n {tablesWithColumns.map((table) => (\n <CommandItem\n key={table.tableName}\n value={table.tableName}\n onSelect={(value) => {\n setSelectedTable(dashboardId, value);\n setTablePickerOpen(false);\n }}\n >\n <Check\n className={`mr-2 h-3.5 w-3.5 ${dashboard?.selectedTable === table.tableName ? 'opacity-100' : 'opacity-0'}`}\n />\n {table.tableName}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={openBuilder}\n disabled={!canCreateChart}\n >\n <Plus className=\"mr-1 h-4 w-4\" />\n Add Chart\n </Button>\n </div>\n );\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface VgPlotSpecPopoverEditorProps {
3
+ value: Record<string, unknown>;
4
+ onApply: (value: Record<string, unknown>) => void;
5
+ }
6
+ export declare const VgPlotSpecPopoverEditor: React.FC<VgPlotSpecPopoverEditorProps>;
7
+ export {};
8
+ //# sourceMappingURL=VgPlotSpecPopoverEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VgPlotSpecPopoverEditor.d.ts","sourceRoot":"","sources":["../../src/dashboard/VgPlotSpecPopoverEditor.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,UAAU,4BAA4B;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,uBAAuB,EAAE,KAAK,CAAC,EAAE,CAC5C,4BAA4B,CAkF7B,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Popover, PopoverContent, PopoverTrigger } from '@sqlrooms/ui';
3
+ import { PencilIcon } from 'lucide-react';
4
+ import { useCallback, useState } from 'react';
5
+ import { MosaicCodeMirrorEditor } from '../editor/MosaicCodeMirrorEditor';
6
+ export const VgPlotSpecPopoverEditor = ({ value, onApply }) => {
7
+ const [open, setOpen] = useState(false);
8
+ const [draft, setDraft] = useState(() => JSON.stringify(value, null, 2));
9
+ const handleOpenChange = useCallback((nextOpen) => {
10
+ setOpen(nextOpen);
11
+ if (nextOpen) {
12
+ setDraft(JSON.stringify(value, null, 2));
13
+ }
14
+ }, [value]);
15
+ const handleApply = useCallback(() => {
16
+ try {
17
+ const parsed = JSON.parse(draft);
18
+ onApply(parsed);
19
+ setOpen(false);
20
+ }
21
+ catch {
22
+ // Invalid JSON — keep the editor open.
23
+ }
24
+ }, [draft, onApply]);
25
+ const serializedValue = JSON.stringify(value, null, 2);
26
+ const isDirty = draft !== serializedValue;
27
+ let isValidJson = false;
28
+ try {
29
+ JSON.parse(draft);
30
+ isValidJson = true;
31
+ }
32
+ catch {
33
+ // ignore
34
+ }
35
+ return (_jsxs(Popover, { open: open, onOpenChange: handleOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", title: "Edit spec", children: _jsx(PencilIcon, { className: "h-3.5 w-3.5" }) }) }), _jsx(PopoverContent, { side: "bottom", align: "end", className: "w-[500px] p-0", onInteractOutside: (event) => {
36
+ if (isDirty)
37
+ event.preventDefault();
38
+ }, children: _jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "h-72 overflow-hidden", children: _jsx(MosaicCodeMirrorEditor, { value: draft, onChange: (nextValue) => setDraft(nextValue ?? ''), className: "h-full", enableSchemaValidation: true }) }), _jsxs("div", { className: "flex items-center justify-end gap-2 border-t p-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setOpen(false), children: "Cancel" }), _jsx(Button, { size: "sm", disabled: !isDirty || !isValidJson, onClick: handleApply, children: "Apply" })] })] }) })] }));
39
+ };
40
+ //# sourceMappingURL=VgPlotSpecPopoverEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VgPlotSpecPopoverEditor.js","sourceRoot":"","sources":["../../src/dashboard/VgPlotSpecPopoverEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Button, Popover, PopoverContent, PopoverTrigger} from '@sqlrooms/ui';\nimport {PencilIcon} from 'lucide-react';\nimport React, {useCallback, useState} from 'react';\nimport {MosaicCodeMirrorEditor} from '../editor/MosaicCodeMirrorEditor';\n\ninterface VgPlotSpecPopoverEditorProps {\n value: Record<string, unknown>;\n onApply: (value: Record<string, unknown>) => void;\n}\n\nexport const VgPlotSpecPopoverEditor: React.FC<\n VgPlotSpecPopoverEditorProps\n> = ({value, onApply}) => {\n const [open, setOpen] = useState(false);\n const [draft, setDraft] = useState(() => JSON.stringify(value, null, 2));\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean) => {\n setOpen(nextOpen);\n if (nextOpen) {\n setDraft(JSON.stringify(value, null, 2));\n }\n },\n [value],\n );\n\n const handleApply = useCallback(() => {\n try {\n const parsed = JSON.parse(draft);\n onApply(parsed as Record<string, unknown>);\n setOpen(false);\n } catch {\n // Invalid JSON — keep the editor open.\n }\n }, [draft, onApply]);\n\n const serializedValue = JSON.stringify(value, null, 2);\n const isDirty = draft !== serializedValue;\n let isValidJson = false;\n try {\n JSON.parse(draft);\n isValidJson = true;\n } catch {\n // ignore\n }\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n title=\"Edit spec\"\n >\n <PencilIcon className=\"h-3.5 w-3.5\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent\n side=\"bottom\"\n align=\"end\"\n className=\"w-[500px] p-0\"\n onInteractOutside={(event) => {\n if (isDirty) event.preventDefault();\n }}\n >\n <div className=\"flex flex-col\">\n <div className=\"h-72 overflow-hidden\">\n <MosaicCodeMirrorEditor\n value={draft}\n onChange={(nextValue: string | undefined) =>\n setDraft(nextValue ?? '')\n }\n className=\"h-full\"\n enableSchemaValidation\n />\n </div>\n <div className=\"flex items-center justify-end gap-2 border-t p-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button\n size=\"sm\"\n disabled={!isDirty || !isValidJson}\n onClick={handleApply}\n >\n Apply\n </Button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n"]}
@@ -0,0 +1,51 @@
1
+ import { Param } from '@uwdata/mosaic-core';
2
+ import { Spec } from '@uwdata/mosaic-spec';
3
+ import React from 'react';
4
+ import { OnMosaicSpecChange } from './types';
5
+ export interface MosaicChartContainerProps {
6
+ /**
7
+ * Initial Mosaic specification
8
+ */
9
+ spec: Spec | string;
10
+ /**
11
+ * Pre-defined params/selections for shared cross-filtering
12
+ */
13
+ params?: Map<string, Param<any>>;
14
+ /**
15
+ * Whether editing is enabled
16
+ * @default true
17
+ */
18
+ editable?: boolean;
19
+ /**
20
+ * Callback when spec changes are applied
21
+ */
22
+ onSpecChange?: OnMosaicSpecChange;
23
+ /**
24
+ * Child components (Chart, SpecEditor, Actions)
25
+ */
26
+ children: React.ReactNode;
27
+ /**
28
+ * Custom class name for the container
29
+ */
30
+ className?: string;
31
+ }
32
+ /**
33
+ * Container component for composable Mosaic chart editing.
34
+ * Provides context for child subcomponents.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <MosaicChart.Container
39
+ * spec={mySpec}
40
+ * params={paramsMap}
41
+ * editable={true}
42
+ * onSpecChange={(spec) => saveSpec(spec)}
43
+ * >
44
+ * <MosaicChart.Chart />
45
+ * <MosaicChart.SpecEditor />
46
+ * <MosaicChart.Actions />
47
+ * </MosaicChart.Container>
48
+ * ```
49
+ */
50
+ export declare const MosaicChartContainer: React.FC<MosaicChartContainerProps>;
51
+ //# sourceMappingURL=MosaicChartContainer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicChartContainer.d.ts","sourceRoot":"","sources":["../../src/editor/MosaicChartContainer.tsx"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAC;AACzC,OAAO,KAAgB,MAAM,OAAO,CAAC;AAErC,OAAO,EAA2B,kBAAkB,EAAC,MAAM,SAAS,CAAC;AAGrE,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC;;OAEG;IACH,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA8BpE,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '@sqlrooms/ui';
3
+ import { useMemo } from 'react';
4
+ import { MosaicEditorContext } from './MosaicEditorContext';
5
+ import { useMosaicChartEditor } from './useMosaicChartEditor';
6
+ /**
7
+ * Container component for composable Mosaic chart editing.
8
+ * Provides context for child subcomponents.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <MosaicChart.Container
13
+ * spec={mySpec}
14
+ * params={paramsMap}
15
+ * editable={true}
16
+ * onSpecChange={(spec) => saveSpec(spec)}
17
+ * >
18
+ * <MosaicChart.Chart />
19
+ * <MosaicChart.SpecEditor />
20
+ * <MosaicChart.Actions />
21
+ * </MosaicChart.Container>
22
+ * ```
23
+ */
24
+ export const MosaicChartContainer = ({ spec, params, editable = true, onSpecChange, children, className, }) => {
25
+ const { state, actions, canApply, hasChanges } = useMosaicChartEditor({
26
+ initialSpec: spec,
27
+ onSpecChange,
28
+ });
29
+ const contextValue = useMemo(() => ({
30
+ state,
31
+ actions,
32
+ editable,
33
+ params,
34
+ canApply,
35
+ hasChanges,
36
+ }), [state, actions, editable, params, canApply, hasChanges]);
37
+ return (_jsx(MosaicEditorContext.Provider, { value: contextValue, children: _jsx("div", { className: cn('flex flex-col gap-2', className), children: children }) }));
38
+ };
39
+ //# sourceMappingURL=MosaicChartContainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicChartContainer.js","sourceRoot":"","sources":["../../src/editor/MosaicChartContainer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAGhC,OAAc,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AA8B5D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAwC,CAAC,EACxE,IAAI,EACJ,MAAM,EACN,QAAQ,GAAG,IAAI,EACf,YAAY,EACZ,QAAQ,EACR,SAAS,GACV,EAAE,EAAE;IACH,MAAM,EAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAC,GAAG,oBAAoB,CAAC;QAClE,WAAW,EAAE,IAAI;QACjB,YAAY;KACb,CAAC,CAAC;IAEH,MAAM,YAAY,GAA6B,OAAO,CACpD,GAAG,EAAE,CAAC,CAAC;QACL,KAAK;QACL,OAAO;QACP,QAAQ;QACR,MAAM;QACN,QAAQ;QACR,UAAU;KACX,CAAC,EACF,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CACzD,CAAC;IAEF,OAAO,CACL,KAAC,mBAAmB,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YAC/C,cAAK,SAAS,EAAE,EAAE,CAAC,qBAAqB,EAAE,SAAS,CAAC,YAAG,QAAQ,GAAO,GACzC,CAChC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {cn} from '@sqlrooms/ui';\nimport {Param} from '@uwdata/mosaic-core';\nimport {Spec} from '@uwdata/mosaic-spec';\nimport React, {useMemo} from 'react';\nimport {MosaicEditorContext} from './MosaicEditorContext';\nimport {MosaicEditorContextValue, OnMosaicSpecChange} from './types';\nimport {useMosaicChartEditor} from './useMosaicChartEditor';\n\nexport interface MosaicChartContainerProps {\n /**\n * Initial Mosaic specification\n */\n spec: Spec | string;\n /**\n * Pre-defined params/selections for shared cross-filtering\n */\n params?: Map<string, Param<any>>;\n /**\n * Whether editing is enabled\n * @default true\n */\n editable?: boolean;\n /**\n * Callback when spec changes are applied\n */\n onSpecChange?: OnMosaicSpecChange;\n /**\n * Child components (Chart, SpecEditor, Actions)\n */\n children: React.ReactNode;\n /**\n * Custom class name for the container\n */\n className?: string;\n}\n\n/**\n * Container component for composable Mosaic chart editing.\n * Provides context for child subcomponents.\n *\n * @example\n * ```tsx\n * <MosaicChart.Container\n * spec={mySpec}\n * params={paramsMap}\n * editable={true}\n * onSpecChange={(spec) => saveSpec(spec)}\n * >\n * <MosaicChart.Chart />\n * <MosaicChart.SpecEditor />\n * <MosaicChart.Actions />\n * </MosaicChart.Container>\n * ```\n */\nexport const MosaicChartContainer: React.FC<MosaicChartContainerProps> = ({\n spec,\n params,\n editable = true,\n onSpecChange,\n children,\n className,\n}) => {\n const {state, actions, canApply, hasChanges} = useMosaicChartEditor({\n initialSpec: spec,\n onSpecChange,\n });\n\n const contextValue: MosaicEditorContextValue = useMemo(\n () => ({\n state,\n actions,\n editable,\n params,\n canApply,\n hasChanges,\n }),\n [state, actions, editable, params, canApply, hasChanges],\n );\n\n return (\n <MosaicEditorContext.Provider value={contextValue}>\n <div className={cn('flex flex-col gap-2', className)}>{children}</div>\n </MosaicEditorContext.Provider>\n );\n};\n"]}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ export interface MosaicChartDisplayProps {
3
+ /**
4
+ * Custom class name for the chart container
5
+ */
6
+ className?: string;
7
+ }
8
+ /**
9
+ * Chart display subcomponent for MosaicChart.Container.
10
+ * Renders the VgPlotChart with the current spec from editor context.
11
+ *
12
+ * Uses the last valid spec for rendering, so the chart keeps
13
+ * displaying even during typing with invalid JSON.
14
+ *
15
+ * Must be used within a MosaicChart.Container component.
16
+ */
17
+ export declare const MosaicChartDisplay: React.FC<MosaicChartDisplayProps>;
18
+ //# sourceMappingURL=MosaicChartDisplay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicChartDisplay.d.ts","sourceRoot":"","sources":["../../src/editor/MosaicChartDisplay.tsx"],"names":[],"mappings":"AACA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAIrC,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAehE,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '@sqlrooms/ui';
3
+ import React, { useMemo } from 'react';
4
+ import { VgPlotChart } from '../VgPlotChart';
5
+ import { useMosaicEditorContext } from './MosaicEditorContext';
6
+ /**
7
+ * Chart display subcomponent for MosaicChart.Container.
8
+ * Renders the VgPlotChart with the current spec from editor context.
9
+ *
10
+ * Uses the last valid spec for rendering, so the chart keeps
11
+ * displaying even during typing with invalid JSON.
12
+ *
13
+ * Must be used within a MosaicChart.Container component.
14
+ */
15
+ export const MosaicChartDisplay = React.memo(({ className }) => {
16
+ const { state, params } = useMosaicEditorContext();
17
+ const spec = useMemo(() => state.parsedSpec ?? state.lastValidSpec, [state.parsedSpec, state.lastValidSpec]);
18
+ return (_jsx("div", { className: cn('relative', className), children: _jsx(VgPlotChart, { spec: spec, params: params }) }));
19
+ });
20
+ MosaicChartDisplay.displayName = 'MosaicChartDisplay';
21
+ //# sourceMappingURL=MosaicChartDisplay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicChartDisplay.js","sourceRoot":"","sources":["../../src/editor/MosaicChartDisplay.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAChC,OAAO,KAAK,EAAE,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAC,sBAAsB,EAAC,MAAM,uBAAuB,CAAC;AAS7D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAsC,KAAK,CAAC,IAAI,CAC7E,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE;IACd,MAAM,EAAC,KAAK,EAAE,MAAM,EAAC,GAAG,sBAAsB,EAAE,CAAC;IAEjD,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,aAAa,EAC7C,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,aAAa,CAAC,CACxC,CAAC;IAEF,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,YACvC,KAAC,WAAW,IAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAI,GACvC,CACP,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,kBAAkB,CAAC,WAAW,GAAG,oBAAoB,CAAC","sourcesContent":["import {cn} from '@sqlrooms/ui';\nimport React, {useMemo} from 'react';\nimport {VgPlotChart} from '../VgPlotChart';\nimport {useMosaicEditorContext} from './MosaicEditorContext';\n\nexport interface MosaicChartDisplayProps {\n /**\n * Custom class name for the chart container\n */\n className?: string;\n}\n\n/**\n * Chart display subcomponent for MosaicChart.Container.\n * Renders the VgPlotChart with the current spec from editor context.\n *\n * Uses the last valid spec for rendering, so the chart keeps\n * displaying even during typing with invalid JSON.\n *\n * Must be used within a MosaicChart.Container component.\n */\nexport const MosaicChartDisplay: React.FC<MosaicChartDisplayProps> = React.memo(\n ({className}) => {\n const {state, params} = useMosaicEditorContext();\n\n const spec = useMemo(\n () => state.parsedSpec ?? state.lastValidSpec,\n [state.parsedSpec, state.lastValidSpec],\n );\n\n return (\n <div className={cn('relative', className)}>\n <VgPlotChart spec={spec} params={params} />\n </div>\n );\n },\n);\n\nMosaicChartDisplay.displayName = 'MosaicChartDisplay';\n"]}
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ export interface MosaicChartEditorActionsProps {
3
+ /**
4
+ * Custom class name for the actions container
5
+ */
6
+ className?: string;
7
+ /**
8
+ * Whether to show the Reset button
9
+ * @default true
10
+ */
11
+ showReset?: boolean;
12
+ }
13
+ /**
14
+ * Actions subcomponent for MosaicChart.Container.
15
+ * Renders Apply, Cancel, and Reset buttons.
16
+ *
17
+ * Must be used within a MosaicChart.Container component.
18
+ */
19
+ export declare const MosaicChartEditorActions: React.FC<MosaicChartEditorActionsProps>;
20
+ //# sourceMappingURL=MosaicChartEditorActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicChartEditorActions.d.ts","sourceRoot":"","sources":["../../src/editor/MosaicChartEditorActions.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,6BAA6B;IAC5C;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAC7C,6BAA6B,CA8C9B,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, cn } from '@sqlrooms/ui';
3
+ import { Check, RotateCcw, X } from 'lucide-react';
4
+ import { useMosaicEditorContext } from './MosaicEditorContext';
5
+ /**
6
+ * Actions subcomponent for MosaicChart.Container.
7
+ * Renders Apply, Cancel, and Reset buttons.
8
+ *
9
+ * Must be used within a MosaicChart.Container component.
10
+ */
11
+ export const MosaicChartEditorActions = ({ className, showReset = true }) => {
12
+ const { actions, canApply, hasChanges, editable } = useMosaicEditorContext();
13
+ if (!editable) {
14
+ return null;
15
+ }
16
+ return (_jsxs("div", { className: cn('flex items-center justify-end gap-2 border-t px-3 py-2', className), children: [showReset && (_jsxs(Button, { variant: "ghost", size: "sm", onClick: actions.resetToOriginal, title: "Reset to original", children: [_jsx(RotateCcw, { className: "mr-1 h-4 w-4" }), "Reset"] })), _jsxs(Button, { variant: "outline", size: "sm", onClick: actions.cancelChanges, disabled: !hasChanges, children: [_jsx(X, { className: "mr-1 h-4 w-4" }), "Cancel"] }), _jsxs(Button, { variant: "default", size: "sm", onClick: actions.applyChanges, disabled: !canApply, children: [_jsx(Check, { className: "mr-1 h-4 w-4" }), "Apply"] })] }));
17
+ };
18
+ //# sourceMappingURL=MosaicChartEditorActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicChartEditorActions.js","sourceRoot":"","sources":["../../src/editor/MosaicChartEditorActions.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,EAAE,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAC,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAC,sBAAsB,EAAC,MAAM,uBAAuB,CAAC;AAc7D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAEjC,CAAC,EAAC,SAAS,EAAE,SAAS,GAAG,IAAI,EAAC,EAAE,EAAE;IACpC,MAAM,EAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAC,GAAG,sBAAsB,EAAE,CAAC;IAE3E,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,wDAAwD,EACxD,SAAS,CACV,aAEA,SAAS,IAAI,CACZ,MAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,OAAO,CAAC,eAAe,EAChC,KAAK,EAAC,mBAAmB,aAEzB,KAAC,SAAS,IAAC,SAAS,EAAC,cAAc,GAAG,aAE/B,CACV,EACD,MAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,OAAO,CAAC,aAAa,EAC9B,QAAQ,EAAE,CAAC,UAAU,aAErB,KAAC,CAAC,IAAC,SAAS,EAAC,cAAc,GAAG,cAEvB,EACT,MAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,OAAO,CAAC,YAAY,EAC7B,QAAQ,EAAE,CAAC,QAAQ,aAEnB,KAAC,KAAK,IAAC,SAAS,EAAC,cAAc,GAAG,aAE3B,IACL,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {Button, cn} from '@sqlrooms/ui';\nimport {Check, RotateCcw, X} from 'lucide-react';\nimport React from 'react';\nimport {useMosaicEditorContext} from './MosaicEditorContext';\n\nexport interface MosaicChartEditorActionsProps {\n /**\n * Custom class name for the actions container\n */\n className?: string;\n /**\n * Whether to show the Reset button\n * @default true\n */\n showReset?: boolean;\n}\n\n/**\n * Actions subcomponent for MosaicChart.Container.\n * Renders Apply, Cancel, and Reset buttons.\n *\n * Must be used within a MosaicChart.Container component.\n */\nexport const MosaicChartEditorActions: React.FC<\n MosaicChartEditorActionsProps\n> = ({className, showReset = true}) => {\n const {actions, canApply, hasChanges, editable} = useMosaicEditorContext();\n\n if (!editable) {\n return null;\n }\n\n return (\n <div\n className={cn(\n 'flex items-center justify-end gap-2 border-t px-3 py-2',\n className,\n )}\n >\n {showReset && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={actions.resetToOriginal}\n title=\"Reset to original\"\n >\n <RotateCcw className=\"mr-1 h-4 w-4\" />\n Reset\n </Button>\n )}\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={actions.cancelChanges}\n disabled={!hasChanges}\n >\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={actions.applyChanges}\n disabled={!canApply}\n >\n <Check className=\"mr-1 h-4 w-4\" />\n Apply\n </Button>\n </div>\n );\n};\n"]}
@@ -0,0 +1,15 @@
1
+ import { JsonCodeMirrorEditorProps } from '@sqlrooms/codemirror';
2
+ import React from 'react';
3
+ export interface MosaicCodeMirrorEditorProps extends Omit<JsonCodeMirrorEditorProps, 'schema'> {
4
+ /**
5
+ * Whether to enable Mosaic JSON schema validation
6
+ * @default false
7
+ */
8
+ enableSchemaValidation?: boolean;
9
+ }
10
+ /**
11
+ * A CodeMirror editor specialized for editing Mosaic vgplot specifications.
12
+ * Automatically loads and configures the Mosaic JSON schema for validation.
13
+ */
14
+ export declare const MosaicCodeMirrorEditor: React.FC<MosaicCodeMirrorEditorProps>;
15
+ //# sourceMappingURL=MosaicCodeMirrorEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicCodeMirrorEditor.d.ts","sourceRoot":"","sources":["../../src/editor/MosaicCodeMirrorEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,yBAAyB,EAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAA4B,MAAM,OAAO,CAAC;AAGjD,MAAM,WAAW,2BAA4B,SAAQ,IAAI,CACvD,yBAAyB,EACzB,QAAQ,CACT;IACC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAkCxE,CAAC"}