@sqlrooms/mosaic 0.29.0-rc.0 → 0.29.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -2
- package/dist/MosaicChart.d.ts +20 -0
- package/dist/MosaicChart.d.ts.map +1 -0
- package/dist/MosaicChart.js +25 -0
- package/dist/MosaicChart.js.map +1 -0
- package/dist/MosaicChartBuilder.d.ts +32 -0
- package/dist/MosaicChartBuilder.d.ts.map +1 -0
- package/dist/MosaicChartBuilder.js +35 -0
- package/dist/MosaicChartBuilder.js.map +1 -0
- package/dist/MosaicColorLegend.d.ts +18 -0
- package/dist/MosaicColorLegend.d.ts.map +1 -0
- package/dist/MosaicColorLegend.js +117 -0
- package/dist/MosaicColorLegend.js.map +1 -0
- package/dist/MosaicSlice.d.ts +16 -13
- package/dist/MosaicSlice.d.ts.map +1 -1
- package/dist/MosaicSlice.js +67 -32
- package/dist/MosaicSlice.js.map +1 -1
- package/dist/VgPlotChart.d.ts +8 -0
- package/dist/VgPlotChart.d.ts.map +1 -1
- package/dist/VgPlotChart.js +26 -6
- package/dist/VgPlotChart.js.map +1 -1
- package/dist/chart-builders/ChartBuilderContent.d.ts +26 -0
- package/dist/chart-builders/ChartBuilderContent.d.ts.map +1 -0
- package/dist/chart-builders/ChartBuilderContent.js +59 -0
- package/dist/chart-builders/ChartBuilderContent.js.map +1 -0
- package/dist/chart-builders/ChartBuilderContext.d.ts +11 -0
- package/dist/chart-builders/ChartBuilderContext.d.ts.map +1 -0
- package/dist/chart-builders/ChartBuilderContext.js +10 -0
- package/dist/chart-builders/ChartBuilderContext.js.map +1 -0
- package/dist/chart-builders/ChartBuilderDialog.d.ts +23 -0
- package/dist/chart-builders/ChartBuilderDialog.d.ts.map +1 -0
- package/dist/chart-builders/ChartBuilderDialog.js +15 -0
- package/dist/chart-builders/ChartBuilderDialog.js.map +1 -0
- package/dist/chart-builders/FieldSelectorInput.d.ts +13 -0
- package/dist/chart-builders/FieldSelectorInput.d.ts.map +1 -0
- package/dist/chart-builders/FieldSelectorInput.js +19 -0
- package/dist/chart-builders/FieldSelectorInput.js.map +1 -0
- package/dist/chart-builders/builders.d.ts +7 -0
- package/dist/chart-builders/builders.d.ts.map +1 -0
- package/dist/chart-builders/builders.js +280 -0
- package/dist/chart-builders/builders.js.map +1 -0
- package/dist/chart-builders/chartSpecTitle.d.ts +7 -0
- package/dist/chart-builders/chartSpecTitle.d.ts.map +1 -0
- package/dist/chart-builders/chartSpecTitle.js +10 -0
- package/dist/chart-builders/chartSpecTitle.js.map +1 -0
- package/dist/chart-builders/createMosaicChartTool.d.ts +45 -0
- package/dist/chart-builders/createMosaicChartTool.d.ts.map +1 -0
- package/dist/chart-builders/createMosaicChartTool.js +109 -0
- package/dist/chart-builders/createMosaicChartTool.js.map +1 -0
- package/dist/chart-builders/describeChartSpecs.d.ts +7 -0
- package/dist/chart-builders/describeChartSpecs.d.ts.map +1 -0
- package/dist/chart-builders/describeChartSpecs.js +38 -0
- package/dist/chart-builders/describeChartSpecs.js.map +1 -0
- package/dist/chart-builders/types.d.ts +40 -0
- package/dist/chart-builders/types.d.ts.map +1 -0
- package/dist/chart-builders/types.js +2 -0
- package/dist/chart-builders/types.js.map +1 -0
- package/dist/dashboard/MosaicDashboard.d.ts +20 -0
- package/dist/dashboard/MosaicDashboard.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboard.js +68 -0
- package/dist/dashboard/MosaicDashboard.js.map +1 -0
- package/dist/dashboard/MosaicDashboardChartPanel.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardChartPanel.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardChartPanel.js +49 -0
- package/dist/dashboard/MosaicDashboardChartPanel.js.map +1 -0
- package/dist/dashboard/MosaicDashboardCharts.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardCharts.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardCharts.js +45 -0
- package/dist/dashboard/MosaicDashboardCharts.js.map +1 -0
- package/dist/dashboard/MosaicDashboardContext.d.ts +11 -0
- package/dist/dashboard/MosaicDashboardContext.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardContext.js +10 -0
- package/dist/dashboard/MosaicDashboardContext.js.map +1 -0
- package/dist/dashboard/MosaicDashboardProfiler.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardProfiler.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardProfiler.js +21 -0
- package/dist/dashboard/MosaicDashboardProfiler.js.map +1 -0
- package/dist/dashboard/MosaicDashboardSlice.d.ts +68 -0
- package/dist/dashboard/MosaicDashboardSlice.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardSlice.js +230 -0
- package/dist/dashboard/MosaicDashboardSlice.js.map +1 -0
- package/dist/dashboard/MosaicDashboardToolbar.d.ts +3 -0
- package/dist/dashboard/MosaicDashboardToolbar.d.ts.map +1 -0
- package/dist/dashboard/MosaicDashboardToolbar.js +19 -0
- package/dist/dashboard/MosaicDashboardToolbar.js.map +1 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.d.ts +8 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.d.ts.map +1 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.js +40 -0
- package/dist/dashboard/VgPlotSpecPopoverEditor.js.map +1 -0
- package/dist/editor/MosaicChartContainer.d.ts +51 -0
- package/dist/editor/MosaicChartContainer.d.ts.map +1 -0
- package/dist/editor/MosaicChartContainer.js +39 -0
- package/dist/editor/MosaicChartContainer.js.map +1 -0
- package/dist/editor/MosaicChartDisplay.d.ts +18 -0
- package/dist/editor/MosaicChartDisplay.d.ts.map +1 -0
- package/dist/editor/MosaicChartDisplay.js +21 -0
- package/dist/editor/MosaicChartDisplay.js.map +1 -0
- package/dist/editor/MosaicChartEditorActions.d.ts +20 -0
- package/dist/editor/MosaicChartEditorActions.d.ts.map +1 -0
- package/dist/editor/MosaicChartEditorActions.js +18 -0
- package/dist/editor/MosaicChartEditorActions.js.map +1 -0
- package/dist/editor/MosaicCodeMirrorEditor.d.ts +15 -0
- package/dist/editor/MosaicCodeMirrorEditor.d.ts.map +1 -0
- package/dist/editor/MosaicCodeMirrorEditor.js +26 -0
- package/dist/editor/MosaicCodeMirrorEditor.js.map +1 -0
- package/dist/editor/MosaicEditorContext.d.ts +8 -0
- package/dist/editor/MosaicEditorContext.d.ts.map +1 -0
- package/dist/editor/MosaicEditorContext.js +14 -0
- package/dist/editor/MosaicEditorContext.js.map +1 -0
- package/dist/editor/MosaicSpecEditorPanel.d.ts +20 -0
- package/dist/editor/MosaicSpecEditorPanel.d.ts.map +1 -0
- package/dist/editor/MosaicSpecEditorPanel.js +25 -0
- package/dist/editor/MosaicSpecEditorPanel.js.map +1 -0
- package/dist/editor/mosaicSchema.d.ts +20 -0
- package/dist/editor/mosaicSchema.d.ts.map +1 -0
- package/dist/editor/mosaicSchema.js +57 -0
- package/dist/editor/mosaicSchema.js.map +1 -0
- package/dist/editor/types.d.ts +72 -0
- package/dist/editor/types.d.ts.map +1 -0
- package/dist/editor/types.js +2 -0
- package/dist/editor/types.js.map +1 -0
- package/dist/editor/useMosaicChartEditor.d.ts +9 -0
- package/dist/editor/useMosaicChartEditor.d.ts.map +1 -0
- package/dist/editor/useMosaicChartEditor.js +199 -0
- package/dist/editor/useMosaicChartEditor.js.map +1 -0
- package/dist/index.d.ts +27 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/profiler/MosaicProfiler.d.ts +32 -0
- package/dist/profiler/MosaicProfiler.d.ts.map +1 -0
- package/dist/profiler/MosaicProfiler.js +57 -0
- package/dist/profiler/MosaicProfiler.js.map +1 -0
- package/dist/profiler/MosaicProfilerHeader.d.ts +7 -0
- package/dist/profiler/MosaicProfilerHeader.d.ts.map +1 -0
- package/dist/profiler/MosaicProfilerHeader.js +196 -0
- package/dist/profiler/MosaicProfilerHeader.js.map +1 -0
- package/dist/profiler/MosaicProfilerRows.d.ts +9 -0
- package/dist/profiler/MosaicProfilerRows.d.ts.map +1 -0
- package/dist/profiler/MosaicProfilerRows.js +65 -0
- package/dist/profiler/MosaicProfilerRows.js.map +1 -0
- package/dist/profiler/MosaicProfilerStatusBar.d.ts +9 -0
- package/dist/profiler/MosaicProfilerStatusBar.d.ts.map +1 -0
- package/dist/profiler/MosaicProfilerStatusBar.js +28 -0
- package/dist/profiler/MosaicProfilerStatusBar.js.map +1 -0
- package/dist/profiler/ProfilerCategoryClient.d.ts +50 -0
- package/dist/profiler/ProfilerCategoryClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerCategoryClient.js +121 -0
- package/dist/profiler/ProfilerCategoryClient.js.map +1 -0
- package/dist/profiler/ProfilerCountClient.d.ts +28 -0
- package/dist/profiler/ProfilerCountClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerCountClient.js +51 -0
- package/dist/profiler/ProfilerCountClient.js.map +1 -0
- package/dist/profiler/ProfilerHistogramClient.d.ts +69 -0
- package/dist/profiler/ProfilerHistogramClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerHistogramClient.js +179 -0
- package/dist/profiler/ProfilerHistogramClient.js.map +1 -0
- package/dist/profiler/ProfilerPageClient.d.ts +37 -0
- package/dist/profiler/ProfilerPageClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerPageClient.js +65 -0
- package/dist/profiler/ProfilerPageClient.js.map +1 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.d.ts +24 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.d.ts.map +1 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.js +51 -0
- package/dist/profiler/ProfilerUnsupportedSummaryClient.js.map +1 -0
- package/dist/profiler/createProfilerStore.d.ts +45 -0
- package/dist/profiler/createProfilerStore.d.ts.map +1 -0
- package/dist/profiler/createProfilerStore.js +120 -0
- package/dist/profiler/createProfilerStore.js.map +1 -0
- package/dist/profiler/layout.d.ts +7 -0
- package/dist/profiler/layout.d.ts.map +1 -0
- package/dist/profiler/layout.js +13 -0
- package/dist/profiler/layout.js.map +1 -0
- package/dist/profiler/profilerController.d.ts +64 -0
- package/dist/profiler/profilerController.d.ts.map +1 -0
- package/dist/profiler/profilerController.js +123 -0
- package/dist/profiler/profilerController.js.map +1 -0
- package/dist/profiler/types.d.ts +86 -0
- package/dist/profiler/types.d.ts.map +1 -0
- package/dist/profiler/types.js +2 -0
- package/dist/profiler/types.js.map +1 -0
- package/dist/profiler/useMosaicProfiler.d.ts +7 -0
- package/dist/profiler/useMosaicProfiler.d.ts.map +1 -0
- package/dist/profiler/useMosaicProfiler.js +339 -0
- package/dist/profiler/useMosaicProfiler.js.map +1 -0
- package/dist/profiler/utils.d.ts +61 -0
- package/dist/profiler/utils.d.ts.map +1 -0
- package/dist/profiler/utils.js +347 -0
- package/dist/profiler/utils.js.map +1 -0
- package/dist/tableInterop.d.ts +30 -0
- package/dist/tableInterop.d.ts.map +1 -0
- package/dist/tableInterop.js +85 -0
- package/dist/tableInterop.js.map +1 -0
- package/dist/use-mosaic.d.ts +11 -0
- package/dist/use-mosaic.d.ts.map +1 -0
- package/dist/use-mosaic.js +42 -0
- package/dist/use-mosaic.js.map +1 -0
- package/dist/useMosaicClient.d.ts +5 -4
- package/dist/useMosaicClient.d.ts.map +1 -1
- package/dist/useMosaicClient.js +13 -3
- package/dist/useMosaicClient.js.map +1 -1
- package/package.json +24 -6
package/dist/MosaicSlice.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MosaicSlice.js","sourceRoot":"","sources":["../src/MosaicSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {createId} from '@paralleldrive/cuid2';\nimport {DuckDbSliceState, isWasmDuckDbConnector} from '@sqlrooms/duckdb';\nimport {\n BaseRoomStoreState,\n createSlice,\n useBaseRoomStore,\n type SliceFunctions,\n} from '@sqlrooms/room-store';\nimport {\n Connector,\n Coordinator,\n coordinator,\n makeClient,\n Selection,\n wasmConnector,\n} from '@uwdata/mosaic-core';\nimport {Query} from '@uwdata/mosaic-sql';\nimport {produce} from 'immer';\nimport {z} from 'zod';\n\nexport const MosaicSliceConfig = z.object({});\nexport type MosaicSliceConfig = z.infer<typeof MosaicSliceConfig>;\n\n// Client configuration options\nexport type MosaicClientOptions<T = unknown> = {\n /** Unique identifier for this client */\n id?: string;\n /** Selection name for cross-filtering (will create if doesn't exist) */\n selectionName?: string;\n /** The selection to subscribe to for cross-filtering */\n selection?: Selection;\n /** Query builder function that receives the current filter */\n query: (filter: unknown) => ReturnType<typeof Query.from>;\n /** Callback when query results are received */\n queryResult?: (result: T) => void;\n};\n\n// Tracked client info\nexport type TrackedClient<T = unknown> = {\n id: string;\n client: ReturnType<typeof makeClient>;\n createdAt: number;\n isLoading: boolean;\n data: T | null;\n selection?: Selection; // Track for change detection\n queryResultCallback?: (result: T) => void; // External callback\n};\n\nexport type MosaicSliceState = {\n mosaic: SliceFunctions & {\n connection:\n | {status: 'idle' | 'loading'}\n | {status: 'ready'; connector: Connector; coordinator: Coordinator}\n | {status: 'error'; error: unknown};\n config: MosaicSliceConfig;\n /** Record of registered clients by id */\n clients: Record<string, TrackedClient<unknown>>;\n /** Named selections for cross-filtering (e.g., 'brush', 'hover') */\n selections: Record<string, Selection>;\n initialize: () => Promise<void>;\n /** Get or create a named selection for cross-filtering */\n getSelection: (\n name: string,\n type?: 'crossfilter' | 'single' | 'union',\n ) => Selection;\n /** Create a mosaic client and register it */\n createClient: <T>(options: MosaicClientOptions<T>) => string;\n /** Ensure a client exists with given options (idempotent - creates or updates as needed) */\n ensureClient: <T>(\n options: MosaicClientOptions<T> & {\n id: string;\n onQueryResult?: (result: T) => void;\n },\n ) => void;\n /** Disconnect and remove a client by id */\n destroyClient: (id: string) => void;\n /** Disconnect all clients (useful for cleanup) */\n destroyAllClients: () => void;\n };\n};\n\nexport function createDefaultMosaicConfig(\n props?: Partial<MosaicSliceConfig>,\n): MosaicSliceConfig {\n return {\n ...props,\n } as MosaicSliceConfig;\n}\n\nexport function createMosaicSlice(props?: {\n config?: Partial<MosaicSliceConfig>;\n}) {\n return createSlice<\n MosaicSliceState,\n BaseRoomStoreState & DuckDbSliceState & MosaicSliceState\n >((set, get, store) => ({\n mosaic: {\n config: createDefaultMosaicConfig(props?.config),\n connection: {\n status: 'idle',\n connector: undefined,\n },\n clients: {},\n selections: {},\n\n async initialize() {\n let mosaicConnector: Connector | undefined;\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.connection = {status: 'loading'};\n }),\n );\n try {\n const dbConnector = await get().db.getConnector();\n if (!isWasmDuckDbConnector(dbConnector)) {\n throw new Error('Only WasmDuckDbConnector is currently supported');\n }\n mosaicConnector = await coordinator().databaseConnector(\n wasmConnector({\n // @ts-expect-error - We install a different version of duckdb-wasm\n duckDb: dbConnector.getDb(),\n connection: dbConnector.getConnection(),\n }),\n );\n } catch (error) {\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.connection = {status: 'error', error};\n }),\n );\n throw error;\n } finally {\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.connection = {\n status: 'ready',\n connector: mosaicConnector!,\n coordinator: coordinator(),\n };\n }),\n );\n }\n },\n\n async destroy() {\n get().mosaic.destroyAllClients();\n },\n\n getSelection(\n name: string,\n type: 'crossfilter' | 'single' | 'union' = 'crossfilter',\n ) {\n const existing = get().mosaic.selections[name];\n if (existing) return existing;\n\n const selection =\n type === 'crossfilter'\n ? Selection.crossfilter()\n : type === 'single'\n ? Selection.single()\n : Selection.union();\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.selections[name] = selection;\n }),\n );\n return selection;\n },\n\n createClient<T>(options: MosaicClientOptions<T>) {\n const {connection} = get().mosaic;\n if (connection.status !== 'ready') {\n throw new Error('Mosaic connection not ready');\n }\n\n const id = options.id ?? createId();\n\n // Determine which selection to use\n const selection =\n options.selection ??\n (options.selectionName\n ? get().mosaic.getSelection(options.selectionName)\n : undefined);\n\n // Wrap queryResult to update store state AND call external callback\n const wrappedQueryResult = (data: unknown) => {\n const typedData = data as T;\n set((state) =>\n produce(state, (draft) => {\n const tracked = draft.mosaic.clients[id];\n if (tracked) {\n tracked.data = typedData;\n tracked.isLoading = false;\n }\n }),\n );\n // Call external callback if provided\n options.queryResult?.(typedData);\n };\n\n const client = makeClient({\n coordinator: connection.coordinator,\n selection,\n query: options.query,\n queryResult: wrappedQueryResult,\n });\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.clients[id] = {\n id,\n client,\n createdAt: Date.now(),\n isLoading: true,\n data: null,\n selection,\n queryResultCallback: options.queryResult\n ? (result: unknown) => options.queryResult!(result as T)\n : undefined,\n };\n }),\n );\n\n return id;\n },\n\n ensureClient<T>(\n options: MosaicClientOptions<T> & {\n id: string;\n onQueryResult?: (result: T) => void;\n },\n ) {\n const {connection, clients} = get().mosaic;\n if (connection.status !== 'ready') {\n return; // Silently return if not ready - hook will handle retry\n }\n\n const existing = clients[options.id];\n\n // Determine which selection to use\n const selection =\n options.selection ??\n (options.selectionName\n ? get().mosaic.getSelection(options.selectionName)\n : undefined);\n\n // Check if client exists and selection matches\n // Note: If query or callback changes, we recreate the client to ensure\n // the latest versions are used. This is simpler than trying to update\n // the bound queryResult callback in makeClient.\n if (existing && existing.selection === selection) {\n return; // No-op - client already exists with same selection\n }\n\n // If exists but selection changed, destroy it first\n if (existing) {\n get().mosaic.destroyClient(options.id);\n }\n\n // Create new client with wrapped queryResult that calls both store update and external callback\n const wrappedQueryResult = (data: unknown) => {\n const typedData = data as T;\n set((state) =>\n produce(state, (draft) => {\n const tracked = draft.mosaic.clients[options.id];\n if (tracked) {\n tracked.data = typedData;\n tracked.isLoading = false;\n }\n }),\n );\n // Call external callback if provided\n options.onQueryResult?.(typedData);\n // Also call original queryResult if provided\n options.queryResult?.(typedData);\n };\n\n const client = makeClient({\n coordinator: connection.coordinator,\n selection,\n query: options.query,\n queryResult: wrappedQueryResult,\n });\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.clients[options.id] = {\n id: options.id,\n client,\n createdAt: Date.now(),\n isLoading: true,\n data: null,\n selection,\n queryResultCallback: options.onQueryResult as\n | ((result: unknown) => void)\n | undefined,\n };\n }),\n );\n },\n\n destroyClient(id: string) {\n const {connection, clients} = get().mosaic;\n const tracked = clients[id];\n if (!tracked) return;\n\n if (connection.status === 'ready') {\n connection.coordinator.disconnect(tracked.client);\n }\n\n set((state) =>\n produce(state, (draft) => {\n delete draft.mosaic.clients[id];\n }),\n );\n },\n\n destroyAllClients() {\n const {connection, clients} = get().mosaic;\n\n if (connection.status === 'ready') {\n Object.values(clients).forEach((tracked) => {\n connection.coordinator.disconnect(tracked.client);\n });\n }\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.clients = {};\n }),\n );\n },\n },\n }));\n}\n\nexport type DuckDbSliceStateWithMosaic = DuckDbSliceState & MosaicSliceState;\n\nexport function useStoreWithMosaic<T>(\n selector: (state: DuckDbSliceStateWithMosaic) => T,\n): T {\n return useBaseRoomStore<BaseRoomStoreState, T>((state) =>\n selector(state as unknown as DuckDbSliceStateWithMosaic),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MosaicSlice.js","sourceRoot":"","sources":["../src/MosaicSlice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EACL,qBAAqB,GAGtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,WAAW,EACX,gBAAgB,GAEjB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EAGL,WAAW,EAEX,UAAU,EACV,SAAS,EACT,aAAa,GACd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EACL,+BAA+B,EAC/B,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AA6D9C,MAAM,UAAU,yBAAyB,CACvC,KAAkC;IAElC,OAAO;QACL,GAAG,KAAK;KACY,CAAC;AACzB,CAAC;AAOD,MAAM,UAAU,iBAAiB,CAAC,QAAgC,EAAE;IAClE,OAAO,WAAW,CAGhB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACtB,MAAM,EAAE;YACN,MAAM,EAAE,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC;YAChD,UAAU,EAAE,EAAC,MAAM,EAAE,MAAM,EAAC;YAC5B,OAAO,EAAE,EAAE;YACX,UAAU,EAAE,EAAE;YAEd,KAAK,CAAC,UAAU;gBACd,IAAI,eAAsC,CAAC;gBAC3C,IAAI,mBAAiC,CAAC;gBACtC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,EAAC,MAAM,EAAE,SAAS,EAAC,CAAC;gBAChD,CAAC,CAAC,CACH,CAAC;gBACF,IAAI,CAAC;oBACH,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;wBACtB,mBAAmB,GAAG,KAAK,CAAC,WAAW,CAAC;oBAC1C,CAAC;yBAAM,CAAC;wBACN,MAAM,WAAW,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;wBAClD,mBAAmB,GAAG,WAAW,EAAE,CAAC;wBACpC,eAAe,GAAG,qBAAqB,CAAC,WAAW,CAAC;4BAClD,CAAC,CAAC,MAAM,aAAa,CAAC;gCAClB,mEAAmE;gCACnE,MAAM,EAAE,WAAW,CAAC,KAAK,EAAE;gCAC3B,UAAU,EAAE,WAAW,CAAC,aAAa,EAAE;6BACxC,CAAC;4BACJ,CAAC,CAAC,2BAA2B,CAAC,WAAW,CAAC,CAAC;wBAC7C,mBAAmB,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC;oBACzD,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,EAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAC,CAAC;oBACrD,CAAC,CAAC,CACH,CAAC;oBACF,MAAM,KAAK,CAAC;gBACd,CAAC;gBACD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG;wBACxB,MAAM,EAAE,OAAO;wBACf,SAAS,EAAE,eAAe;wBAC1B,WAAW,EAAE,mBAAmB;qBACjC,CAAC;gBACJ,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;YAED,KAAK,CAAC,OAAO;gBACX,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;YACnC,CAAC;YAED,YAAY,CACV,IAAY,EACZ,OAA2C,aAAa;gBAExD,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,QAAQ;oBAAE,OAAO,QAAQ,CAAC;gBAE9B,MAAM,SAAS,GACb,IAAI,KAAK,aAAa;oBACpB,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;oBACzB,CAAC,CAAC,IAAI,KAAK,QAAQ;wBACjB,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE;wBACpB,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;gBAE1B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;gBAC5C,CAAC,CAAC,CACH,CAAC;gBACF,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,YAAY,CAAC,OAA4B;gBACvC,MAAM,EAAC,UAAU,EAAC,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC;gBAClC,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBAClC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;gBACjD,CAAC;gBAED,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAEpC,mCAAmC;gBACnC,MAAM,SAAS,GACb,OAAO,CAAC,SAAS;oBACjB,CAAC,OAAO,CAAC,aAAa;wBACpB,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,aAAa,CAAC;wBAClD,CAAC,CAAC,SAAS,CAAC,CAAC;gBAEjB,oEAAoE;gBACpE,MAAM,kBAAkB,GAAG,CAAC,IAAa,EAAE,EAAE;oBAC3C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;wBACzC,IAAI,OAAO,EAAE,CAAC;4BACZ,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;4BACpB,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC;wBAC5B,CAAC;oBACH,CAAC,CAAC,CACH,CAAC;oBACF,qCAAqC;oBACrC,OAAO,CAAC,WAAW,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;gBACnD,CAAC,CAAC;gBAEF,MAAM,MAAM,GAAG,UAAU,CAAC;oBACxB,WAAW,EAAE,UAAU,CAAC,WAAW;oBACnC,SAAS;oBACT,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,WAAW,EAAE,kBAAkB;iBAChC,CAAC,CAAC;gBAEH,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;wBACzB,EAAE;wBACF,MAAM;wBACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;wBACrB,SAAS,EAAE,IAAI;wBACf,IAAI,EAAE,IAAI;wBACV,SAAS;wBACT,mBAAmB,EAAE,OAAO,CAAC,WAAW;4BACtC,CAAC,CAAC,CAAC,MAAe,EAAE,EAAE,CAClB,OAAO,CAAC,WAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;4BACrD,CAAC,CAAC,SAAS;qBACd,CAAC;gBACJ,CAAC,CAAC,CACH,CAAC;gBAEF,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,YAAY,CACV,OAGC;gBAED,MAAM,EAAC,UAAU,EAAE,OAAO,EAAC,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC;gBAC3C,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBAClC,OAAO,CAAC,wDAAwD;gBAClE,CAAC;gBAED,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAErC,mCAAmC;gBACnC,MAAM,SAAS,GACb,OAAO,CAAC,SAAS;oBACjB,CAAC,OAAO,CAAC,aAAa;wBACpB,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,aAAa,CAAC;wBAClD,CAAC,CAAC,SAAS,CAAC,CAAC;gBAEjB,+CAA+C;gBAC/C,uEAAuE;gBACvE,sEAAsE;gBACtE,gDAAgD;gBAChD,IAAI,QAAQ,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;oBACjD,OAAO,CAAC,oDAAoD;gBAC9D,CAAC;gBAED,oDAAoD;gBACpD,IAAI,QAAQ,EAAE,CAAC;oBACb,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBACzC,CAAC;gBAED,gGAAgG;gBAChG,MAAM,kBAAkB,GAAG,CAAC,IAAa,EAAE,EAAE;oBAC3C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;wBACjD,IAAI,OAAO,EAAE,CAAC;4BACZ,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;4BACpB,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC;wBAC5B,CAAC;oBACH,CAAC,CAAC,CACH,CAAC;oBACF,MAAM,SAAS,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;oBAC5C,qCAAqC;oBACrC,OAAO,CAAC,aAAa,EAAE,CAAC,SAAS,CAAC,CAAC;oBACnC,6CAA6C;oBAC7C,OAAO,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC;gBACnC,CAAC,CAAC;gBAEF,MAAM,MAAM,GAAG,UAAU,CAAC;oBACxB,WAAW,EAAE,UAAU,CAAC,WAAW;oBACnC,SAAS;oBACT,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,WAAW,EAAE,kBAAkB;iBAChC,CAAC,CAAC;gBAEH,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;wBACjC,EAAE,EAAE,OAAO,CAAC,EAAE;wBACd,MAAM;wBACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;wBACrB,SAAS,EAAE,IAAI;wBACf,IAAI,EAAE,IAAI;wBACV,SAAS;wBACT,mBAAmB,EAAE,OAAO,CAAC,aAAa;4BACxC,CAAC,CAAC,CAAC,MAAe,EAAE,EAAE,CAClB,OAAO,CAAC,aAAc,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;4BACvD,CAAC,CAAC,SAAS;qBACd,CAAC;gBACJ,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;YAED,aAAa,CAAC,EAAU;gBACtB,MAAM,EAAC,UAAU,EAAE,OAAO,EAAC,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC;gBAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC5B,IAAI,CAAC,OAAO;oBAAE,OAAO;gBAErB,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBAClC,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBACpD,CAAC;gBAED,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAClC,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;YAED,iBAAiB;gBACf,MAAM,EAAC,UAAU,EAAE,OAAO,EAAC,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC;gBAE3C,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;wBACzC,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACpD,CAAC,CAAC,CAAC;gBACL,CAAC;gBAED,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,KAAK,CAAC,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;gBAC5B,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAID,MAAM,UAAU,kBAAkB,CAChC,QAAkD;IAElD,OAAO,gBAAgB,CAAwB,CAAC,KAAK,EAAE,EAAE,CACvD,QAAQ,CAAC,KAA8C,CAAC,CACzD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,2BAA2B,CAAC,SAA0B;IAC7D,OAAO;QACL,KAAK,EAAE,CAAC,KAAK,EACX,KAA8D,EAC9D,EAAE;YACF,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC;YACxC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;gBACzB,MAAM,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACnC,OAAO,SAAgB,CAAC;YAC1B,CAAC;YACD,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,CACpC,KAAK,CAAC,GAAG,CACV,CAAC;gBACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAQ,CAAC;YACjC,CAAC;YACD,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;gBAC1B,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACpD,OAAO,+BAA+B,CAAC,UAAU,CAAQ,CAAC;YAC5D,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,SAAS,IAAI,CAAC,CAAC;QACnE,CAAC,CAAuB;KACzB,CAAC;AACJ,CAAC","sourcesContent":["import {createId} from '@paralleldrive/cuid2';\nimport {\n isWasmDuckDbConnector,\n type DuckDbConnector,\n type DuckDbSliceState,\n} from '@sqlrooms/duckdb';\nimport {\n BaseRoomStoreState,\n createSlice,\n useBaseRoomStore,\n type SliceFunctions,\n} from '@sqlrooms/room-store';\nimport type {\n ArrowQueryRequest,\n ExecQueryRequest,\n JSONQueryRequest,\n} from '@uwdata/mosaic-core';\nimport {\n Connector,\n Coordinator,\n coordinator,\n decodeIPC,\n makeClient,\n Selection,\n wasmConnector,\n} from '@uwdata/mosaic-core';\nimport {Query} from '@uwdata/mosaic-sql';\nimport type {Table as ArrowTable} from 'apache-arrow';\nimport {produce} from 'immer';\nimport {z} from 'zod';\nimport {\n createMosaicTableFromArrowTable,\n toArrowClientResult,\n} from './tableInterop';\n\nexport const MosaicSliceConfig = z.object({});\nexport type MosaicSliceConfig = z.infer<typeof MosaicSliceConfig>;\n\n// Client configuration options\nexport type MosaicClientOptions = {\n /** Unique identifier for this client */\n id?: string;\n /** Selection name for cross-filtering (will create if doesn't exist) */\n selectionName?: string;\n /** The selection to subscribe to for cross-filtering */\n selection?: Selection;\n /** Query builder function that receives the current filter */\n query: (filter: unknown) => ReturnType<typeof Query.from>;\n /** Callback when query results are received */\n queryResult?: (result: ArrowTable) => void;\n};\n\n// Tracked client info\nexport type TrackedClient = {\n id: string;\n client: ReturnType<typeof makeClient>;\n createdAt: number;\n isLoading: boolean;\n data: unknown | null;\n selection?: Selection; // Track for change detection\n queryResultCallback?: (result: ArrowTable) => void; // External callback\n};\n\nexport type MosaicSliceState = {\n mosaic: SliceFunctions & {\n connection:\n | {status: 'idle' | 'loading'}\n | {status: 'ready'; connector?: Connector; coordinator: Coordinator}\n | {status: 'error'; error: unknown};\n config: MosaicSliceConfig;\n /** Record of registered clients by id */\n clients: Record<string, TrackedClient>;\n /** Named selections for cross-filtering (e.g., 'brush', 'hover') */\n selections: Record<string, Selection>;\n initialize: () => Promise<void>;\n /** Get or create a named selection for cross-filtering */\n getSelection: (\n name: string,\n type?: 'crossfilter' | 'single' | 'union',\n ) => Selection;\n /** Create a mosaic client and register it */\n createClient: (options: MosaicClientOptions) => string;\n /** Ensure a client exists with given options (idempotent - creates or updates as needed) */\n ensureClient: (\n options: MosaicClientOptions & {\n id: string;\n onQueryResult?: (result: ArrowTable) => void;\n },\n ) => void;\n /** Disconnect and remove a client by id */\n destroyClient: (id: string) => void;\n /** Disconnect all clients (useful for cleanup) */\n destroyAllClients: () => void;\n };\n};\n\nexport function createDefaultMosaicConfig(\n props?: Partial<MosaicSliceConfig>,\n): MosaicSliceConfig {\n return {\n ...props,\n } as MosaicSliceConfig;\n}\n\nexport type CreateMosaicSliceProps = {\n config?: Partial<MosaicSliceConfig>;\n coordinator?: Coordinator;\n};\n\nexport function createMosaicSlice(props: CreateMosaicSliceProps = {}) {\n return createSlice<\n MosaicSliceState,\n BaseRoomStoreState & DuckDbSliceState & MosaicSliceState\n >((set, get, store) => ({\n mosaic: {\n config: createDefaultMosaicConfig(props?.config),\n connection: {status: 'idle'},\n clients: {},\n selections: {},\n\n async initialize() {\n let mosaicConnector: Connector | undefined;\n let resolvedCoordinator!: Coordinator;\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.connection = {status: 'loading'};\n }),\n );\n try {\n if (props.coordinator) {\n resolvedCoordinator = props.coordinator;\n } else {\n const dbConnector = await get().db.getConnector();\n resolvedCoordinator = coordinator();\n mosaicConnector = isWasmDuckDbConnector(dbConnector)\n ? await wasmConnector({\n // @ts-expect-error - We install a different version of duckdb-wasm\n duckDb: dbConnector.getDb(),\n connection: dbConnector.getConnection(),\n })\n : createDuckDbMosaicConnector(dbConnector);\n resolvedCoordinator.databaseConnector(mosaicConnector);\n }\n } catch (error) {\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.connection = {status: 'error', error};\n }),\n );\n throw error;\n }\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.connection = {\n status: 'ready',\n connector: mosaicConnector,\n coordinator: resolvedCoordinator,\n };\n }),\n );\n },\n\n async destroy() {\n get().mosaic.destroyAllClients();\n },\n\n getSelection(\n name: string,\n type: 'crossfilter' | 'single' | 'union' = 'crossfilter',\n ) {\n const existing = get().mosaic.selections[name];\n if (existing) return existing;\n\n const selection =\n type === 'crossfilter'\n ? Selection.crossfilter()\n : type === 'single'\n ? Selection.single()\n : Selection.union();\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.selections[name] = selection;\n }),\n );\n return selection;\n },\n\n createClient(options: MosaicClientOptions) {\n const {connection} = get().mosaic;\n if (connection.status !== 'ready') {\n throw new Error('Mosaic connection not ready');\n }\n\n const id = options.id ?? createId();\n\n // Determine which selection to use\n const selection =\n options.selection ??\n (options.selectionName\n ? get().mosaic.getSelection(options.selectionName)\n : undefined);\n\n // Wrap queryResult to update store state AND call external callback\n const wrappedQueryResult = (data: unknown) => {\n set((state) =>\n produce(state, (draft) => {\n const tracked = draft.mosaic.clients[id];\n if (tracked) {\n tracked.data = data;\n tracked.isLoading = false;\n }\n }),\n );\n // Call external callback if provided\n options.queryResult?.(toArrowClientResult(data));\n };\n\n const client = makeClient({\n coordinator: connection.coordinator,\n selection,\n query: options.query,\n queryResult: wrappedQueryResult,\n });\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.clients[id] = {\n id,\n client,\n createdAt: Date.now(),\n isLoading: true,\n data: null,\n selection,\n queryResultCallback: options.queryResult\n ? (result: unknown) =>\n options.queryResult!(toArrowClientResult(result))\n : undefined,\n };\n }),\n );\n\n return id;\n },\n\n ensureClient(\n options: MosaicClientOptions & {\n id: string;\n onQueryResult?: (result: ArrowTable) => void;\n },\n ) {\n const {connection, clients} = get().mosaic;\n if (connection.status !== 'ready') {\n return; // Silently return if not ready - hook will handle retry\n }\n\n const existing = clients[options.id];\n\n // Determine which selection to use\n const selection =\n options.selection ??\n (options.selectionName\n ? get().mosaic.getSelection(options.selectionName)\n : undefined);\n\n // Check if client exists and selection matches\n // Note: If query or callback changes, we recreate the client to ensure\n // the latest versions are used. This is simpler than trying to update\n // the bound queryResult callback in makeClient.\n if (existing && existing.selection === selection) {\n return; // No-op - client already exists with same selection\n }\n\n // If exists but selection changed, destroy it first\n if (existing) {\n get().mosaic.destroyClient(options.id);\n }\n\n // Create new client with wrapped queryResult that calls both store update and external callback\n const wrappedQueryResult = (data: unknown) => {\n set((state) =>\n produce(state, (draft) => {\n const tracked = draft.mosaic.clients[options.id];\n if (tracked) {\n tracked.data = data;\n tracked.isLoading = false;\n }\n }),\n );\n const arrowData = toArrowClientResult(data);\n // Call external callback if provided\n options.onQueryResult?.(arrowData);\n // Also call original queryResult if provided\n options.queryResult?.(arrowData);\n };\n\n const client = makeClient({\n coordinator: connection.coordinator,\n selection,\n query: options.query,\n queryResult: wrappedQueryResult,\n });\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.clients[options.id] = {\n id: options.id,\n client,\n createdAt: Date.now(),\n isLoading: true,\n data: null,\n selection,\n queryResultCallback: options.onQueryResult\n ? (result: unknown) =>\n options.onQueryResult!(toArrowClientResult(result))\n : undefined,\n };\n }),\n );\n },\n\n destroyClient(id: string) {\n const {connection, clients} = get().mosaic;\n const tracked = clients[id];\n if (!tracked) return;\n\n if (connection.status === 'ready') {\n connection.coordinator.disconnect(tracked.client);\n }\n\n set((state) =>\n produce(state, (draft) => {\n delete draft.mosaic.clients[id];\n }),\n );\n },\n\n destroyAllClients() {\n const {connection, clients} = get().mosaic;\n\n if (connection.status === 'ready') {\n Object.values(clients).forEach((tracked) => {\n connection.coordinator.disconnect(tracked.client);\n });\n }\n\n set((state) =>\n produce(state, (draft) => {\n draft.mosaic.clients = {};\n }),\n );\n },\n },\n }));\n}\n\nexport type DuckDbSliceStateWithMosaic = DuckDbSliceState & MosaicSliceState;\n\nexport function useStoreWithMosaic<T>(\n selector: (state: DuckDbSliceStateWithMosaic) => T,\n): T {\n return useBaseRoomStore<BaseRoomStoreState, T>((state) =>\n selector(state as unknown as DuckDbSliceStateWithMosaic),\n );\n}\n\n/**\n * Adapts a {@link DuckDbConnector} to the Mosaic {@link Connector} interface.\n *\n * For `'arrow'` queries the Apache Arrow table returned by the connector is\n * converted via {@link createMosaicTableFromArrowTable} into a flechette\n * `Table`, which is the shape Mosaic consumers expect (with `.toColumns()`).\n * For `'json'` queries, rows are materialized with {@link Array.from} which\n * may have performance/memory implications for very large result sets.\n * The `as any` casts on the return type are an intentional adapter trade-off\n * to satisfy the polymorphic {@link Connector['query']} signature.\n */\nfunction createDuckDbMosaicConnector(connector: DuckDbConnector): Connector {\n return {\n query: (async (\n query: ArrowQueryRequest | ExecQueryRequest | JSONQueryRequest,\n ) => {\n const queryType = query.type ?? 'arrow';\n if (queryType === 'exec') {\n await connector.execute(query.sql);\n return undefined as any;\n }\n if (queryType === 'json') {\n const rows = await connector.queryJson<Record<string, unknown>>(\n query.sql,\n );\n return Array.from(rows) as any;\n }\n if (queryType === 'arrow') {\n const arrowTable = await connector.query(query.sql);\n return createMosaicTableFromArrowTable(arrowTable) as any;\n }\n throw new Error(`Unsupported Mosaic query type \"${queryType}\".`);\n }) as Connector['query'],\n };\n}\n"]}
|
package/dist/VgPlotChart.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { Param } from '@uwdata/mosaic-core';
|
|
1
2
|
import { Spec } from '@uwdata/mosaic-spec';
|
|
2
3
|
import { FC } from 'react';
|
|
3
4
|
type SpecProps = {
|
|
4
5
|
spec: Spec;
|
|
6
|
+
/**
|
|
7
|
+
* Pre-defined params/selections to inject when rendering the spec.
|
|
8
|
+
* Keys are param names (without $), values are Param or Selection instances.
|
|
9
|
+
* This allows multiple independently-rendered specs to share the same
|
|
10
|
+
* Selection objects for cross-filtering.
|
|
11
|
+
*/
|
|
12
|
+
params?: Map<string, Param<any>>;
|
|
5
13
|
};
|
|
6
14
|
type PlotProps = {
|
|
7
15
|
plot: HTMLElement | SVGSVGElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VgPlotChart.d.ts","sourceRoot":"","sources":["../src/VgPlotChart.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsB,IAAI,EAAC,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"VgPlotChart.d.ts","sourceRoot":"","sources":["../src/VgPlotChart.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAsB,IAAI,EAAC,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAC,EAAE,EAA0B,MAAM,OAAO,CAAC;AAElD,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,IAAI,CAAC;IACX;;;;;OAKG;IACH,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;CAClC,CAAC;AACF,KAAK,SAAS,GAAG;IAAC,IAAI,EAAE,WAAW,GAAG,aAAa,CAAA;CAAC,CAAC;AACrD,KAAK,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9C,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,KAAK,IAAI,SAAS,CAEvE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,KAAK,IAAI,SAAS,CAEvE;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA2C5C,CAAC"}
|
package/dist/VgPlotChart.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { astToDOM, parseSpec } from '@uwdata/mosaic-spec';
|
|
3
|
-
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { memo, useEffect, useRef } from 'react';
|
|
4
4
|
export function isSpecProps(props) {
|
|
5
5
|
return 'spec' in props;
|
|
6
6
|
}
|
|
@@ -14,9 +14,10 @@ export function isPlotProps(props) {
|
|
|
14
14
|
* @param {Spec} props.spec - The Vega-Lite specification for the chart.
|
|
15
15
|
* @returns {React.ReactElement} The rendered chart component.
|
|
16
16
|
*/
|
|
17
|
-
export const VgPlotChart = (props) => {
|
|
17
|
+
export const VgPlotChart = memo((props) => {
|
|
18
18
|
const containerRef = useRef(null);
|
|
19
19
|
useEffect(() => {
|
|
20
|
+
let cancelled = false;
|
|
20
21
|
(async () => {
|
|
21
22
|
if (containerRef.current) {
|
|
22
23
|
let element;
|
|
@@ -25,16 +26,35 @@ export const VgPlotChart = (props) => {
|
|
|
25
26
|
}
|
|
26
27
|
else if (isSpecProps(props)) {
|
|
27
28
|
const ast = await parseSpec(props.spec);
|
|
28
|
-
|
|
29
|
+
if (cancelled)
|
|
30
|
+
return;
|
|
31
|
+
const options = props.params ? { params: props.params } : undefined;
|
|
32
|
+
element = (await astToDOM(ast, options)).element;
|
|
29
33
|
}
|
|
30
34
|
else {
|
|
31
35
|
element = document.createElement('div');
|
|
32
36
|
element.innerHTML = 'Error: Invalid props provided to VgPlotChart';
|
|
33
37
|
}
|
|
34
|
-
|
|
38
|
+
if (!cancelled) {
|
|
39
|
+
containerRef.current?.replaceChildren(element);
|
|
40
|
+
}
|
|
35
41
|
}
|
|
36
42
|
})();
|
|
37
|
-
|
|
43
|
+
return () => {
|
|
44
|
+
cancelled = true;
|
|
45
|
+
};
|
|
46
|
+
}, [props]);
|
|
38
47
|
return _jsx("div", { ref: containerRef });
|
|
39
|
-
}
|
|
48
|
+
}, (prevProps, nextProps) => {
|
|
49
|
+
if (isPlotProps(prevProps) && isPlotProps(nextProps)) {
|
|
50
|
+
return prevProps.plot === nextProps.plot;
|
|
51
|
+
}
|
|
52
|
+
if (isSpecProps(prevProps) && isSpecProps(nextProps)) {
|
|
53
|
+
const specEqual = JSON.stringify(prevProps.spec) === JSON.stringify(nextProps.spec);
|
|
54
|
+
const paramsEqual = prevProps.params === nextProps.params;
|
|
55
|
+
return specEqual && paramsEqual;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
});
|
|
59
|
+
VgPlotChart.displayName = 'VgPlotChart';
|
|
40
60
|
//# sourceMappingURL=VgPlotChart.js.map
|
package/dist/VgPlotChart.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VgPlotChart.js","sourceRoot":"","sources":["../src/VgPlotChart.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"VgPlotChart.js","sourceRoot":"","sources":["../src/VgPlotChart.tsx"],"names":[],"mappings":";AACA,OAAO,EAAC,QAAQ,EAAE,SAAS,EAAO,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAK,IAAI,EAAE,SAAS,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;AAelD,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,OAAO,MAAM,IAAI,KAAK,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,OAAO,MAAM,IAAI,KAAK,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAyB,IAAI,CACnD,CAAC,KAAK,EAAE,EAAE;IACR,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;gBACzB,IAAI,OAAoC,CAAC;gBACzC,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;oBACvB,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC;gBACvB,CAAC;qBAAM,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC9B,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACxC,IAAI,SAAS;wBAAE,OAAO;oBACtB,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAC,CAAC,CAAC,CAAC,SAAS,CAAC;oBAClE,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;oBACxC,OAAO,CAAC,SAAS,GAAG,8CAA8C,CAAC;gBACrE,CAAC;gBACD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,cAAK,GAAG,EAAE,YAAY,GAAI,CAAC;AACpC,CAAC,EACD,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE;IACvB,IAAI,WAAW,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,OAAO,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC;IAC3C,CAAC;IACD,IAAI,WAAW,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,MAAM,SAAS,GACb,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACpE,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,CAAC;QAC1D,OAAO,SAAS,IAAI,WAAW,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CACF,CAAC;AAEF,WAAW,CAAC,WAAW,GAAG,aAAa,CAAC","sourcesContent":["import {Param} from '@uwdata/mosaic-core';\nimport {astToDOM, parseSpec, Spec} from '@uwdata/mosaic-spec';\nimport {FC, memo, useEffect, useRef} from 'react';\n\ntype SpecProps = {\n spec: Spec;\n /**\n * Pre-defined params/selections to inject when rendering the spec.\n * Keys are param names (without $), values are Param or Selection instances.\n * This allows multiple independently-rendered specs to share the same\n * Selection objects for cross-filtering.\n */\n params?: Map<string, Param<any>>;\n};\ntype PlotProps = {plot: HTMLElement | SVGSVGElement};\ntype VgPlotChartProps = SpecProps | PlotProps;\n\nexport function isSpecProps(props: VgPlotChartProps): props is SpecProps {\n return 'spec' in props;\n}\n\nexport function isPlotProps(props: VgPlotChartProps): props is PlotProps {\n return 'plot' in props;\n}\n\n/**\n * Renders a Vega-Lite chart using the Mosaic library.\n *\n * @param {VgPlotChartProps} props - The component props.\n * @param {Spec} props.spec - The Vega-Lite specification for the chart.\n * @returns {React.ReactElement} The rendered chart component.\n */\nexport const VgPlotChart: FC<VgPlotChartProps> = memo(\n (props) => {\n const containerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n let cancelled = false;\n (async () => {\n if (containerRef.current) {\n let element: HTMLElement | SVGSVGElement;\n if (isPlotProps(props)) {\n element = props.plot;\n } else if (isSpecProps(props)) {\n const ast = await parseSpec(props.spec);\n if (cancelled) return;\n const options = props.params ? {params: props.params} : undefined;\n element = (await astToDOM(ast, options)).element;\n } else {\n element = document.createElement('div');\n element.innerHTML = 'Error: Invalid props provided to VgPlotChart';\n }\n if (!cancelled) {\n containerRef.current?.replaceChildren(element);\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [props]);\n\n return <div ref={containerRef} />;\n },\n (prevProps, nextProps) => {\n if (isPlotProps(prevProps) && isPlotProps(nextProps)) {\n return prevProps.plot === nextProps.plot;\n }\n if (isSpecProps(prevProps) && isSpecProps(nextProps)) {\n const specEqual =\n JSON.stringify(prevProps.spec) === JSON.stringify(nextProps.spec);\n const paramsEqual = prevProps.params === nextProps.params;\n return specEqual && paramsEqual;\n }\n return false;\n },\n);\n\nVgPlotChart.displayName = 'VgPlotChart';\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Spec } from '@uwdata/mosaic-spec';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { ChartBuilderColumn, ChartBuilderTemplate } from './types';
|
|
4
|
+
export interface ChartBuilderContentProps {
|
|
5
|
+
/** Table name to use in generated specs */
|
|
6
|
+
tableName: string;
|
|
7
|
+
/** Available columns for field selectors */
|
|
8
|
+
columns: ChartBuilderColumn[];
|
|
9
|
+
/** Callback when a chart spec is created */
|
|
10
|
+
onCreateChart: (spec: Spec, title: string) => void;
|
|
11
|
+
/** Custom builders (defaults to all built-in builders) */
|
|
12
|
+
builders?: ChartBuilderTemplate[];
|
|
13
|
+
/** Custom class name */
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Standalone chart builder UI for creating Mosaic charts from templates.
|
|
18
|
+
*
|
|
19
|
+
* Step 1: Select a chart type from the grid
|
|
20
|
+
* Step 2: Fill in field selectors
|
|
21
|
+
* Step 3: Confirm to generate spec
|
|
22
|
+
*
|
|
23
|
+
* Can be used directly without a dialog wrapper.
|
|
24
|
+
*/
|
|
25
|
+
export declare const ChartBuilderContent: React.FC<ChartBuilderContentProps>;
|
|
26
|
+
//# sourceMappingURL=ChartBuilderContent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartBuilderContent.d.ts","sourceRoot":"","sources":["../../src/chart-builders/ChartBuilderContent.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAuC,MAAM,OAAO,CAAC;AAG5D,OAAO,EAAC,kBAAkB,EAAE,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,4CAA4C;IAC5C,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAClC,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA4GlE,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, cn } from '@sqlrooms/ui';
|
|
3
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
4
|
+
import { createDefaultChartBuilders } from './builders';
|
|
5
|
+
import { FieldSelectorInput } from './FieldSelectorInput';
|
|
6
|
+
/**
|
|
7
|
+
* Standalone chart builder UI for creating Mosaic charts from templates.
|
|
8
|
+
*
|
|
9
|
+
* Step 1: Select a chart type from the grid
|
|
10
|
+
* Step 2: Fill in field selectors
|
|
11
|
+
* Step 3: Confirm to generate spec
|
|
12
|
+
*
|
|
13
|
+
* Can be used directly without a dialog wrapper.
|
|
14
|
+
*/
|
|
15
|
+
export const ChartBuilderContent = ({ tableName, columns, onCreateChart, builders, className, }) => {
|
|
16
|
+
const resolvedBuilders = useMemo(() => builders ?? createDefaultChartBuilders(), [builders]);
|
|
17
|
+
const [selectedBuilder, setSelectedBuilder] = useState(null);
|
|
18
|
+
const [fieldValues, setFieldValues] = useState({});
|
|
19
|
+
const handleReset = useCallback(() => {
|
|
20
|
+
setSelectedBuilder(null);
|
|
21
|
+
setFieldValues({});
|
|
22
|
+
}, []);
|
|
23
|
+
const handleSelectBuilder = useCallback((builder) => {
|
|
24
|
+
setSelectedBuilder(builder);
|
|
25
|
+
setFieldValues({});
|
|
26
|
+
}, []);
|
|
27
|
+
const handleFieldChange = useCallback((key, value) => {
|
|
28
|
+
setFieldValues((prev) => ({ ...prev, [key]: value }));
|
|
29
|
+
}, []);
|
|
30
|
+
const canCreate = useMemo(() => {
|
|
31
|
+
if (!selectedBuilder)
|
|
32
|
+
return false;
|
|
33
|
+
return selectedBuilder.fields
|
|
34
|
+
.filter((f) => f.required ?? true)
|
|
35
|
+
.every((f) => fieldValues[f.key]);
|
|
36
|
+
}, [selectedBuilder, fieldValues]);
|
|
37
|
+
const handleCreate = useCallback(() => {
|
|
38
|
+
if (!selectedBuilder || !canCreate)
|
|
39
|
+
return;
|
|
40
|
+
const spec = selectedBuilder.createSpec(tableName, fieldValues);
|
|
41
|
+
const title = selectedBuilder.fields.length > 0
|
|
42
|
+
? `${selectedBuilder.description.replace(/^Create (a |an )?/, '')} - ${Object.values(fieldValues).join(', ')}`
|
|
43
|
+
: selectedBuilder.description.replace(/^Create (a |an )?/, '');
|
|
44
|
+
onCreateChart(spec, title);
|
|
45
|
+
handleReset();
|
|
46
|
+
}, [
|
|
47
|
+
selectedBuilder,
|
|
48
|
+
canCreate,
|
|
49
|
+
tableName,
|
|
50
|
+
fieldValues,
|
|
51
|
+
onCreateChart,
|
|
52
|
+
handleReset,
|
|
53
|
+
]);
|
|
54
|
+
return (_jsxs("div", { className: cn('flex flex-col gap-2', className), children: [!selectedBuilder ? (_jsx("div", { className: "grid grid-cols-2 gap-2 py-2", children: resolvedBuilders.map((builder) => {
|
|
55
|
+
const Icon = builder.icon;
|
|
56
|
+
return (_jsxs("button", { className: cn('flex items-center gap-3 rounded-md border p-3 text-left transition-colors', 'hover:bg-accent hover:text-accent-foreground'), onClick: () => handleSelectBuilder(builder), children: [_jsx(Icon, { className: "h-5 w-5 shrink-0 opacity-70" }), _jsx("span", { className: "text-sm", children: builder.description })] }, builder.id));
|
|
57
|
+
}) })) : (_jsx("div", { className: "flex flex-col gap-4 py-2", children: selectedBuilder.fields.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "This chart type has no configurable fields. A template spec will be created that you can edit manually." })) : (selectedBuilder.fields.map((field) => (_jsx(FieldSelectorInput, { field: field, columns: columns, value: fieldValues[field.key], onChange: (v) => handleFieldChange(field.key, v) }, field.key)))) })), selectedBuilder && (_jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: handleReset, children: "Back" }), _jsx(Button, { size: "sm", onClick: handleCreate, disabled: !canCreate, children: "Create" })] }))] }));
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=ChartBuilderContent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartBuilderContent.js","sourceRoot":"","sources":["../../src/chart-builders/ChartBuilderContent.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Button, cn} from '@sqlrooms/ui';\nimport type {Spec} from '@uwdata/mosaic-spec';\nimport React, {useCallback, useMemo, useState} from 'react';\nimport {createDefaultChartBuilders} from './builders';\nimport {FieldSelectorInput} from './FieldSelectorInput';\nimport {ChartBuilderColumn, ChartBuilderTemplate} from './types';\n\nexport interface ChartBuilderContentProps {\n /** Table name to use in generated specs */\n tableName: string;\n /** Available columns for field selectors */\n columns: ChartBuilderColumn[];\n /** Callback when a chart spec is created */\n onCreateChart: (spec: Spec, title: string) => void;\n /** Custom builders (defaults to all built-in builders) */\n builders?: ChartBuilderTemplate[];\n /** Custom class name */\n className?: string;\n}\n\n/**\n * Standalone chart builder UI for creating Mosaic charts from templates.\n *\n * Step 1: Select a chart type from the grid\n * Step 2: Fill in field selectors\n * Step 3: Confirm to generate spec\n *\n * Can be used directly without a dialog wrapper.\n */\nexport const ChartBuilderContent: React.FC<ChartBuilderContentProps> = ({\n tableName,\n columns,\n onCreateChart,\n builders,\n className,\n}) => {\n const resolvedBuilders = useMemo(\n () => builders ?? createDefaultChartBuilders(),\n [builders],\n );\n const [selectedBuilder, setSelectedBuilder] =\n useState<ChartBuilderTemplate | null>(null);\n const [fieldValues, setFieldValues] = useState<Record<string, string>>({});\n\n const handleReset = useCallback(() => {\n setSelectedBuilder(null);\n setFieldValues({});\n }, []);\n\n const handleSelectBuilder = useCallback((builder: ChartBuilderTemplate) => {\n setSelectedBuilder(builder);\n setFieldValues({});\n }, []);\n\n const handleFieldChange = useCallback((key: string, value: string) => {\n setFieldValues((prev) => ({...prev, [key]: value}));\n }, []);\n\n const canCreate = useMemo(() => {\n if (!selectedBuilder) return false;\n return selectedBuilder.fields\n .filter((f) => f.required ?? true)\n .every((f) => fieldValues[f.key]);\n }, [selectedBuilder, fieldValues]);\n\n const handleCreate = useCallback(() => {\n if (!selectedBuilder || !canCreate) return;\n const spec = selectedBuilder.createSpec(tableName, fieldValues);\n const title =\n selectedBuilder.fields.length > 0\n ? `${selectedBuilder.description.replace(/^Create (a |an )?/, '')} - ${Object.values(fieldValues).join(', ')}`\n : selectedBuilder.description.replace(/^Create (a |an )?/, '');\n onCreateChart(spec, title);\n handleReset();\n }, [\n selectedBuilder,\n canCreate,\n tableName,\n fieldValues,\n onCreateChart,\n handleReset,\n ]);\n\n return (\n <div className={cn('flex flex-col gap-2', className)}>\n {!selectedBuilder ? (\n <div className=\"grid grid-cols-2 gap-2 py-2\">\n {resolvedBuilders.map((builder) => {\n const Icon = builder.icon;\n return (\n <button\n key={builder.id}\n className={cn(\n 'flex items-center gap-3 rounded-md border p-3 text-left transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n )}\n onClick={() => handleSelectBuilder(builder)}\n >\n <Icon className=\"h-5 w-5 shrink-0 opacity-70\" />\n <span className=\"text-sm\">{builder.description}</span>\n </button>\n );\n })}\n </div>\n ) : (\n <div className=\"flex flex-col gap-4 py-2\">\n {selectedBuilder.fields.length === 0 ? (\n <p className=\"text-muted-foreground text-sm\">\n This chart type has no configurable fields. A template spec will\n be created that you can edit manually.\n </p>\n ) : (\n selectedBuilder.fields.map((field) => (\n <FieldSelectorInput\n key={field.key}\n field={field}\n columns={columns}\n value={fieldValues[field.key]}\n onChange={(v) => handleFieldChange(field.key, v)}\n />\n ))\n )}\n </div>\n )}\n\n {selectedBuilder && (\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={handleReset}>\n Back\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={!canCreate}>\n Create\n </Button>\n </div>\n )}\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Spec } from '@uwdata/mosaic-spec';
|
|
2
|
+
import type { ChartBuilderColumn, ChartBuilderTemplate } from './types';
|
|
3
|
+
export type ChartBuilderContextValue = {
|
|
4
|
+
tableName: string;
|
|
5
|
+
columns: ChartBuilderColumn[];
|
|
6
|
+
onCreateChart: (spec: Spec, title: string) => void;
|
|
7
|
+
builders?: ChartBuilderTemplate[];
|
|
8
|
+
};
|
|
9
|
+
export declare const ChartBuilderContext: import("react").Context<ChartBuilderContextValue | null>;
|
|
10
|
+
export declare function useChartBuilderContext(): ChartBuilderContextValue;
|
|
11
|
+
//# sourceMappingURL=ChartBuilderContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartBuilderContext.d.ts","sourceRoot":"","sources":["../../src/chart-builders/ChartBuilderContext.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,EAAC,kBAAkB,EAAE,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAEtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,mBAAmB,0DACsB,CAAC;AAEvD,wBAAgB,sBAAsB,IAAI,wBAAwB,CAQjE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
export const ChartBuilderContext = createContext(null);
|
|
3
|
+
export function useChartBuilderContext() {
|
|
4
|
+
const ctx = useContext(ChartBuilderContext);
|
|
5
|
+
if (!ctx) {
|
|
6
|
+
throw new Error('ChartBuilder compound components must be rendered inside <MosaicChartBuilder>.');
|
|
7
|
+
}
|
|
8
|
+
return ctx;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=ChartBuilderContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartBuilderContext.js","sourceRoot":"","sources":["../../src/chart-builders/ChartBuilderContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,OAAO,CAAC;AAWhD,MAAM,CAAC,MAAM,mBAAmB,GAC9B,aAAa,CAAkC,IAAI,CAAC,CAAC;AAEvD,MAAM,UAAU,sBAAsB;IACpC,MAAM,GAAG,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,gFAAgF,CACjF,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["import {createContext, useContext} from 'react';\nimport type {Spec} from '@uwdata/mosaic-spec';\nimport type {ChartBuilderColumn, ChartBuilderTemplate} from './types';\n\nexport type ChartBuilderContextValue = {\n tableName: string;\n columns: ChartBuilderColumn[];\n onCreateChart: (spec: Spec, title: string) => void;\n builders?: ChartBuilderTemplate[];\n};\n\nexport const ChartBuilderContext =\n createContext<ChartBuilderContextValue | null>(null);\n\nexport function useChartBuilderContext(): ChartBuilderContextValue {\n const ctx = useContext(ChartBuilderContext);\n if (!ctx) {\n throw new Error(\n 'ChartBuilder compound components must be rendered inside <MosaicChartBuilder>.',\n );\n }\n return ctx;\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Spec } from '@uwdata/mosaic-spec';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { ChartBuilderColumn, ChartBuilderTemplate } from './types';
|
|
4
|
+
export interface ChartBuilderDialogProps {
|
|
5
|
+
/** Whether the dialog is open */
|
|
6
|
+
open: boolean;
|
|
7
|
+
/** Callback when dialog open state changes */
|
|
8
|
+
onOpenChange: (open: boolean) => void;
|
|
9
|
+
/** Table name to use in generated specs */
|
|
10
|
+
tableName: string;
|
|
11
|
+
/** Available columns for field selectors */
|
|
12
|
+
columns: ChartBuilderColumn[];
|
|
13
|
+
/** Callback when a chart spec is created */
|
|
14
|
+
onCreateChart: (spec: Spec, title: string) => void;
|
|
15
|
+
/** Custom builders (defaults to all built-in builders) */
|
|
16
|
+
builders?: ChartBuilderTemplate[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Dialog wrapper for the chart builder.
|
|
20
|
+
* For a non-dialog version, use MosaicChartBuilder.Content directly.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ChartBuilderDialog: React.FC<ChartBuilderDialogProps>;
|
|
23
|
+
//# sourceMappingURL=ChartBuilderDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartBuilderDialog.d.ts","sourceRoot":"","sources":["../../src/chart-builders/ChartBuilderDialog.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAC,kBAAkB,EAAE,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAEjE,MAAM,WAAW,uBAAuB;IACtC,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,4CAA4C;IAC5C,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA6BhE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@sqlrooms/ui';
|
|
3
|
+
import { ChartBuilderContent } from './ChartBuilderContent';
|
|
4
|
+
/**
|
|
5
|
+
* Dialog wrapper for the chart builder.
|
|
6
|
+
* For a non-dialog version, use MosaicChartBuilder.Content directly.
|
|
7
|
+
*/
|
|
8
|
+
export const ChartBuilderDialog = ({ open, onOpenChange, tableName, columns, onCreateChart, builders, }) => {
|
|
9
|
+
const handleCreateChart = (spec, title) => {
|
|
10
|
+
onCreateChart(spec, title);
|
|
11
|
+
onOpenChange(false);
|
|
12
|
+
};
|
|
13
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Add Chart" }), _jsx(DialogDescription, { children: "Select a chart type to create." })] }), _jsx(ChartBuilderContent, { tableName: tableName, columns: columns, onCreateChart: handleCreateChart, builders: builders })] }) }));
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=ChartBuilderDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartBuilderDialog.js","sourceRoot":"","sources":["../../src/chart-builders/ChartBuilderDialog.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAkB1D;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAsC,CAAC,EACpE,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,OAAO,EACP,aAAa,EACb,QAAQ,GACT,EAAE,EAAE;IACH,MAAM,iBAAiB,GAAG,CAAC,IAAU,EAAE,KAAa,EAAE,EAAE;QACtD,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3B,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,YAC5C,MAAC,aAAa,IAAC,SAAS,EAAC,aAAa,aACpC,MAAC,YAAY,eACX,KAAC,WAAW,4BAAwB,EACpC,KAAC,iBAAiB,iDAAmD,IACxD,EACf,KAAC,mBAAmB,IAClB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,iBAAiB,EAChC,QAAQ,EAAE,QAAQ,GAClB,IACY,GACT,CACV,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@sqlrooms/ui';\nimport type {Spec} from '@uwdata/mosaic-spec';\nimport React from 'react';\nimport {ChartBuilderContent} from './ChartBuilderContent';\nimport {ChartBuilderColumn, ChartBuilderTemplate} from './types';\n\nexport interface ChartBuilderDialogProps {\n /** Whether the dialog is open */\n open: boolean;\n /** Callback when dialog open state changes */\n onOpenChange: (open: boolean) => void;\n /** Table name to use in generated specs */\n tableName: string;\n /** Available columns for field selectors */\n columns: ChartBuilderColumn[];\n /** Callback when a chart spec is created */\n onCreateChart: (spec: Spec, title: string) => void;\n /** Custom builders (defaults to all built-in builders) */\n builders?: ChartBuilderTemplate[];\n}\n\n/**\n * Dialog wrapper for the chart builder.\n * For a non-dialog version, use MosaicChartBuilder.Content directly.\n */\nexport const ChartBuilderDialog: React.FC<ChartBuilderDialogProps> = ({\n open,\n onOpenChange,\n tableName,\n columns,\n onCreateChart,\n builders,\n}) => {\n const handleCreateChart = (spec: Spec, title: string) => {\n onCreateChart(spec, title);\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-lg\">\n <DialogHeader>\n <DialogTitle>Add Chart</DialogTitle>\n <DialogDescription>Select a chart type to create.</DialogDescription>\n </DialogHeader>\n <ChartBuilderContent\n tableName={tableName}\n columns={columns}\n onCreateChart={handleCreateChart}\n builders={builders}\n />\n </DialogContent>\n </Dialog>\n );\n};\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ChartBuilderColumn, ChartBuilderField } from './types';
|
|
3
|
+
export interface FieldSelectorInputProps {
|
|
4
|
+
field: ChartBuilderField;
|
|
5
|
+
columns: ChartBuilderColumn[];
|
|
6
|
+
value: string | undefined;
|
|
7
|
+
onChange: (value: string) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A searchable dropdown selector for choosing a table column for a chart builder field.
|
|
11
|
+
*/
|
|
12
|
+
export declare const FieldSelectorInput: React.FC<FieldSelectorInputProps>;
|
|
13
|
+
//# sourceMappingURL=FieldSelectorInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FieldSelectorInput.d.ts","sourceRoot":"","sources":["../../src/chart-builders/FieldSelectorInput.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAiB,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,SAAS,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,iBAAiB,CAAC;IACzB,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA+EhE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, cn, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Popover, PopoverContent, PopoverTrigger, } from '@sqlrooms/ui';
|
|
3
|
+
import { Check, ChevronsUpDown } from 'lucide-react';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
/**
|
|
6
|
+
* A searchable dropdown selector for choosing a table column for a chart builder field.
|
|
7
|
+
*/
|
|
8
|
+
export const FieldSelectorInput = ({ field, columns, value, onChange, }) => {
|
|
9
|
+
const [open, setOpen] = useState(false);
|
|
10
|
+
const filteredColumns = field.types
|
|
11
|
+
? columns.filter((col) => field.types.some((t) => col.type.toUpperCase() === t.toUpperCase()))
|
|
12
|
+
: columns;
|
|
13
|
+
const selectedColumn = filteredColumns.find((col) => col.name === value);
|
|
14
|
+
return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("label", { className: "text-sm font-medium", children: [field.label, field.required && _jsx("span", { className: "text-destructive ml-1", children: "*" })] }), _jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", role: "combobox", "aria-expanded": open, className: "w-full justify-between font-normal", children: [selectedColumn ? (_jsxs("span", { className: "flex items-center gap-2 truncate", children: [_jsx("span", { className: "truncate", children: selectedColumn.name }), _jsx("span", { className: "text-muted-foreground text-xs", children: selectedColumn.type })] })) : (_jsxs("span", { className: "text-muted-foreground", children: ["Select ", field.label.toLowerCase(), "..."] })), _jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-[--radix-popover-trigger-width] p-0", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: `Search columns...` }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: "No matching column." }), _jsx(CommandGroup, { children: filteredColumns.map((col) => (_jsxs(CommandItem, { value: col.name, onSelect: (currentValue) => {
|
|
15
|
+
onChange(currentValue);
|
|
16
|
+
setOpen(false);
|
|
17
|
+
}, children: [_jsx(Check, { className: cn('mr-2 h-4 w-4 shrink-0', value === col.name ? 'opacity-100' : 'opacity-0') }), _jsx("span", { className: "truncate", children: col.name }), _jsx("span", { className: "text-muted-foreground ml-auto text-xs", children: col.type })] }, col.name))) })] })] }) })] })] }));
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=FieldSelectorInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FieldSelectorInput.js","sourceRoot":"","sources":["../../src/chart-builders/FieldSelectorInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Button,\n cn,\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} from 'lucide-react';\nimport React, {useState} from 'react';\nimport {ChartBuilderColumn, ChartBuilderField} from './types';\n\nexport interface FieldSelectorInputProps {\n field: ChartBuilderField;\n columns: ChartBuilderColumn[];\n value: string | undefined;\n onChange: (value: string) => void;\n}\n\n/**\n * A searchable dropdown selector for choosing a table column for a chart builder field.\n */\nexport const FieldSelectorInput: React.FC<FieldSelectorInputProps> = ({\n field,\n columns,\n value,\n onChange,\n}) => {\n const [open, setOpen] = useState(false);\n\n const filteredColumns = field.types\n ? columns.filter((col) =>\n field.types!.some((t) => col.type.toUpperCase() === t.toUpperCase()),\n )\n : columns;\n\n const selectedColumn = filteredColumns.find((col) => col.name === value);\n\n return (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-sm font-medium\">\n {field.label}\n {field.required && <span className=\"text-destructive ml-1\">*</span>}\n </label>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n className=\"w-full justify-between font-normal\"\n >\n {selectedColumn ? (\n <span className=\"flex items-center gap-2 truncate\">\n <span className=\"truncate\">{selectedColumn.name}</span>\n <span className=\"text-muted-foreground text-xs\">\n {selectedColumn.type}\n </span>\n </span>\n ) : (\n <span className=\"text-muted-foreground\">\n Select {field.label.toLowerCase()}...\n </span>\n )}\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[--radix-popover-trigger-width] p-0\">\n <Command>\n <CommandInput placeholder={`Search columns...`} />\n <CommandList>\n <CommandEmpty>No matching column.</CommandEmpty>\n <CommandGroup>\n {filteredColumns.map((col) => (\n <CommandItem\n key={col.name}\n value={col.name}\n onSelect={(currentValue) => {\n onChange(currentValue);\n setOpen(false);\n }}\n >\n <Check\n className={cn(\n 'mr-2 h-4 w-4 shrink-0',\n value === col.name ? 'opacity-100' : 'opacity-0',\n )}\n />\n <span className=\"truncate\">{col.name}</span>\n <span className=\"text-muted-foreground ml-auto text-xs\">\n {col.type}\n </span>\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ChartBuilderTemplate } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the default set of chart builders.
|
|
4
|
+
* Call this to get a fresh array that you can extend or filter.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createDefaultChartBuilders(): ChartBuilderTemplate[];
|
|
7
|
+
//# sourceMappingURL=builders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../../src/chart-builders/builders.ts"],"names":[],"mappings":"AAWA,OAAO,EAAC,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAyR7C;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,oBAAoB,EAAE,CAWnE"}
|