@data360/mcp-viz-core 0.0.1

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 ADDED
@@ -0,0 +1,20 @@
1
+ # @data360/mcp-viz-core
2
+
3
+ Framework-agnostic TypeScript utilities for Data360 MCP **Vega-Lite** tool output: the same `prepareSpec` / `parseSpec` pipeline and World Bank theme used by [`@data360/mcp-ui`](../mcp-ui) (React) and [`@data360/mcp-ui-angular`](../mcp-ui-angular) (Angular).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @data360/mcp-viz-core
9
+ ```
10
+
11
+ ## API
12
+
13
+ - **`prepareSpec(spec, chartHeight?)`** — eight-guard pipeline (inline datasets, responsive sizing, WB theme merge, axis rules, etc.). See [`packages/mcp-ui` README](../mcp-ui/README.md) for the full list.
14
+ - **`parseSpec(spec, palette)`** — legend metadata from the **raw** spec (before `prepareSpec`).
15
+ - **`getMark(spec)`**, **`WB_THEME`**, **`WB_PALETTE`**, **`WB_THEME_URL`**
16
+ - Types: **`VLSpec`**, **`Annotation`**, **`VegaChartCardBaseProps`**, etc.
17
+
18
+ ## Version coupling
19
+
20
+ When the MCP server or [`@data360/tool-types`](../tool-types) changes viz JSON shape or Vega-Lite conventions, bump **`@data360/mcp-viz-core`** together with **`@data360/mcp-ui`** and **`@data360/mcp-ui-angular`** so all consumers stay aligned.
@@ -0,0 +1,4 @@
1
+ export type { Annotation, MarkType, VegaChartCardBaseProps, VLEncoding, VLSpec, } from "./types";
2
+ export { WB_PALETTE, WB_THEME, WB_THEME_URL, type WBTheme, } from "./wb-theme";
3
+ export { getMark, parseSpec, prepareSpec, type ParsedSpec, } from "./prepare-spec";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,QAAQ,EACR,sBAAsB,EACtB,UAAU,EACV,MAAM,GACP,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,KAAK,OAAO,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,OAAO,EACP,SAAS,EACT,WAAW,EACX,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { WB_PALETTE, WB_THEME, WB_THEME_URL, } from "./wb-theme";
2
+ export { getMark, parseSpec, prepareSpec, } from "./prepare-spec";
@@ -0,0 +1,31 @@
1
+ import type { MarkType, VLSpec } from "./types";
2
+ export declare function getMark(spec: VLSpec): MarkType;
3
+ /**
4
+ * Applies the 8-guard pipeline to make any Data360 Vega-Lite spec compatible
5
+ * with the VegaChartCard component and the WB visual theme.
6
+ *
7
+ * Guards:
8
+ * 1. Inline named dataset → data.values
9
+ * 2. Responsive sizing (width: "container", configurable height)
10
+ * 3. Suppress built-in legend (card renders its own)
11
+ * 3b. Remove top-level title (card header shows it; avoids duplicating Vega’s title)
12
+ * 4. Strip zoom/pan params (conflicts with card controls)
13
+ * 5. Normalize $schema v6 → v5 (vega-embed 6 compatibility)
14
+ * 6. Merge WB theme into config
15
+ * 7. scale.zero — false for line/area/point/tick, true for bar
16
+ * 8. x-axis format — %Y only for temporal; dropped for ordinal/nominal
17
+ */
18
+ export declare function prepareSpec(spec: VLSpec, chartHeight?: number): VLSpec;
19
+ export interface ParsedSpec {
20
+ rows: Record<string, unknown>[];
21
+ colorField: string | null;
22
+ specTitle: string | null;
23
+ distinctGroups: string[];
24
+ colorMap: Record<string, string>;
25
+ }
26
+ /**
27
+ * Extract legend metadata from a raw (un-prepared) spec.
28
+ * Call this once on the original spec, not the prepared one.
29
+ */
30
+ export declare function parseSpec(spec: VLSpec, palette: string[]): ParsedSpec;
31
+ //# sourceMappingURL=prepare-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-spec.d.ts","sourceRoot":"","sources":["../src/prepare-spec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIhD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAG9C;AAwBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,SAAM,GAAG,MAAM,CAkDnE;AAID,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,UAAU,CAuBrE"}
@@ -0,0 +1,105 @@
1
+ import { WB_THEME } from "./wb-theme";
2
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
3
+ export function getMark(spec) {
4
+ if (!spec.mark)
5
+ return "line";
6
+ return typeof spec.mark === "string" ? spec.mark : (spec.mark.type ?? "line");
7
+ }
8
+ /** Resolve spec.datasets[spec.data.name] → spec.data.values */
9
+ function inlineDataset(spec) {
10
+ const name = spec.data?.name;
11
+ if (name && spec.datasets?.[name]) {
12
+ return { ...spec, data: { values: spec.datasets[name] }, datasets: undefined };
13
+ }
14
+ return spec;
15
+ }
16
+ /** Deep-merge WB theme into spec.config. Spec config values win on conflict. */
17
+ function mergeConfig(specConfig, theme) {
18
+ const base = JSON.parse(JSON.stringify(theme));
19
+ if (!specConfig)
20
+ return base;
21
+ // Shallow-merge top-level keys — spec overrides theme
22
+ return { ...base, ...specConfig };
23
+ }
24
+ // ─── prepareSpec ─────────────────────────────────────────────────────────────
25
+ /**
26
+ * Applies the 8-guard pipeline to make any Data360 Vega-Lite spec compatible
27
+ * with the VegaChartCard component and the WB visual theme.
28
+ *
29
+ * Guards:
30
+ * 1. Inline named dataset → data.values
31
+ * 2. Responsive sizing (width: "container", configurable height)
32
+ * 3. Suppress built-in legend (card renders its own)
33
+ * 3b. Remove top-level title (card header shows it; avoids duplicating Vega’s title)
34
+ * 4. Strip zoom/pan params (conflicts with card controls)
35
+ * 5. Normalize $schema v6 → v5 (vega-embed 6 compatibility)
36
+ * 6. Merge WB theme into config
37
+ * 7. scale.zero — false for line/area/point/tick, true for bar
38
+ * 8. x-axis format — %Y only for temporal; dropped for ordinal/nominal
39
+ */
40
+ export function prepareSpec(spec, chartHeight = 260) {
41
+ let out = JSON.parse(JSON.stringify(spec));
42
+ const markType = getMark(out);
43
+ // 1. Inline named dataset
44
+ out = inlineDataset(out);
45
+ // 2. Responsive sizing
46
+ out.width = "container";
47
+ out.height = chartHeight;
48
+ // 3. Suppress built-in legend — card renders its own
49
+ if (out.encoding?.color) {
50
+ out.encoding.color.legend = null;
51
+ }
52
+ // 3b. Title is displayed by VegaChartCard (prop / parseSpec); strip from the embedded spec
53
+ delete out.title;
54
+ // 4. Strip zoom/pan params — conflicts with card controls
55
+ delete out.params;
56
+ // 5. Normalize $schema v6 → v5
57
+ out.$schema = "https://vega.github.io/schema/vega-lite/v5.json";
58
+ // 6. Merge WB theme
59
+ out.config = mergeConfig(out.config, WB_THEME);
60
+ // 7. scale.zero — bars must start at zero; everything else benefits from false
61
+ if (out.encoding?.y) {
62
+ if (!out.encoding.y.scale)
63
+ out.encoding.y.scale = {};
64
+ out.encoding.y.scale.zero = markType === "bar";
65
+ }
66
+ // 8. x-axis format — only apply %Y for temporal x
67
+ if (out.encoding?.x) {
68
+ const xType = out.encoding.x.type;
69
+ if (!out.encoding.x.axis)
70
+ out.encoding.x.axis = {};
71
+ const axis = out.encoding.x.axis;
72
+ if (xType === "temporal") {
73
+ axis.format = "%Y";
74
+ axis.title = null;
75
+ }
76
+ else {
77
+ // ordinal / nominal (bar with year strings, tick with country on x)
78
+ delete axis.format;
79
+ axis.title = null;
80
+ }
81
+ }
82
+ return out;
83
+ }
84
+ /**
85
+ * Extract legend metadata from a raw (un-prepared) spec.
86
+ * Call this once on the original spec, not the prepared one.
87
+ */
88
+ export function parseSpec(spec, palette) {
89
+ const name = spec.data?.name;
90
+ const rows = name && spec.datasets?.[name]
91
+ ? spec.datasets[name]
92
+ : (spec.data?.values ?? []);
93
+ const colorField = spec.encoding?.color?.field ?? null;
94
+ const specTitle = typeof spec.title === "string"
95
+ ? spec.title
96
+ : spec.title?.text ?? null;
97
+ const distinctGroups = colorField
98
+ ? [...new Set(rows.map((r) => String(r[colorField])))]
99
+ : [];
100
+ const colorMap = {};
101
+ distinctGroups.forEach((g, i) => {
102
+ colorMap[g] = palette[i % palette.length];
103
+ });
104
+ return { rows, colorField, specTitle, distinctGroups, colorMap };
105
+ }
@@ -0,0 +1,91 @@
1
+ export type MarkType = "line" | "bar" | "point" | "area" | "tick";
2
+ export interface VLEncoding {
3
+ field?: string;
4
+ type?: "temporal" | "quantitative" | "nominal" | "ordinal";
5
+ axis?: Record<string, unknown>;
6
+ scale?: Record<string, unknown>;
7
+ legend?: Record<string, unknown> | null;
8
+ timeUnit?: string;
9
+ [key: string]: unknown;
10
+ }
11
+ export interface VLSpec {
12
+ $schema?: string;
13
+ title?: string | {
14
+ text: string;
15
+ [key: string]: unknown;
16
+ };
17
+ data?: {
18
+ name?: string;
19
+ values?: Record<string, unknown>[];
20
+ };
21
+ datasets?: Record<string, Record<string, unknown>[]>;
22
+ mark?: MarkType | {
23
+ type: MarkType;
24
+ [key: string]: unknown;
25
+ };
26
+ encoding?: {
27
+ x?: VLEncoding;
28
+ y?: VLEncoding;
29
+ color?: VLEncoding;
30
+ tooltip?: VLEncoding[];
31
+ [key: string]: unknown;
32
+ };
33
+ params?: unknown[];
34
+ config?: Record<string, unknown>;
35
+ width?: number | string;
36
+ height?: number | string;
37
+ [key: string]: unknown;
38
+ }
39
+ export interface Annotation {
40
+ /** The circled number shown next to the callout. */
41
+ id: number;
42
+ /** The italic callout text. */
43
+ text: string;
44
+ }
45
+ /**
46
+ * Props shared by React and Angular chart card implementations.
47
+ * React adds `railTopSlot`; Angular may use a projected content slot instead.
48
+ */
49
+ export interface VegaChartCardBaseProps {
50
+ /**
51
+ * A valid Vega-Lite spec. Passed through the prepareSpec() pipeline before
52
+ * rendering — named datasets are inlined, WB theme applied, and mark-aware
53
+ * axis/scale guards run automatically.
54
+ */
55
+ spec: VLSpec;
56
+ /**
57
+ * Card title. If omitted, falls back to spec.title.
58
+ */
59
+ title?: string;
60
+ /**
61
+ * Secondary line shown below the title (e.g. "Brazil, India · 2018–2022").
62
+ */
63
+ subtitle?: string;
64
+ /**
65
+ * Attribution line shown below the chart area.
66
+ */
67
+ source?: string;
68
+ /**
69
+ * Numbered callout annotations shown below the chart.
70
+ * Hidden when the user toggles "Show annotations" off.
71
+ */
72
+ annotations?: Annotation[];
73
+ /**
74
+ * Card height in pixels. Defaults to 260.
75
+ */
76
+ chartHeight?: number;
77
+ /**
78
+ * Called when "Download data" is clicked.
79
+ * Receives the raw filtered rows currently visible in the chart.
80
+ * Defaults to a CSV download if omitted.
81
+ */
82
+ onDownload?: (rows: Record<string, unknown>[]) => void;
83
+ /**
84
+ * Called when the PNG export button is clicked.
85
+ * Receives the PNG data URL. Defaults to a file download if omitted.
86
+ */
87
+ onExport?: (dataUrl: string) => void;
88
+ /** Extra class name applied to the outer card div. */
89
+ className?: string;
90
+ }
91
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,UAAU,GAAG,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,MAAM;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1D,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;KAAE,CAAC;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACrD,IAAI,CAAC,EAAE,QAAQ,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC7D,QAAQ,CAAC,EAAE;QACT,CAAC,CAAC,EAAE,UAAU,CAAC;QACf,CAAC,CAAC,EAAE,UAAU,CAAC;QACf,KAAK,CAAC,EAAE,UAAU,CAAC;QACnB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;QACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAE3B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC;IAEvD;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ // ─── Vega-Lite spec (minimal typed surface) ───────────────────────────────────
2
+ export {};
@@ -0,0 +1,84 @@
1
+ export declare const WB_THEME_URL = "https://worldbank.github.io/data-visualization-style-guide/vega/wb-vega-theme.json";
2
+ export declare const WB_THEME: {
3
+ readonly background: "#ffffff";
4
+ readonly view: {
5
+ readonly stroke: null;
6
+ };
7
+ readonly arc: {
8
+ readonly fill: "#34A7F2";
9
+ };
10
+ readonly area: {
11
+ readonly fill: "#34A7F2";
12
+ };
13
+ readonly line: {
14
+ readonly stroke: "#34A7F2";
15
+ readonly strokeCap: "round";
16
+ readonly strokeJoin: "round";
17
+ };
18
+ readonly rect: {
19
+ readonly fill: "#34A7F2";
20
+ };
21
+ readonly point: {
22
+ readonly filled: true;
23
+ readonly stroke: "white";
24
+ readonly strokeWidth: 1;
25
+ };
26
+ readonly title: {
27
+ readonly font: "Open Sans, Arial, sans-serif";
28
+ readonly subtitleFont: "Open Sans, Arial, sans-serif";
29
+ readonly anchor: "start";
30
+ readonly fontSize: 18;
31
+ readonly fontWeight: 600;
32
+ readonly offset: 20;
33
+ readonly subtitleFontSize: 15;
34
+ readonly subtitleColor: "#666666";
35
+ readonly subtitlePadding: 6;
36
+ };
37
+ readonly axis: {
38
+ readonly titleFont: "Open Sans, Arial, sans-serif";
39
+ readonly titleFontSize: 13;
40
+ readonly titleFontWeight: 600;
41
+ readonly labelFont: "Open Sans, Arial, sans-serif";
42
+ readonly labelColor: "#666666";
43
+ readonly labelFontSize: 13;
44
+ readonly gridWidth: 1;
45
+ readonly tickColor: "#CED4DE";
46
+ readonly tickWidth: 0.2;
47
+ readonly titleColor: "#111111";
48
+ readonly gridDash: readonly [4, 2];
49
+ readonly gridColor: "#CED4DE";
50
+ readonly labelPadding: 6;
51
+ readonly labelOverlap: true;
52
+ readonly labelFlush: false;
53
+ };
54
+ readonly axisBand: {
55
+ readonly grid: false;
56
+ };
57
+ readonly axisX: {
58
+ readonly grid: true;
59
+ readonly tickSize: 0;
60
+ readonly domain: false;
61
+ };
62
+ readonly axisY: {
63
+ readonly domain: false;
64
+ readonly grid: true;
65
+ readonly tickSize: 0;
66
+ };
67
+ readonly legend: {
68
+ readonly labelFont: "Open Sans, Arial, sans-serif";
69
+ readonly titleFont: "Open Sans, Arial, sans-serif";
70
+ readonly titleFontSize: 15;
71
+ readonly labelFontSize: 13;
72
+ readonly labelColor: "#111111";
73
+ readonly padding: 1;
74
+ readonly symbolSize: 140;
75
+ readonly orient: "bottom";
76
+ readonly direction: "horizontal";
77
+ };
78
+ readonly range: {
79
+ readonly category: readonly ["#34A7F2", "#FF9800", "#664AB6", "#4EC2C0", "#F3578E", "#081079", "#0C7C68"];
80
+ };
81
+ };
82
+ export type WBTheme = typeof WB_THEME;
83
+ export declare const WB_PALETTE: string[];
84
+ //# sourceMappingURL=wb-theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wb-theme.d.ts","sourceRoot":"","sources":["../src/wb-theme.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,uFAC6D,CAAC;AAEvF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DX,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC;AACtC,eAAO,MAAM,UAAU,EAAyC,MAAM,EAAE,CAAC"}
@@ -0,0 +1,64 @@
1
+ export const WB_THEME_URL = "https://worldbank.github.io/data-visualization-style-guide/vega/wb-vega-theme.json";
2
+ export const WB_THEME = {
3
+ background: "#ffffff",
4
+ view: { stroke: null },
5
+ arc: { fill: "#34A7F2" },
6
+ area: { fill: "#34A7F2" },
7
+ line: { stroke: "#34A7F2", strokeCap: "round", strokeJoin: "round" },
8
+ rect: { fill: "#34A7F2" },
9
+ point: { filled: true, stroke: "white", strokeWidth: 1 },
10
+ title: {
11
+ font: "Open Sans, Arial, sans-serif",
12
+ subtitleFont: "Open Sans, Arial, sans-serif",
13
+ anchor: "start",
14
+ fontSize: 18,
15
+ fontWeight: 600,
16
+ offset: 20,
17
+ subtitleFontSize: 15,
18
+ subtitleColor: "#666666",
19
+ subtitlePadding: 6,
20
+ },
21
+ axis: {
22
+ titleFont: "Open Sans, Arial, sans-serif",
23
+ titleFontSize: 13,
24
+ titleFontWeight: 600,
25
+ labelFont: "Open Sans, Arial, sans-serif",
26
+ labelColor: "#666666",
27
+ labelFontSize: 13,
28
+ gridWidth: 1,
29
+ tickColor: "#CED4DE",
30
+ tickWidth: 0.2,
31
+ titleColor: "#111111",
32
+ gridDash: [4, 2],
33
+ gridColor: "#CED4DE",
34
+ labelPadding: 6,
35
+ labelOverlap: true,
36
+ labelFlush: false,
37
+ },
38
+ axisBand: { grid: false },
39
+ axisX: { grid: true, tickSize: 0, domain: false },
40
+ axisY: { domain: false, grid: true, tickSize: 0 },
41
+ legend: {
42
+ labelFont: "Open Sans, Arial, sans-serif",
43
+ titleFont: "Open Sans, Arial, sans-serif",
44
+ titleFontSize: 15,
45
+ labelFontSize: 13,
46
+ labelColor: "#111111",
47
+ padding: 1,
48
+ symbolSize: 140,
49
+ orient: "bottom",
50
+ direction: "horizontal",
51
+ },
52
+ range: {
53
+ category: [
54
+ "#34A7F2",
55
+ "#FF9800",
56
+ "#664AB6",
57
+ "#4EC2C0",
58
+ "#F3578E",
59
+ "#081079",
60
+ "#0C7C68",
61
+ ],
62
+ },
63
+ };
64
+ export const WB_PALETTE = WB_THEME.range.category;
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@data360/mcp-viz-core",
3
+ "version": "0.0.1",
4
+ "description": "Framework-agnostic Vega-Lite prep and World Bank theme for Data360 MCP viz tools.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "tsc"
19
+ },
20
+ "devDependencies": {
21
+ "typescript": "^5.5.0"
22
+ },
23
+ "keywords": [
24
+ "data360",
25
+ "mcp",
26
+ "vega-lite",
27
+ "world-bank"
28
+ ],
29
+ "license": "MIT",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/worldbank/data360-mcp"
36
+ }
37
+ }