@sqlrooms/vega 0.24.20 → 0.24.22
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/dist/VegaChartToolResult.d.ts.map +1 -1
- package/dist/VegaChartToolResult.js +3 -2
- package/dist/VegaChartToolResult.js.map +1 -1
- package/dist/VegaLiteChart.d.ts +32 -52
- package/dist/VegaLiteChart.d.ts.map +1 -1
- package/dist/VegaLiteChart.js +50 -10
- package/dist/VegaLiteChart.js.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VegaChartToolResult.d.ts","sourceRoot":"","sources":["../src/VegaChartToolResult.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VegaChartToolResult.d.ts","sourceRoot":"","sources":["../src/VegaChartToolResult.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAC,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAG7C,KAAK,wBAAwB,GAAG;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,iBAAiB,CAAC;CACjC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,QAAQ,EACR,YAAY,GACb,EAAE,wBAAwB,2CAgC1B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { QueryToolResult } from '@sqlrooms/ai';
|
|
3
|
+
import { useSql } from '@sqlrooms/duckdb';
|
|
3
4
|
import { cn } from '@sqlrooms/ui';
|
|
4
|
-
import { Suspense } from 'react';
|
|
5
5
|
import { VegaLiteChart } from './VegaLiteChart';
|
|
6
6
|
/**
|
|
7
7
|
* Renders a chart tool call with visualization using Vega-Lite
|
|
@@ -9,6 +9,7 @@ import { VegaLiteChart } from './VegaLiteChart';
|
|
|
9
9
|
* @returns {JSX.Element} The rendered chart tool call
|
|
10
10
|
*/
|
|
11
11
|
export function VegaChartToolResult({ className, sqlQuery, vegaLiteSpec, }) {
|
|
12
|
-
|
|
12
|
+
const result = useSql({ query: sqlQuery });
|
|
13
|
+
return (_jsx(_Fragment, { children: vegaLiteSpec && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(QueryToolResult, { title: "", arrowTable: result.data?.arrowTable, sqlQuery: sqlQuery }), result.error ? (_jsx("div", { className: "whitespace-pre-wrap font-mono text-sm text-red-500", children: result.error?.message })) : result.isLoading ? (_jsxs("div", { className: "text-muted-foreground align-center flex gap-2 px-2", children: [_jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-blue-600" }), "Running query for chart data\u2026"] })) : (_jsx(VegaLiteChart.ArrowChart, { className: cn('max-w-[600px]', className), aspectRatio: 16 / 9, arrowTable: result.data?.arrowTable, spec: vegaLiteSpec }))] })) }));
|
|
13
14
|
}
|
|
14
15
|
//# sourceMappingURL=VegaChartToolResult.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VegaChartToolResult.js","sourceRoot":"","sources":["../src/VegaChartToolResult.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"VegaChartToolResult.js","sourceRoot":"","sources":["../src/VegaChartToolResult.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAGhC,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAS9C;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAClC,SAAS,EACT,QAAQ,EACR,YAAY,GACa;IACzB,MAAM,MAAM,GAAG,MAAM,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAC,CAAC,CAAC;IACzC,OAAO,CACL,4BACG,YAAY,IAAI,CACf,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,eAAe,IACd,KAAK,EAAC,EAAE,EACR,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EACnC,QAAQ,EAAE,QAAQ,GAClB,EACD,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CACd,cAAK,SAAS,EAAC,oDAAoD,YAChE,MAAM,CAAC,KAAK,EAAE,OAAO,GAClB,CACP,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CACrB,eAAK,SAAS,EAAC,oDAAoD,aACjE,cAAK,SAAS,EAAC,8EAA8E,GAAO,0CAEhG,CACP,CAAC,CAAC,CAAC,CACF,KAAC,aAAa,CAAC,UAAU,IACvB,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,SAAS,CAAC,EACzC,WAAW,EAAE,EAAE,GAAG,CAAC,EACnB,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EACnC,IAAI,EAAE,YAAY,GAClB,CACH,IACG,CACP,GACA,CACJ,CAAC;AACJ,CAAC","sourcesContent":["import {QueryToolResult} from '@sqlrooms/ai';\nimport {useSql} from '@sqlrooms/duckdb';\nimport {cn} from '@sqlrooms/ui';\nimport {Suspense} from 'react';\nimport {VisualizationSpec} from 'react-vega';\nimport {VegaLiteChart} from './VegaLiteChart';\n\ntype VegaChartToolResultProps = {\n className?: string;\n reasoning: string;\n sqlQuery: string;\n vegaLiteSpec: VisualizationSpec;\n};\n\n/**\n * Renders a chart tool call with visualization using Vega-Lite\n * @param {VegaChartToolResultProps} props - The component props\n * @returns {JSX.Element} The rendered chart tool call\n */\nexport function VegaChartToolResult({\n className,\n sqlQuery,\n vegaLiteSpec,\n}: VegaChartToolResultProps) {\n const result = useSql({query: sqlQuery});\n return (\n <>\n {vegaLiteSpec && (\n <div className=\"flex flex-col gap-2\">\n <QueryToolResult\n title=\"\"\n arrowTable={result.data?.arrowTable}\n sqlQuery={sqlQuery}\n />\n {result.error ? (\n <div className=\"whitespace-pre-wrap font-mono text-sm text-red-500\">\n {result.error?.message}\n </div>\n ) : result.isLoading ? (\n <div className=\"text-muted-foreground align-center flex gap-2 px-2\">\n <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-blue-600\"></div>\n Running query for chart data…\n </div>\n ) : (\n <VegaLiteChart.ArrowChart\n className={cn('max-w-[600px]', className)}\n aspectRatio={16 / 9}\n arrowTable={result.data?.arrowTable}\n spec={vegaLiteSpec}\n />\n )}\n </div>\n )}\n </>\n );\n}\n"]}
|
package/dist/VegaLiteChart.d.ts
CHANGED
|
@@ -1,60 +1,40 @@
|
|
|
1
|
+
import * as arrow from 'apache-arrow';
|
|
1
2
|
import { VisualizationSpec } from 'react-vega';
|
|
2
|
-
|
|
3
|
-
* A component that renders a Vega-Lite chart with SQL data and responsive sizing.
|
|
4
|
-
*
|
|
5
|
-
* The chart can be sized in multiple ways:
|
|
6
|
-
* - Fixed dimensions: Provide both width and height as numbers
|
|
7
|
-
* - Fixed width, proportional height: Provide width as number, height as 'auto'
|
|
8
|
-
* - Fixed height, proportional width: Provide height as number, width as 'auto'
|
|
9
|
-
* - Fully responsive: Leave both as 'auto' (default), chart will fill container while maintaining aspect ratio
|
|
10
|
-
*
|
|
11
|
-
* @param props - The component props
|
|
12
|
-
* @param {number | 'auto'} [props.width='auto'] - The chart width in pixels, or 'auto' to use container width
|
|
13
|
-
* @param {number | 'auto'} [props.height='auto'] - The chart height in pixels, or 'auto' to calculate from aspect ratio
|
|
14
|
-
* @param {number} [props.aspectRatio=3/2] - The desired width-to-height ratio when dimensions are auto-calculated
|
|
15
|
-
* @param {string} props.sqlQuery - The SQL query to fetch data for the chart
|
|
16
|
-
* @param {string | VisualizationSpec} props.spec - The Vega-Lite specification for the chart.
|
|
17
|
-
* Can be either a JSON string or a VisualizationSpec object.
|
|
18
|
-
* The data and size properties will be overridden by the component.
|
|
19
|
-
*
|
|
20
|
-
* @returns The rendered chart component
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* // Fixed size chart
|
|
24
|
-
* <VegaLiteChart
|
|
25
|
-
* width={600}
|
|
26
|
-
* height={400}
|
|
27
|
-
* sqlQuery="SELECT category, count(*) as count FROM sales GROUP BY category"
|
|
28
|
-
* spec={{
|
|
29
|
-
* mark: 'bar',
|
|
30
|
-
* encoding: {
|
|
31
|
-
* x: {field: 'category', type: 'nominal'},
|
|
32
|
-
* y: {field: 'count', type: 'quantitative'}
|
|
33
|
-
* }
|
|
34
|
-
* }}
|
|
35
|
-
* />
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* // Responsive chart with 16:9 aspect ratio
|
|
39
|
-
* <VegaLiteChart
|
|
40
|
-
* className="max-w-[600px]"
|
|
41
|
-
* aspectRatio={16/9}
|
|
42
|
-
* sqlQuery="SELECT date, value FROM metrics"
|
|
43
|
-
* spec={{
|
|
44
|
-
* mark: 'line',
|
|
45
|
-
* encoding: {
|
|
46
|
-
* x: {field: 'date', type: 'temporal'},
|
|
47
|
-
* y: {field: 'value', type: 'quantitative'}
|
|
48
|
-
* }
|
|
49
|
-
* }}
|
|
50
|
-
* />
|
|
51
|
-
*/
|
|
52
|
-
export declare const VegaLiteChart: React.FC<{
|
|
3
|
+
export declare const ArrowChart: React.FC<{
|
|
53
4
|
className?: string;
|
|
54
5
|
width?: number | 'auto';
|
|
55
6
|
height?: number | 'auto';
|
|
56
7
|
aspectRatio?: number;
|
|
57
|
-
sqlQuery: string;
|
|
58
8
|
spec: string | VisualizationSpec;
|
|
9
|
+
arrowTable: arrow.Table | undefined;
|
|
10
|
+
dataName?: string;
|
|
59
11
|
}>;
|
|
12
|
+
export declare const VegaLiteChart: import("react").FC<{
|
|
13
|
+
className?: string;
|
|
14
|
+
width?: number | "auto";
|
|
15
|
+
height?: number | "auto";
|
|
16
|
+
aspectRatio?: number;
|
|
17
|
+
sqlQuery: string;
|
|
18
|
+
spec: string | VisualizationSpec;
|
|
19
|
+
dataName?: string;
|
|
20
|
+
}> & {
|
|
21
|
+
SqlChart: import("react").FC<{
|
|
22
|
+
className?: string;
|
|
23
|
+
width?: number | "auto";
|
|
24
|
+
height?: number | "auto";
|
|
25
|
+
aspectRatio?: number;
|
|
26
|
+
sqlQuery: string;
|
|
27
|
+
spec: string | VisualizationSpec;
|
|
28
|
+
dataName?: string;
|
|
29
|
+
}>;
|
|
30
|
+
ArrowChart: import("react").FC<{
|
|
31
|
+
className?: string;
|
|
32
|
+
width?: number | "auto";
|
|
33
|
+
height?: number | "auto";
|
|
34
|
+
aspectRatio?: number;
|
|
35
|
+
spec: string | VisualizationSpec;
|
|
36
|
+
arrowTable: arrow.Table | undefined;
|
|
37
|
+
dataName?: string;
|
|
38
|
+
}>;
|
|
39
|
+
};
|
|
60
40
|
//# sourceMappingURL=VegaLiteChart.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VegaLiteChart.d.ts","sourceRoot":"","sources":["../src/VegaLiteChart.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VegaLiteChart.d.ts","sourceRoot":"","sources":["../src/VegaLiteChart.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAW,iBAAiB,EAAC,MAAM,YAAY,CAAC;AA2HvD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACjC,UAAU,EAAE,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAwEA,CAAC;AAEF,eAAO,MAAM,aAAa;gBAtJZ,MAAM;YACV,MAAM,GAAG,MAAM;aACd,MAAM,GAAG,MAAM;kBACV,MAAM;cACV,MAAM;UACV,MAAM,GAAG,iBAAiB;eACrB,MAAM;;;oBANL,MAAM;gBACV,MAAM,GAAG,MAAM;iBACd,MAAM,GAAG,MAAM;sBACV,MAAM;kBACV,MAAM;cACV,MAAM,GAAG,iBAAiB;mBACrB,MAAM;;;oBA+DL,MAAM;gBACV,MAAM,GAAG,MAAM;iBACd,MAAM,GAAG,MAAM;sBACV,MAAM;cACd,MAAM,GAAG,iBAAiB;oBACpB,KAAK,CAAC,KAAK,GAAG,SAAS;mBACxB,MAAM;;CA8EjB,CAAC"}
|
package/dist/VegaLiteChart.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ToolErrorMessage } from '@sqlrooms/ai';
|
|
3
|
+
import { arrowTableToJson, useSql } from '@sqlrooms/duckdb';
|
|
4
|
+
import { AspectRatio, cn, useAspectRatioDimensions, } from '@sqlrooms/ui';
|
|
4
5
|
import { safeJsonParse } from '@sqlrooms/utils';
|
|
5
|
-
import { useMemo, useRef } from 'react';
|
|
6
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
6
7
|
import { VegaLite } from 'react-vega';
|
|
7
|
-
const
|
|
8
|
+
const DEFAULT_DATA_NAME = 'queryResult';
|
|
8
9
|
/**
|
|
9
10
|
* A component that renders a Vega-Lite chart with SQL data and responsive sizing.
|
|
10
11
|
*
|
|
@@ -55,7 +56,7 @@ const DATA_NAME = 'queryResult';
|
|
|
55
56
|
* }}
|
|
56
57
|
* />
|
|
57
58
|
*/
|
|
58
|
-
|
|
59
|
+
const VegaLiteSqlChart = ({ className, width = 'auto', height = 'auto', aspectRatio = 3 / 2, sqlQuery, spec, dataName = DEFAULT_DATA_NAME, }) => {
|
|
59
60
|
const containerRef = useRef(null);
|
|
60
61
|
const dimensions = useAspectRatioDimensions({
|
|
61
62
|
containerRef,
|
|
@@ -69,7 +70,7 @@ export const VegaLiteChart = ({ className, width = 'auto', height = 'auto', aspe
|
|
|
69
70
|
return null;
|
|
70
71
|
return {
|
|
71
72
|
...parsed,
|
|
72
|
-
data: { name:
|
|
73
|
+
data: { name: dataName },
|
|
73
74
|
width: dimensions.width,
|
|
74
75
|
height: dimensions.height,
|
|
75
76
|
autosize: {
|
|
@@ -79,11 +80,50 @@ export const VegaLiteChart = ({ className, width = 'auto', height = 'auto', aspe
|
|
|
79
80
|
};
|
|
80
81
|
}, [spec, dimensions]);
|
|
81
82
|
const result = useSql({ query: sqlQuery });
|
|
83
|
+
const arrowTable = result.data?.arrowTable;
|
|
84
|
+
return (_jsxs("div", { ref: containerRef, className: cn('flex h-full w-full flex-col gap-2 overflow-hidden', className), children: [result.error && (_jsx("div", { className: "whitespace-pre-wrap font-mono text-sm text-red-500", children: result.error.message })), result.isLoading ? (_jsxs("div", { className: "text-muted-foreground align-center flex gap-2 px-2", children: [_jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-blue-600" }), "Running query for chart data\u2026"] })) : (refinedSpec &&
|
|
85
|
+
arrowTable && _jsx(ArrowChart, { spec: refinedSpec, arrowTable: arrowTable }))] }));
|
|
86
|
+
};
|
|
87
|
+
export const ArrowChart = ({ className, width = 'auto', height = 'auto', aspectRatio = 3 / 2, spec, arrowTable, dataName = DEFAULT_DATA_NAME, }) => {
|
|
88
|
+
const containerRef = useRef(null);
|
|
89
|
+
const [chartError, setChartError] = useState(null);
|
|
90
|
+
const dimensions = useAspectRatioDimensions({
|
|
91
|
+
containerRef,
|
|
92
|
+
width,
|
|
93
|
+
height,
|
|
94
|
+
aspectRatio,
|
|
95
|
+
});
|
|
96
|
+
const refinedSpec = useMemo(() => {
|
|
97
|
+
const parsed = typeof spec === 'string' ? safeJsonParse(spec) : spec;
|
|
98
|
+
if (!parsed) {
|
|
99
|
+
setChartError(new Error('Invalid Vega-Lite specification'));
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...parsed,
|
|
104
|
+
data: { name: dataName },
|
|
105
|
+
width: dimensions.width,
|
|
106
|
+
height: dimensions.height,
|
|
107
|
+
autosize: {
|
|
108
|
+
type: 'fit',
|
|
109
|
+
contains: 'padding',
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}, [spec, dimensions]);
|
|
82
113
|
const data = useMemo(() => {
|
|
83
|
-
if (!
|
|
114
|
+
if (!arrowTable)
|
|
84
115
|
return null;
|
|
85
|
-
return {
|
|
86
|
-
}, [
|
|
87
|
-
|
|
116
|
+
return { queryResult: arrowTableToJson(arrowTable) };
|
|
117
|
+
}, [arrowTable]);
|
|
118
|
+
// Reset chart error whenever spec or data changes
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
setChartError(null);
|
|
121
|
+
}, [spec, data]);
|
|
122
|
+
return (_jsx("div", { ref: containerRef, className: cn('flex h-full w-full flex-col gap-2 overflow-hidden', className), children: chartError ? (_jsx(ToolErrorMessage, { error: chartError, triggerLabel: "Chart rendering failed", title: "Chart error", align: "start", details: spec })) : (refinedSpec &&
|
|
123
|
+
data && (_jsx(AspectRatio, { ratio: aspectRatio, children: _jsx(VegaLite, { spec: refinedSpec, data: data, onError: setChartError }) }))) }));
|
|
88
124
|
};
|
|
125
|
+
export const VegaLiteChart = Object.assign(VegaLiteSqlChart, {
|
|
126
|
+
SqlChart: VegaLiteSqlChart,
|
|
127
|
+
ArrowChart: ArrowChart,
|
|
128
|
+
});
|
|
89
129
|
//# sourceMappingURL=VegaLiteChart.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VegaLiteChart.js","sourceRoot":"","sources":["../src/VegaLiteChart.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAC,WAAW,EAAE,EAAE,EAAE,wBAAwB,EAAC,MAAM,cAAc,CAAC;AACvE,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,OAAO,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAEvD,MAAM,SAAS,GAAG,aAAa,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,CAAC,MAAM,aAAa,GAOrB,CAAC,EACJ,SAAS,EACT,KAAK,GAAG,MAAM,EACd,MAAM,GAAG,MAAM,EACf,WAAW,GAAG,CAAC,GAAG,CAAC,EACnB,QAAQ,EACR,IAAI,GACL,EAAE,EAAE;IACH,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,wBAAwB,CAAC;QAC1C,YAAY;QACZ,KAAK;QACL,MAAM;QACN,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/B,MAAM,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrE,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO;YACL,GAAG,MAAM;YACT,IAAI,EAAE,EAAC,IAAI,EAAE,SAAS,EAAC;YACvB,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE;gBACR,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,SAAS;aACpB;SACmB,CAAC;IACzB,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IAEvB,MAAM,MAAM,GAAG,MAAM,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAC,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;QACxB,IAAI,CAAC,MAAM,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAC9B,OAAO,EAAC,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,EAAC,CAAC;IAC9C,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAElB,OAAO,CACL,eACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,EAAE,CACX,mDAAmD,EACnD,SAAS,CACV,aAEA,MAAM,CAAC,KAAK,IAAI,CACf,cAAK,SAAS,EAAC,oDAAoD,YAChE,MAAM,CAAC,KAAK,CAAC,OAAO,GACjB,CACP,EACD,KAAC,WAAW,IAAC,KAAK,EAAE,WAAW,YAC5B,WAAW,IAAI,IAAI,IAAI,KAAC,QAAQ,IAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,GAAI,GACvD,IACV,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {useSql} from '@sqlrooms/duckdb';\nimport {AspectRatio, cn, useAspectRatioDimensions} from '@sqlrooms/ui';\nimport {safeJsonParse} from '@sqlrooms/utils';\nimport {useMemo, useRef} from 'react';\nimport {VegaLite, VisualizationSpec} from 'react-vega';\n\nconst DATA_NAME = 'queryResult';\n\n/**\n * A component that renders a Vega-Lite chart with SQL data and responsive sizing.\n *\n * The chart can be sized in multiple ways:\n * - Fixed dimensions: Provide both width and height as numbers\n * - Fixed width, proportional height: Provide width as number, height as 'auto'\n * - Fixed height, proportional width: Provide height as number, width as 'auto'\n * - Fully responsive: Leave both as 'auto' (default), chart will fill container while maintaining aspect ratio\n *\n * @param props - The component props\n * @param {number | 'auto'} [props.width='auto'] - The chart width in pixels, or 'auto' to use container width\n * @param {number | 'auto'} [props.height='auto'] - The chart height in pixels, or 'auto' to calculate from aspect ratio\n * @param {number} [props.aspectRatio=3/2] - The desired width-to-height ratio when dimensions are auto-calculated\n * @param {string} props.sqlQuery - The SQL query to fetch data for the chart\n * @param {string | VisualizationSpec} props.spec - The Vega-Lite specification for the chart.\n * Can be either a JSON string or a VisualizationSpec object.\n * The data and size properties will be overridden by the component.\n *\n * @returns The rendered chart component\n *\n * @example\n * // Fixed size chart\n * <VegaLiteChart\n * width={600}\n * height={400}\n * sqlQuery=\"SELECT category, count(*) as count FROM sales GROUP BY category\"\n * spec={{\n * mark: 'bar',\n * encoding: {\n * x: {field: 'category', type: 'nominal'},\n * y: {field: 'count', type: 'quantitative'}\n * }\n * }}\n * />\n *\n * @example\n * // Responsive chart with 16:9 aspect ratio\n * <VegaLiteChart\n * className=\"max-w-[600px]\"\n * aspectRatio={16/9}\n * sqlQuery=\"SELECT date, value FROM metrics\"\n * spec={{\n * mark: 'line',\n * encoding: {\n * x: {field: 'date', type: 'temporal'},\n * y: {field: 'value', type: 'quantitative'}\n * }\n * }}\n * />\n */\nexport const VegaLiteChart: React.FC<{\n className?: string;\n width?: number | 'auto';\n height?: number | 'auto';\n aspectRatio?: number;\n sqlQuery: string;\n spec: string | VisualizationSpec;\n}> = ({\n className,\n width = 'auto',\n height = 'auto',\n aspectRatio = 3 / 2,\n sqlQuery,\n spec,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const dimensions = useAspectRatioDimensions({\n containerRef,\n width,\n height,\n aspectRatio,\n });\n\n const refinedSpec = useMemo(() => {\n const parsed = typeof spec === 'string' ? safeJsonParse(spec) : spec;\n if (!parsed) return null;\n return {\n ...parsed,\n data: {name: DATA_NAME},\n width: dimensions.width,\n height: dimensions.height,\n autosize: {\n type: 'fit',\n contains: 'padding',\n },\n } as VisualizationSpec;\n }, [spec, dimensions]);\n\n const result = useSql({query: sqlQuery});\n const data = useMemo(() => {\n if (!result.data) return null;\n return {[DATA_NAME]: result.data.toArray()};\n }, [result.data]);\n\n return (\n <div\n ref={containerRef}\n className={cn(\n 'flex h-full w-full flex-col gap-2 overflow-hidden',\n className,\n )}\n >\n {result.error && (\n <div className=\"whitespace-pre-wrap font-mono text-sm text-red-500\">\n {result.error.message}\n </div>\n )}\n <AspectRatio ratio={aspectRatio}>\n {refinedSpec && data && <VegaLite spec={refinedSpec} data={data} />}\n </AspectRatio>\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"VegaLiteChart.js","sourceRoot":"","sources":["../src/VegaLiteChart.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAC,gBAAgB,EAAE,MAAM,EAAC,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EACL,WAAW,EAEX,EAAE,EAIF,wBAAwB,GACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAG9C,OAAO,EAAC,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAC,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAEvD,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,gBAAgB,GAQjB,CAAC,EACJ,SAAS,EACT,KAAK,GAAG,MAAM,EACd,MAAM,GAAG,MAAM,EACf,WAAW,GAAG,CAAC,GAAG,CAAC,EACnB,QAAQ,EACR,IAAI,EACJ,QAAQ,GAAG,iBAAiB,GAC7B,EAAE,EAAE;IACH,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,wBAAwB,CAAC;QAC1C,YAAY;QACZ,KAAK;QACL,MAAM;QACN,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/B,MAAM,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrE,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO;YACL,GAAG,MAAM;YACT,IAAI,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC;YACtB,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE;gBACR,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,SAAS;aACpB;SACmB,CAAC;IACzB,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IAEvB,MAAM,MAAM,GAAG,MAAM,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAC,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC;IAE3C,OAAO,CACL,eACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,EAAE,CACX,mDAAmD,EACnD,SAAS,CACV,aAEA,MAAM,CAAC,KAAK,IAAI,CACf,cAAK,SAAS,EAAC,oDAAoD,YAChE,MAAM,CAAC,KAAK,CAAC,OAAO,GACjB,CACP,EACA,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAClB,eAAK,SAAS,EAAC,oDAAoD,aACjE,cAAK,SAAS,EAAC,8EAA8E,GAAO,0CAEhG,CACP,CAAC,CAAC,CAAC,CACF,WAAW;gBACX,UAAU,IAAI,KAAC,UAAU,IAAC,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,GAAI,CACxE,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAQlB,CAAC,EACJ,SAAS,EACT,KAAK,GAAG,MAAM,EACd,MAAM,GAAG,MAAM,EACf,WAAW,GAAG,CAAC,GAAG,CAAC,EACnB,IAAI,EACJ,UAAU,EACV,QAAQ,GAAG,iBAAiB,GAC7B,EAAE,EAAE;IACH,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,wBAAwB,CAAC;QAC1C,YAAY;QACZ,KAAK;QACL,MAAM;QACN,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/B,MAAM,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,aAAa,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO;YACL,GAAG,MAAM;YACT,IAAI,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC;YACtB,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE;gBACR,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,SAAS;aACpB;SACmB,CAAC;IACzB,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IAEvB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;QACxB,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAC7B,OAAO,EAAC,WAAW,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAC,CAAC;IACrD,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,kDAAkD;IAClD,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAEjB,OAAO,CACL,cACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,EAAE,CACX,mDAAmD,EACnD,SAAS,CACV,YAEA,UAAU,CAAC,CAAC,CAAC,CACZ,KAAC,gBAAgB,IACf,KAAK,EAAE,UAAU,EACjB,YAAY,EAAC,wBAAwB,EACrC,KAAK,EAAC,aAAa,EACnB,KAAK,EAAC,OAAO,EACb,OAAO,EAAE,IAAI,GACb,CACH,CAAC,CAAC,CAAC,CACF,WAAW;YACX,IAAI,IAAI,CACN,KAAC,WAAW,IAAC,KAAK,EAAE,WAAW,YAC7B,KAAC,QAAQ,IAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,GAAI,GACvD,CACf,CACF,GACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE;IAC3D,QAAQ,EAAE,gBAAgB;IAC1B,UAAU,EAAE,UAAU;CACvB,CAAC,CAAC","sourcesContent":["import {ToolErrorMessage} from '@sqlrooms/ai';\nimport {arrowTableToJson, useSql} from '@sqlrooms/duckdb';\nimport {\n AspectRatio,\n Button,\n cn,\n Popover,\n PopoverContent,\n PopoverTrigger,\n useAspectRatioDimensions,\n} from '@sqlrooms/ui';\nimport {safeJsonParse} from '@sqlrooms/utils';\nimport * as arrow from 'apache-arrow';\nimport {TriangleAlertIcon} from 'lucide-react';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {VegaLite, VisualizationSpec} from 'react-vega';\n\nconst DEFAULT_DATA_NAME = 'queryResult';\n\n/**\n * A component that renders a Vega-Lite chart with SQL data and responsive sizing.\n *\n * The chart can be sized in multiple ways:\n * - Fixed dimensions: Provide both width and height as numbers\n * - Fixed width, proportional height: Provide width as number, height as 'auto'\n * - Fixed height, proportional width: Provide height as number, width as 'auto'\n * - Fully responsive: Leave both as 'auto' (default), chart will fill container while maintaining aspect ratio\n *\n * @param props - The component props\n * @param {number | 'auto'} [props.width='auto'] - The chart width in pixels, or 'auto' to use container width\n * @param {number | 'auto'} [props.height='auto'] - The chart height in pixels, or 'auto' to calculate from aspect ratio\n * @param {number} [props.aspectRatio=3/2] - The desired width-to-height ratio when dimensions are auto-calculated\n * @param {string} props.sqlQuery - The SQL query to fetch data for the chart\n * @param {string | VisualizationSpec} props.spec - The Vega-Lite specification for the chart.\n * Can be either a JSON string or a VisualizationSpec object.\n * The data and size properties will be overridden by the component.\n *\n * @returns The rendered chart component\n *\n * @example\n * // Fixed size chart\n * <VegaLiteChart\n * width={600}\n * height={400}\n * sqlQuery=\"SELECT category, count(*) as count FROM sales GROUP BY category\"\n * spec={{\n * mark: 'bar',\n * encoding: {\n * x: {field: 'category', type: 'nominal'},\n * y: {field: 'count', type: 'quantitative'}\n * }\n * }}\n * />\n *\n * @example\n * // Responsive chart with 16:9 aspect ratio\n * <VegaLiteChart\n * className=\"max-w-[600px]\"\n * aspectRatio={16/9}\n * sqlQuery=\"SELECT date, value FROM metrics\"\n * spec={{\n * mark: 'line',\n * encoding: {\n * x: {field: 'date', type: 'temporal'},\n * y: {field: 'value', type: 'quantitative'}\n * }\n * }}\n * />\n */\nconst VegaLiteSqlChart: React.FC<{\n className?: string;\n width?: number | 'auto';\n height?: number | 'auto';\n aspectRatio?: number;\n sqlQuery: string;\n spec: string | VisualizationSpec;\n dataName?: string;\n}> = ({\n className,\n width = 'auto',\n height = 'auto',\n aspectRatio = 3 / 2,\n sqlQuery,\n spec,\n dataName = DEFAULT_DATA_NAME,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const dimensions = useAspectRatioDimensions({\n containerRef,\n width,\n height,\n aspectRatio,\n });\n\n const refinedSpec = useMemo(() => {\n const parsed = typeof spec === 'string' ? safeJsonParse(spec) : spec;\n if (!parsed) return null;\n return {\n ...parsed,\n data: {name: dataName},\n width: dimensions.width,\n height: dimensions.height,\n autosize: {\n type: 'fit',\n contains: 'padding',\n },\n } as VisualizationSpec;\n }, [spec, dimensions]);\n\n const result = useSql({query: sqlQuery});\n const arrowTable = result.data?.arrowTable;\n\n return (\n <div\n ref={containerRef}\n className={cn(\n 'flex h-full w-full flex-col gap-2 overflow-hidden',\n className,\n )}\n >\n {result.error && (\n <div className=\"whitespace-pre-wrap font-mono text-sm text-red-500\">\n {result.error.message}\n </div>\n )}\n {result.isLoading ? (\n <div className=\"text-muted-foreground align-center flex gap-2 px-2\">\n <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-blue-600\"></div>\n Running query for chart data…\n </div>\n ) : (\n refinedSpec &&\n arrowTable && <ArrowChart spec={refinedSpec} arrowTable={arrowTable} />\n )}\n </div>\n );\n};\n\nexport const ArrowChart: React.FC<{\n className?: string;\n width?: number | 'auto';\n height?: number | 'auto';\n aspectRatio?: number;\n spec: string | VisualizationSpec;\n arrowTable: arrow.Table | undefined;\n dataName?: string;\n}> = ({\n className,\n width = 'auto',\n height = 'auto',\n aspectRatio = 3 / 2,\n spec,\n arrowTable,\n dataName = DEFAULT_DATA_NAME,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [chartError, setChartError] = useState<Error | null>(null);\n const dimensions = useAspectRatioDimensions({\n containerRef,\n width,\n height,\n aspectRatio,\n });\n\n const refinedSpec = useMemo(() => {\n const parsed = typeof spec === 'string' ? safeJsonParse(spec) : spec;\n if (!parsed) {\n setChartError(new Error('Invalid Vega-Lite specification'));\n return null;\n }\n return {\n ...parsed,\n data: {name: dataName},\n width: dimensions.width,\n height: dimensions.height,\n autosize: {\n type: 'fit',\n contains: 'padding',\n },\n } as VisualizationSpec;\n }, [spec, dimensions]);\n\n const data = useMemo(() => {\n if (!arrowTable) return null;\n return {queryResult: arrowTableToJson(arrowTable)};\n }, [arrowTable]);\n\n // Reset chart error whenever spec or data changes\n useEffect(() => {\n setChartError(null);\n }, [spec, data]);\n\n return (\n <div\n ref={containerRef}\n className={cn(\n 'flex h-full w-full flex-col gap-2 overflow-hidden',\n className,\n )}\n >\n {chartError ? (\n <ToolErrorMessage\n error={chartError}\n triggerLabel=\"Chart rendering failed\"\n title=\"Chart error\"\n align=\"start\"\n details={spec}\n />\n ) : (\n refinedSpec &&\n data && (\n <AspectRatio ratio={aspectRatio}>\n <VegaLite spec={refinedSpec} data={data} onError={setChartError} />\n </AspectRatio>\n )\n )}\n </div>\n );\n};\n\nexport const VegaLiteChart = Object.assign(VegaLiteSqlChart, {\n SqlChart: VegaLiteSqlChart,\n ArrowChart: ArrowChart,\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sqlrooms/vega",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.22",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@openassistant/utils": "^0.5.13",
|
|
22
|
-
"@sqlrooms/ai": "0.24.
|
|
23
|
-
"@sqlrooms/duckdb": "0.24.
|
|
24
|
-
"@sqlrooms/ui": "0.24.
|
|
25
|
-
"@sqlrooms/utils": "0.24.
|
|
22
|
+
"@sqlrooms/ai": "0.24.22",
|
|
23
|
+
"@sqlrooms/duckdb": "0.24.22",
|
|
24
|
+
"@sqlrooms/ui": "0.24.22",
|
|
25
|
+
"@sqlrooms/utils": "0.24.22",
|
|
26
26
|
"react-vega": "^7.6.0",
|
|
27
27
|
"vega": "^5.33.0",
|
|
28
28
|
"vega-lite": "^5.23.0",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"typecheck": "tsc --noEmit",
|
|
40
40
|
"typedoc": "typedoc"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "bc633cde7574270b679cb6c3d9ce9b496a634133"
|
|
43
43
|
}
|