@unovis/mcp 1.7.0-mcp.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/LICENSE +193 -0
  2. package/README.md +154 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +109 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/codegen/index.d.ts +14 -0
  7. package/dist/codegen/index.js +346 -0
  8. package/dist/codegen/index.js.map +1 -0
  9. package/dist/env/bbox.d.ts +13 -0
  10. package/dist/env/bbox.js +335 -0
  11. package/dist/env/bbox.js.map +1 -0
  12. package/dist/env/canvas.d.ts +9 -0
  13. package/dist/env/canvas.js +55 -0
  14. package/dist/env/canvas.js.map +1 -0
  15. package/dist/env/computed-style.d.ts +38 -0
  16. package/dist/env/computed-style.js +186 -0
  17. package/dist/env/computed-style.js.map +1 -0
  18. package/dist/env/fonts.d.ts +3 -0
  19. package/dist/env/fonts.js +103 -0
  20. package/dist/env/fonts.js.map +1 -0
  21. package/dist/env/index.d.ts +13 -0
  22. package/dist/env/index.js +121 -0
  23. package/dist/env/index.js.map +1 -0
  24. package/dist/env/raf-queue.d.ts +23 -0
  25. package/dist/env/raf-queue.js +51 -0
  26. package/dist/env/raf-queue.js.map +1 -0
  27. package/dist/env/size.d.ts +9 -0
  28. package/dist/env/size.js +30 -0
  29. package/dist/env/size.js.map +1 -0
  30. package/dist/html/document.d.ts +16 -0
  31. package/dist/html/document.js +95 -0
  32. package/dist/html/document.js.map +1 -0
  33. package/dist/index.d.ts +25 -0
  34. package/dist/index.js +18 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/recipes/area.d.ts +66 -0
  37. package/dist/recipes/area.js +76 -0
  38. package/dist/recipes/area.js.map +1 -0
  39. package/dist/recipes/bar.d.ts +67 -0
  40. package/dist/recipes/bar.js +69 -0
  41. package/dist/recipes/bar.js.map +1 -0
  42. package/dist/recipes/boxplot.d.ts +64 -0
  43. package/dist/recipes/boxplot.js +89 -0
  44. package/dist/recipes/boxplot.js.map +1 -0
  45. package/dist/recipes/chord.d.ts +41 -0
  46. package/dist/recipes/chord.js +72 -0
  47. package/dist/recipes/chord.js.map +1 -0
  48. package/dist/recipes/choropleth-regions.d.ts +49 -0
  49. package/dist/recipes/choropleth-regions.js +521 -0
  50. package/dist/recipes/choropleth-regions.js.map +1 -0
  51. package/dist/recipes/choropleth.d.ts +27 -0
  52. package/dist/recipes/choropleth.js +86 -0
  53. package/dist/recipes/choropleth.js.map +1 -0
  54. package/dist/recipes/donut.d.ts +25 -0
  55. package/dist/recipes/donut.js +51 -0
  56. package/dist/recipes/donut.js.map +1 -0
  57. package/dist/recipes/graph.d.ts +55 -0
  58. package/dist/recipes/graph.js +132 -0
  59. package/dist/recipes/graph.js.map +1 -0
  60. package/dist/recipes/heatmap.d.ts +21 -0
  61. package/dist/recipes/heatmap.js +79 -0
  62. package/dist/recipes/heatmap.js.map +1 -0
  63. package/dist/recipes/index.d.ts +5 -0
  64. package/dist/recipes/index.js +35 -0
  65. package/dist/recipes/index.js.map +1 -0
  66. package/dist/recipes/line.d.ts +69 -0
  67. package/dist/recipes/line.js +64 -0
  68. package/dist/recipes/line.js.map +1 -0
  69. package/dist/recipes/nested-donut.d.ts +22 -0
  70. package/dist/recipes/nested-donut.js +47 -0
  71. package/dist/recipes/nested-donut.js.map +1 -0
  72. package/dist/recipes/radial-bar.d.ts +25 -0
  73. package/dist/recipes/radial-bar.js +53 -0
  74. package/dist/recipes/radial-bar.js.map +1 -0
  75. package/dist/recipes/sankey.d.ts +41 -0
  76. package/dist/recipes/sankey.js +61 -0
  77. package/dist/recipes/sankey.js.map +1 -0
  78. package/dist/recipes/scatter.d.ts +68 -0
  79. package/dist/recipes/scatter.js +75 -0
  80. package/dist/recipes/scatter.js.map +1 -0
  81. package/dist/recipes/shared.d.ts +144 -0
  82. package/dist/recipes/shared.js +212 -0
  83. package/dist/recipes/shared.js.map +1 -0
  84. package/dist/recipes/timeline.d.ts +31 -0
  85. package/dist/recipes/timeline.js +123 -0
  86. package/dist/recipes/timeline.js.map +1 -0
  87. package/dist/recipes/treemap.d.ts +19 -0
  88. package/dist/recipes/treemap.js +43 -0
  89. package/dist/recipes/treemap.js.map +1 -0
  90. package/dist/recipes/types.d.ts +16 -0
  91. package/dist/recipes/types.js +2 -0
  92. package/dist/recipes/types.js.map +1 -0
  93. package/dist/render/headless.d.ts +62 -0
  94. package/dist/render/headless.js +158 -0
  95. package/dist/render/headless.js.map +1 -0
  96. package/dist/render/materialize.d.ts +35 -0
  97. package/dist/render/materialize.js +160 -0
  98. package/dist/render/materialize.js.map +1 -0
  99. package/dist/render/mutex.d.ts +9 -0
  100. package/dist/render/mutex.js +14 -0
  101. package/dist/render/mutex.js.map +1 -0
  102. package/dist/render/rasterize.d.ts +10 -0
  103. package/dist/render/rasterize.js +29 -0
  104. package/dist/render/rasterize.js.map +1 -0
  105. package/dist/render/renderer.d.ts +21 -0
  106. package/dist/render/renderer.js +66 -0
  107. package/dist/render/renderer.js.map +1 -0
  108. package/dist/render/spec.d.ts +95 -0
  109. package/dist/render/spec.js +15 -0
  110. package/dist/render/spec.js.map +1 -0
  111. package/dist/server.d.ts +4 -0
  112. package/dist/server.js +44 -0
  113. package/dist/server.js.map +1 -0
  114. package/dist/svg/collect-css.d.ts +14 -0
  115. package/dist/svg/collect-css.js +53 -0
  116. package/dist/svg/collect-css.js.map +1 -0
  117. package/dist/svg/css-vars.d.ts +17 -0
  118. package/dist/svg/css-vars.js +64 -0
  119. package/dist/svg/css-vars.js.map +1 -0
  120. package/dist/svg/header.d.ts +8 -0
  121. package/dist/svg/header.js +81 -0
  122. package/dist/svg/header.js.map +1 -0
  123. package/dist/svg/ids.d.ts +12 -0
  124. package/dist/svg/ids.js +94 -0
  125. package/dist/svg/ids.js.map +1 -0
  126. package/dist/svg/postprocess.d.ts +41 -0
  127. package/dist/svg/postprocess.js +135 -0
  128. package/dist/svg/postprocess.js.map +1 -0
  129. package/dist/tools/register.d.ts +12 -0
  130. package/dist/tools/register.js +127 -0
  131. package/dist/tools/register.js.map +1 -0
  132. package/dist/widget/bundle.js +1777 -0
  133. package/dist/widget/bundle.meta.json +3 -0
  134. package/dist/widget/entry.d.ts +34 -0
  135. package/dist/widget/entry.js +118 -0
  136. package/dist/widget/entry.js.map +1 -0
  137. package/dist/widget/interactions.d.ts +14 -0
  138. package/dist/widget/interactions.js +151 -0
  139. package/dist/widget/interactions.js.map +1 -0
  140. package/dist/widget/unovis-slim.d.ts +33 -0
  141. package/dist/widget/unovis-slim.js +34 -0
  142. package/dist/widget/unovis-slim.js.map +1 -0
  143. package/docs/README.md +56 -0
  144. package/docs/architecture.md +158 -0
  145. package/docs/chart-spec.md +148 -0
  146. package/docs/getting-started.md +175 -0
  147. package/docs/interactive.md +125 -0
  148. package/docs/output-types.md +170 -0
  149. package/docs/programmatic.md +234 -0
  150. package/docs/tools.md +273 -0
  151. package/docs/troubleshooting.md +140 -0
  152. package/fonts/README.md +19 -0
  153. package/package.json +73 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choropleth.js","sourceRoot":"","sources":["../../src/recipes/choropleth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ import type { Recipe } from './types.js';
3
+ export declare const donutInputShape: {
4
+ width: z.ZodDefault<z.ZodNumber>;
5
+ height: z.ZodDefault<z.ZodNumber>;
6
+ theme: z.ZodDefault<z.ZodEnum<["light", "dark"]>>;
7
+ title: z.ZodOptional<z.ZodString>;
8
+ colors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ framework: z.ZodDefault<z.ZodEnum<["ts", "react", "svelte", "vue", "angular", "solid"]>>;
10
+ outputType: z.ZodDefault<z.ZodEnum<["svg", "png", "html", "interactive", "config", "code"]>>;
11
+ outputPath: z.ZodOptional<z.ZodString>;
12
+ scale: z.ZodDefault<z.ZodNumber>;
13
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
14
+ value: z.ZodString;
15
+ label: z.ZodOptional<z.ZodString>;
16
+ variant: z.ZodDefault<z.ZodEnum<["donut", "pie"]>>;
17
+ arcWidth: z.ZodOptional<z.ZodNumber>;
18
+ centralLabel: z.ZodOptional<z.ZodString>;
19
+ centralSubLabel: z.ZodOptional<z.ZodString>;
20
+ padAngle: z.ZodDefault<z.ZodNumber>;
21
+ sortDescending: z.ZodDefault<z.ZodBoolean>;
22
+ showBackground: z.ZodDefault<z.ZodBoolean>;
23
+ legend: z.ZodDefault<z.ZodBoolean>;
24
+ };
25
+ export declare const donutRecipe: Recipe<typeof donutInputShape>;
@@ -0,0 +1,51 @@
1
+ import { z } from 'zod';
2
+ import { commonInput, dataRecords, fieldName, assertFieldsExist, baseSpec, field } from './shared.js';
3
+ export const donutInputShape = {
4
+ data: dataRecords,
5
+ value: fieldName.describe('Field with the numeric value of each segment'),
6
+ label: fieldName.optional().describe('Field with the segment name (used for the legend)'),
7
+ variant: z.enum(['donut', 'pie']).default('donut').describe('Donut (ring) or full pie'),
8
+ arcWidth: z.number().min(2).max(200).optional().describe('Ring thickness in pixels (donut variant only)'),
9
+ centralLabel: z.string().optional().describe('Text in the middle of the donut'),
10
+ centralSubLabel: z.string().optional().describe('Smaller text under the central label'),
11
+ padAngle: z.number().min(0).max(0.2).default(0).describe('Angular padding between segments, in radians'),
12
+ sortDescending: z.boolean().default(false).describe('Sort segments by value, largest first'),
13
+ showBackground: z.boolean().default(false).describe('Show a background ring behind the segments'),
14
+ legend: z.boolean().default(true).describe('Show a legend (requires the label field)'),
15
+ ...commonInput,
16
+ };
17
+ export const donutRecipe = {
18
+ name: 'generate_donut_chart',
19
+ title: 'Donut / pie chart',
20
+ description: 'Generate a donut or pie chart showing parts of a whole. ' +
21
+ 'Example: data=[{"browser":"Chrome","share":65},{"browser":"Safari","share":19}], value="share", label="browser".',
22
+ inputShape: donutInputShape,
23
+ toSpec: (input) => {
24
+ let data = input.data;
25
+ assertFieldsExist(data, [input.value, input.label]);
26
+ if (input.sortDescending) {
27
+ data = [...data].sort((a, b) => Number(b[input.value]) - Number(a[input.value]));
28
+ }
29
+ const legend = input.legend && input.label
30
+ ? data.map((d, i) => ({ name: String(d[input.label]), paletteIndex: i, color: input.colors?.[i % (input.colors.length || 1)] }))
31
+ : undefined;
32
+ return {
33
+ container: 'single',
34
+ ...baseSpec(input),
35
+ components: [{
36
+ type: 'Donut',
37
+ config: {
38
+ value: field(input.value, 'number'),
39
+ arcWidth: input.variant === 'pie' ? 0 : (input.arcWidth ?? Math.round(Math.min(input.width, input.height) * 0.1)),
40
+ centralLabel: input.centralLabel,
41
+ centralSubLabel: input.centralSubLabel,
42
+ padAngle: input.padAngle,
43
+ showBackground: input.showBackground,
44
+ },
45
+ }],
46
+ legend,
47
+ data,
48
+ };
49
+ },
50
+ };
51
+ //# sourceMappingURL=donut.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"donut.js","sourceRoot":"","sources":["../../src/recipes/donut.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { z } from 'zod';
2
+ import type { Recipe } from './types.js';
3
+ export declare const graphInputShape: {
4
+ height: z.ZodDefault<z.ZodNumber>;
5
+ width: z.ZodDefault<z.ZodNumber>;
6
+ theme: z.ZodDefault<z.ZodEnum<["light", "dark"]>>;
7
+ title: z.ZodOptional<z.ZodString>;
8
+ colors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ framework: z.ZodDefault<z.ZodEnum<["ts", "react", "svelte", "vue", "angular", "solid"]>>;
10
+ outputType: z.ZodDefault<z.ZodEnum<["svg", "png", "html", "interactive", "config", "code"]>>;
11
+ outputPath: z.ZodOptional<z.ZodString>;
12
+ scale: z.ZodDefault<z.ZodNumber>;
13
+ nodes: z.ZodArray<z.ZodObject<{
14
+ id: z.ZodString;
15
+ label: z.ZodOptional<z.ZodString>;
16
+ group: z.ZodOptional<z.ZodString>;
17
+ size: z.ZodOptional<z.ZodNumber>;
18
+ subLabel: z.ZodOptional<z.ZodString>;
19
+ }, "strip", z.ZodTypeAny, {
20
+ id: string;
21
+ label?: string | undefined;
22
+ size?: number | undefined;
23
+ subLabel?: string | undefined;
24
+ group?: string | undefined;
25
+ }, {
26
+ id: string;
27
+ label?: string | undefined;
28
+ size?: number | undefined;
29
+ subLabel?: string | undefined;
30
+ group?: string | undefined;
31
+ }>, "many">;
32
+ links: z.ZodArray<z.ZodObject<{
33
+ source: z.ZodString;
34
+ target: z.ZodString;
35
+ label: z.ZodOptional<z.ZodString>;
36
+ width: z.ZodOptional<z.ZodNumber>;
37
+ }, "strip", z.ZodTypeAny, {
38
+ source: string;
39
+ target: string;
40
+ label?: string | undefined;
41
+ width?: number | undefined;
42
+ }, {
43
+ source: string;
44
+ target: string;
45
+ label?: string | undefined;
46
+ width?: number | undefined;
47
+ }>, "many">;
48
+ layout: z.ZodDefault<z.ZodEnum<["force", "circular", "concentric", "dagre"]>>;
49
+ nodeSize: z.ZodDefault<z.ZodNumber>;
50
+ showLabels: z.ZodDefault<z.ZodBoolean>;
51
+ linkArrows: z.ZodDefault<z.ZodBoolean>;
52
+ linkWidth: z.ZodDefault<z.ZodNumber>;
53
+ legend: z.ZodDefault<z.ZodBoolean>;
54
+ };
55
+ export declare const graphRecipe: Recipe<typeof graphInputShape>;
@@ -0,0 +1,132 @@
1
+ import { z } from 'zod';
2
+ import { commonInput, baseSpec, seriesLegend, ChartInputError } from './shared.js';
3
+ /** Category color: custom palette entries cycle; otherwise theme palette variables
4
+ * (resolved to literal colors per theme during SVG post-processing) */
5
+ const categoryColor = (i, colors) => colors?.length ? colors[i % colors.length] : `var(--vis-color${i % 6})`;
6
+ /** Neutral grey for nodes without a group when other nodes have one (works on both themes) */
7
+ const UNKNOWN_GROUP_COLOR = '#94A0AB';
8
+ const graphNode = z.object({
9
+ id: z.string().min(1).describe('Unique node id'),
10
+ label: z.string().optional().describe('Display name (defaults to id)'),
11
+ group: z.string().optional().describe('Category the node belongs to — drives node color (and ring placement in the concentric layout)'),
12
+ size: z.number().min(4).max(200).optional().describe('Node diameter in pixels (defaults to nodeSize)'),
13
+ subLabel: z.string().optional().describe('Smaller text under the node label'),
14
+ });
15
+ const graphLink = z.object({
16
+ source: z.string().min(1).describe('Source node id'),
17
+ target: z.string().min(1).describe('Target node id'),
18
+ label: z.string().optional().describe('Short badge label drawn on the link (keep it within a few characters)'),
19
+ width: z.number().min(0.5).max(20).optional().describe('Link stroke width in pixels (defaults to linkWidth)'),
20
+ });
21
+ export const graphInputShape = {
22
+ nodes: z.array(graphNode).min(1).max(300)
23
+ .describe('Graph nodes, e.g. [{"id":"gw","label":"Gateway","group":"service"}]'),
24
+ links: z.array(graphLink).max(1000)
25
+ .describe('Edges between nodes by id, e.g. [{"source":"gw","target":"db"}]'),
26
+ layout: z.enum(['force', 'circular', 'concentric', 'dagre']).default('force')
27
+ .describe('Node placement: force (organic, general networks), circular (single ring), ' +
28
+ 'concentric (one ring per group), dagre (layered top to bottom — best for hierarchies and DAGs)'),
29
+ nodeSize: z.number().min(4).max(100).default(22).describe('Default node diameter in pixels'),
30
+ showLabels: z.boolean().default(true).describe('Show node labels'),
31
+ linkArrows: z.boolean().default(false).describe('Draw source → target arrowheads on links'),
32
+ linkWidth: z.number().min(0.5).max(20).default(1.5).describe('Default link stroke width in pixels'),
33
+ legend: z.boolean().default(true).describe('Show a legend when nodes have groups'),
34
+ ...commonInput,
35
+ height: z.number().int().min(100).max(4000).default(600).describe('Chart height in pixels'),
36
+ };
37
+ export const graphRecipe = {
38
+ name: 'generate_network_graph',
39
+ title: 'Network graph',
40
+ description: 'Generate a network graph (node-link diagram) of relationships between entities — ' +
41
+ 'topologies, dependencies, hierarchies, social networks. Nodes are colored by their optional group. ' +
42
+ 'Use layout "dagre" with linkArrows for hierarchies and DAGs, "force" for general networks, ' +
43
+ '"circular"/"concentric" for symmetric views. ' +
44
+ 'Example: nodes=[{"id":"api","group":"service"},{"id":"db","group":"storage"}], links=[{"source":"api","target":"db"}].',
45
+ inputShape: graphInputShape,
46
+ toSpec: (input) => {
47
+ const ids = new Set();
48
+ const duplicates = new Set();
49
+ for (const node of input.nodes) {
50
+ if (ids.has(node.id))
51
+ duplicates.add(node.id);
52
+ ids.add(node.id);
53
+ }
54
+ if (duplicates.size) {
55
+ throw new ChartInputError(`Duplicate node id${duplicates.size > 1 ? 's' : ''}: ${[...duplicates].map(d => `"${d}"`).join(', ')}`);
56
+ }
57
+ const unknown = new Set();
58
+ for (const link of input.links) {
59
+ if (!ids.has(link.source))
60
+ unknown.add(link.source);
61
+ if (!ids.has(link.target))
62
+ unknown.add(link.target);
63
+ // The graph data model silently drops self-referencing links — reject
64
+ // them instead so the output never misrepresents the input
65
+ if (link.source === link.target)
66
+ throw new ChartInputError(`Self-referencing link: "${link.source}" → "${link.source}". Links must connect two distinct nodes`);
67
+ }
68
+ if (unknown.size) {
69
+ throw new ChartInputError(`Link endpoint${unknown.size > 1 ? 's' : ''} ${[...unknown].map(d => `"${d}"`).join(', ')} not found in nodes. ` +
70
+ 'Every link source/target must match a node id');
71
+ }
72
+ // Distinct groups in first-seen order map onto the palette; the legend
73
+ // mirrors the same order/colors (scatter colorBy pattern)
74
+ const groups = [];
75
+ for (const node of input.nodes) {
76
+ if (node.group !== undefined && !groups.includes(node.group))
77
+ groups.push(node.group);
78
+ }
79
+ const mapping = {};
80
+ groups.forEach((group, i) => { mapping[group] = categoryColor(i, input.colors); });
81
+ // Ungrouped graphs get the first palette color — the library default
82
+ // (hollow theme-colored circles) reads as unstyled in a generated chart
83
+ const nodeFill = groups.length
84
+ ? { $mapField: { field: 'group', mapping, fallback: UNKNOWN_GROUP_COLOR } }
85
+ : categoryColor(0, input.colors);
86
+ const legend = seriesLegend(groups, input.legend, input.colors);
87
+ // Normalize data so field accessors never hit undefined values
88
+ const anyNodeSize = input.nodes.some(n => n.size !== undefined);
89
+ const anySubLabel = input.nodes.some(n => n.subLabel !== undefined);
90
+ const nodes = input.nodes.map(n => ({
91
+ id: n.id,
92
+ label: n.label ?? n.id,
93
+ ...(n.group !== undefined ? { group: n.group } : {}),
94
+ ...(anyNodeSize ? { size: n.size ?? input.nodeSize } : {}),
95
+ ...(anySubLabel ? { subLabel: n.subLabel ?? '' } : {}),
96
+ }));
97
+ const anyLinkWidth = input.links.some(l => l.width !== undefined);
98
+ const anyLinkLabel = input.links.some(l => l.label !== undefined);
99
+ const links = input.links.map(l => ({
100
+ source: l.source,
101
+ target: l.target,
102
+ ...(anyLinkWidth ? { width: l.width ?? input.linkWidth } : {}),
103
+ // linkLabel expects a GraphCircleLabel object ({ text })
104
+ ...(l.label !== undefined ? { label: { text: l.label } } : {}),
105
+ }));
106
+ return {
107
+ container: 'single',
108
+ ...baseSpec(input),
109
+ components: [{
110
+ type: 'Graph',
111
+ config: {
112
+ layoutType: input.layout,
113
+ ...(input.layout === 'dagre' ? { dagreLayoutSettings: { rankdir: 'TB', ranker: 'longest-path' } } : {}),
114
+ // Top-to-bottom reads naturally for generated hierarchies (lib default is bottom-to-top)
115
+ nodeLabel: input.showLabels ? { $field: 'label' } : '',
116
+ ...(input.showLabels && anySubLabel ? { nodeSubLabel: { $field: 'subLabel' } } : {}),
117
+ nodeSize: anyNodeSize ? { $field: 'size', as: 'number' } : input.nodeSize,
118
+ nodeFill,
119
+ linkWidth: anyLinkWidth ? { $field: 'width', as: 'number' } : input.linkWidth,
120
+ ...(input.linkArrows ? { linkArrow: 'single' } : {}),
121
+ ...(anyLinkLabel ? { linkLabel: { $field: 'label' } } : {}),
122
+ // Headless render: let fit-to-view zoom out further than the
123
+ // interactive default so large layouts are never clipped
124
+ zoomScaleExtent: [0.05, 1.25],
125
+ },
126
+ }],
127
+ legend,
128
+ data: { nodes, links },
129
+ };
130
+ },
131
+ };
132
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/recipes/graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { z } from 'zod';
2
+ import type { Recipe } from './types.js';
3
+ export declare const heatmapInputShape: {
4
+ width: z.ZodDefault<z.ZodNumber>;
5
+ height: z.ZodDefault<z.ZodNumber>;
6
+ theme: z.ZodDefault<z.ZodEnum<["light", "dark"]>>;
7
+ title: z.ZodOptional<z.ZodString>;
8
+ colors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ framework: z.ZodDefault<z.ZodEnum<["ts", "react", "svelte", "vue", "angular", "solid"]>>;
10
+ outputType: z.ZodDefault<z.ZodEnum<["svg", "png", "html", "interactive", "config", "code"]>>;
11
+ outputPath: z.ZodOptional<z.ZodString>;
12
+ scale: z.ZodDefault<z.ZodNumber>;
13
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
14
+ row: z.ZodString;
15
+ column: z.ZodString;
16
+ value: z.ZodString;
17
+ colorRange: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodString], null>>;
18
+ cellPadding: z.ZodDefault<z.ZodNumber>;
19
+ cellCornerRadius: z.ZodDefault<z.ZodNumber>;
20
+ };
21
+ export declare const heatmapRecipe: Recipe<typeof heatmapInputShape>;
@@ -0,0 +1,79 @@
1
+ import { z } from 'zod';
2
+ import { commonInput, dataRecords, fieldName, assertFieldsExist, baseSpec, distinctValues, field } from './shared.js';
3
+ const hexColor = z.string().regex(/^#[0-9a-fA-F]{3,8}$/, 'hex color, e.g. #40C463');
4
+ const hexToRgb = (hex) => {
5
+ let h = hex.slice(1);
6
+ if (h.length < 6)
7
+ h = h.split('').map(c => c + c).join('');
8
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
9
+ };
10
+ /** Evenly spaced hex stops between two colors (inclusive) — the heatmap builds
11
+ * a quantized value → color scale from them, matching its 4-stop default */
12
+ const interpolateHexStops = (from, to, count) => {
13
+ const a = hexToRgb(from);
14
+ const b = hexToRgb(to);
15
+ return Array.from({ length: count }, (_, i) => {
16
+ const t = i / (count - 1);
17
+ return `#${a.map((channel, c) => Math.round(channel + (b[c] - channel) * t).toString(16).padStart(2, '0')).join('')}`;
18
+ });
19
+ };
20
+ export const heatmapInputShape = {
21
+ data: dataRecords,
22
+ row: fieldName.describe('Field with the row category of each cell'),
23
+ column: fieldName.describe('Field with the column category of each cell'),
24
+ value: fieldName.describe('Field with the numeric cell value (drives the cell color)'),
25
+ colorRange: z.tuple([hexColor, hexColor]).optional()
26
+ .describe('[lowColor, highColor] hex pair; cell colors are interpolated between them. Defaults to a green sequence'),
27
+ cellPadding: z.number().min(0).max(20).default(2).describe('Gap between cells in pixels'),
28
+ cellCornerRadius: z.number().min(0).max(30).default(2).describe('Cell corner radius in pixels'),
29
+ ...commonInput,
30
+ };
31
+ export const heatmapRecipe = {
32
+ name: 'generate_heatmap',
33
+ title: 'Heatmap',
34
+ description: 'Generate a heatmap: a grid of cells colored by value across two categorical dimensions ' +
35
+ '(e.g. activity by weekday × hour). Missing row/column combinations render as empty cells. ' +
36
+ 'Example: data=[{"day":"Mon","hour":"9am","visits":34},{"day":"Mon","hour":"10am","visits":51}], row="day", column="hour", value="visits".',
37
+ inputShape: heatmapInputShape,
38
+ toSpec: (input) => {
39
+ const data = input.data;
40
+ assertFieldsExist(data, [input.row, input.column, input.value]);
41
+ // Distinct row/column names in first-seen order define the grid
42
+ const rows = distinctValues(data, input.row).map(String);
43
+ const columns = distinctValues(data, input.column).map(String);
44
+ // Dense row-major grid — layout 'row' fills each row left-to-right.
45
+ // Cells without a record keep a null value and render as empty cells.
46
+ const cells = new Map();
47
+ for (const d of data) {
48
+ const value = Number(d[input.value]);
49
+ if (d[input.value] === null || d[input.value] === '' || Number.isNaN(value))
50
+ continue;
51
+ cells.set(`${String(d[input.row])}\u0000${String(d[input.column])}`, value);
52
+ }
53
+ const grid = rows.flatMap(row => columns.map(column => ({
54
+ row,
55
+ column,
56
+ value: cells.get(`${row}\u0000${column}`) ?? null,
57
+ })));
58
+ return {
59
+ container: 'single',
60
+ ...baseSpec(input),
61
+ components: [{
62
+ type: 'Heatmap',
63
+ config: {
64
+ value: field('value', 'number'),
65
+ layout: 'row',
66
+ numRows: rows.length,
67
+ numColumns: columns.length,
68
+ rowLabel: { $lookup: rows },
69
+ columnLabel: { $lookup: columns },
70
+ cellPadding: input.cellPadding,
71
+ cellCornerRadius: input.cellCornerRadius,
72
+ ...(input.colorRange ? { colorRange: interpolateHexStops(input.colorRange[0], input.colorRange[1], 4) } : {}),
73
+ },
74
+ }],
75
+ data: grid,
76
+ };
77
+ },
78
+ };
79
+ //# sourceMappingURL=heatmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heatmap.js","sourceRoot":"","sources":["../../src/recipes/heatmap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { AnyRecipe } from './types.js';
2
+ export type { Recipe, AnyRecipe } from './types.js';
3
+ /** All available chart recipes, in display order */
4
+ export declare const recipes: AnyRecipe[];
5
+ export declare const recipeByName: Map<string, AnyRecipe>;
@@ -0,0 +1,35 @@
1
+ import { lineRecipe } from './line.js';
2
+ import { areaRecipe } from './area.js';
3
+ import { barRecipe } from './bar.js';
4
+ import { scatterRecipe } from './scatter.js';
5
+ import { donutRecipe } from './donut.js';
6
+ import { timelineRecipe } from './timeline.js';
7
+ import { boxplotRecipe } from './boxplot.js';
8
+ import { sankeyRecipe } from './sankey.js';
9
+ import { heatmapRecipe } from './heatmap.js';
10
+ import { treemapRecipe } from './treemap.js';
11
+ import { chordRecipe } from './chord.js';
12
+ import { nestedDonutRecipe } from './nested-donut.js';
13
+ import { radialBarRecipe } from './radial-bar.js';
14
+ import { graphRecipe } from './graph.js';
15
+ import { choroplethRecipe } from './choropleth.js';
16
+ /** All available chart recipes, in display order */
17
+ export const recipes = [
18
+ lineRecipe,
19
+ areaRecipe,
20
+ barRecipe,
21
+ scatterRecipe,
22
+ donutRecipe,
23
+ timelineRecipe,
24
+ boxplotRecipe,
25
+ sankeyRecipe,
26
+ heatmapRecipe,
27
+ treemapRecipe,
28
+ chordRecipe,
29
+ nestedDonutRecipe,
30
+ radialBarRecipe,
31
+ graphRecipe,
32
+ choroplethRecipe,
33
+ ];
34
+ export const recipeByName = new Map(recipes.map(r => [r.name, r]));
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/recipes/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAIlD,oDAAoD;AACpD,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC,UAAU;IACV,UAAU;IACV,SAAS;IACT,aAAa;IACb,WAAW;IACX,cAAc;IACd,aAAa;IACb,YAAY;IACZ,aAAa;IACb,aAAa;IACb,WAAW;IACX,iBAAiB;IACjB,eAAe;IACf,WAAW;IACX,gBAAgB;CACjB,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,69 @@
1
+ import { z } from 'zod';
2
+ import type { Recipe } from './types.js';
3
+ export declare const lineInputShape: {
4
+ width: z.ZodDefault<z.ZodNumber>;
5
+ height: z.ZodDefault<z.ZodNumber>;
6
+ theme: z.ZodDefault<z.ZodEnum<["light", "dark"]>>;
7
+ title: z.ZodOptional<z.ZodString>;
8
+ colors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ framework: z.ZodDefault<z.ZodEnum<["ts", "react", "svelte", "vue", "angular", "solid"]>>;
10
+ outputType: z.ZodDefault<z.ZodEnum<["svg", "png", "html", "interactive", "config", "code"]>>;
11
+ outputPath: z.ZodOptional<z.ZodString>;
12
+ scale: z.ZodDefault<z.ZodNumber>;
13
+ xAxisLabel: z.ZodOptional<z.ZodString>;
14
+ yAxisLabel: z.ZodOptional<z.ZodString>;
15
+ showGridLines: z.ZodDefault<z.ZodBoolean>;
16
+ legend: z.ZodDefault<z.ZodBoolean>;
17
+ referenceLines: z.ZodOptional<z.ZodArray<z.ZodObject<{
18
+ axis: z.ZodDefault<z.ZodEnum<["x", "y"]>>;
19
+ value: z.ZodNumber;
20
+ label: z.ZodOptional<z.ZodString>;
21
+ color: z.ZodOptional<z.ZodString>;
22
+ lineWidth: z.ZodDefault<z.ZodNumber>;
23
+ style: z.ZodDefault<z.ZodEnum<["dashed", "solid", "dotted"]>>;
24
+ }, "strip", z.ZodTypeAny, {
25
+ value: number;
26
+ style: "solid" | "dashed" | "dotted";
27
+ axis: "x" | "y";
28
+ lineWidth: number;
29
+ label?: string | undefined;
30
+ color?: string | undefined;
31
+ }, {
32
+ value: number;
33
+ label?: string | undefined;
34
+ color?: string | undefined;
35
+ style?: "solid" | "dashed" | "dotted" | undefined;
36
+ axis?: "x" | "y" | undefined;
37
+ lineWidth?: number | undefined;
38
+ }>, "many">>;
39
+ referenceBands: z.ZodOptional<z.ZodArray<z.ZodObject<{
40
+ axis: z.ZodDefault<z.ZodEnum<["x", "y"]>>;
41
+ from: z.ZodNumber;
42
+ to: z.ZodNumber;
43
+ label: z.ZodOptional<z.ZodString>;
44
+ color: z.ZodOptional<z.ZodString>;
45
+ }, "strip", z.ZodTypeAny, {
46
+ axis: "x" | "y";
47
+ from: number;
48
+ to: number;
49
+ label?: string | undefined;
50
+ color?: string | undefined;
51
+ }, {
52
+ from: number;
53
+ to: number;
54
+ label?: string | undefined;
55
+ color?: string | undefined;
56
+ axis?: "x" | "y" | undefined;
57
+ }>, "many">>;
58
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
59
+ x: z.ZodString;
60
+ y: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
61
+ xIsTime: z.ZodDefault<z.ZodBoolean>;
62
+ seriesLabels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
63
+ lineWidth: z.ZodDefault<z.ZodNumber>;
64
+ curve: z.ZodDefault<z.ZodEnum<["linear", "monotoneX", "basis", "natural", "step", "stepAfter", "stepBefore"]>>;
65
+ interpolateMissing: z.ZodDefault<z.ZodBoolean>;
66
+ yDomainMin: z.ZodOptional<z.ZodNumber>;
67
+ yDomainMax: z.ZodOptional<z.ZodNumber>;
68
+ };
69
+ export declare const lineRecipe: Recipe<typeof lineInputShape>;
@@ -0,0 +1,64 @@
1
+ import { z } from 'zod';
2
+ import { commonInput, xyInput, dataRecords, fieldName, assertFieldsExist, baseSpec, categoricalX, categoryAxis, field, seriesLegend, timeTickValuesFromData, toArray, xyAxes, xyDecorations, decorationComponents, } from './shared.js';
3
+ export const lineInputShape = {
4
+ data: dataRecords,
5
+ x: fieldName.describe('Field for X values: numbers, or date strings when xIsTime is true, or category names'),
6
+ y: z.union([fieldName, z.array(fieldName).min(1).max(12)])
7
+ .describe('Field name(s) for Y values. Multiple field names render multiple lines'),
8
+ xIsTime: z.boolean().default(false).describe('Treat x values as dates/timestamps (time axis)'),
9
+ seriesLabels: z.array(z.string()).optional().describe('Display names for the y series (legend). Defaults to field names'),
10
+ lineWidth: z.number().min(0.5).max(20).default(2).describe('Line stroke width in pixels'),
11
+ curve: z.enum(['linear', 'monotoneX', 'basis', 'natural', 'step', 'stepAfter', 'stepBefore']).default('monotoneX')
12
+ .describe('Line interpolation type'),
13
+ interpolateMissing: z.boolean().default(false)
14
+ .describe('Draw dashed interpolated segments across missing (null) values instead of gaps'),
15
+ yDomainMin: z.number().optional().describe('Force the Y axis to start at this value'),
16
+ yDomainMax: z.number().optional().describe('Force the Y axis to end at this value'),
17
+ ...xyDecorations,
18
+ ...xyInput,
19
+ ...commonInput,
20
+ };
21
+ export const lineRecipe = {
22
+ name: 'generate_line_chart',
23
+ title: 'Line chart',
24
+ description: 'Generate a line chart (single or multi-series) for trends over a continuous or time dimension. ' +
25
+ 'Data is an array of flat records; x and y reference field names. ' +
26
+ 'Example: data=[{"month":"2024-01","sales":120,"cost":80},...], x="month", xIsTime=true, y=["sales","cost"].',
27
+ inputShape: lineInputShape,
28
+ toSpec: (input) => {
29
+ const data = input.data;
30
+ const yFields = toArray(input.y);
31
+ assertFieldsExist(data, [input.x, ...yFields]);
32
+ const { x, categories } = categoricalX(data, input.x, input.xIsTime);
33
+ const axes = xyAxes(input);
34
+ const labels = input.seriesLabels?.length ? input.seriesLabels : yFields;
35
+ const deco = decorationComponents(input);
36
+ return {
37
+ container: 'xy',
38
+ ...baseSpec(input),
39
+ components: [...deco.bands, {
40
+ type: 'Line',
41
+ config: {
42
+ x,
43
+ y: yFields.map(f => field(f, 'number')),
44
+ lineWidth: input.lineWidth,
45
+ curveType: input.curve,
46
+ interpolateMissingData: input.interpolateMissing,
47
+ },
48
+ }, ...deco.lines],
49
+ xAxis: {
50
+ ...(categories ? categoryAxis(axes.xAxis, categories) : axes.xAxis),
51
+ ...(input.xIsTime
52
+ ? { tickFormat: { $dateTickFormat: true }, tickValues: timeTickValuesFromData(data, input.x) }
53
+ : {}),
54
+ },
55
+ yAxis: { ...axes.yAxis, tickFormat: { $numTickFormat: true } },
56
+ containerConfig: (input.yDomainMin !== undefined || input.yDomainMax !== undefined)
57
+ ? { yDomain: [input.yDomainMin, input.yDomainMax] }
58
+ : undefined,
59
+ legend: seriesLegend(labels, input.legend, input.colors),
60
+ data,
61
+ };
62
+ },
63
+ };
64
+ //# sourceMappingURL=line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line.js","sourceRoot":"","sources":["../../src/recipes/line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EACL,WAAW,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,KAAK,EACL,YAAY,EACZ,sBAAsB,EACtB,OAAO,EACP,MAAM,EACN,aAAa,EACb,oBAAoB,GACrB,MAAM,aAAa,CAAA;AAGpB,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,WAAW;IACjB,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,sFAAsF,CAAC;IAC7G,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;SACvD,QAAQ,CAAC,wEAAwE,CAAC;IACrF,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,gDAAgD,CAAC;IAC9F,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kEAAkE,CAAC;IACzH,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IACzF,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;SAC/G,QAAQ,CAAC,yBAAyB,CAAC;IACtC,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;SAC3C,QAAQ,CAAC,gFAAgF,CAAC;IAC7F,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;IACrF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IACnF,GAAG,aAAa;IAChB,GAAG,OAAO;IACV,GAAG,WAAW;CACf,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAkC;IACvD,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,iGAAiG;QAC5G,mEAAmE;QACnE,6GAA6G;IAC/G,UAAU,EAAE,cAAc;IAC1B,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;QAChB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAoB,CAAA;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAChC,iBAAiB,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAA;QAE9C,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QACpE,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAA;QAExE,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAA;QACxC,OAAO;YACL,SAAS,EAAE,IAAI;YACf,GAAG,QAAQ,CAAC,KAAK,CAAC;YAClB,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE;oBAC1B,IAAI,EAAE,MAAM;oBACZ,MAAM,EAAE;wBACN,CAAC;wBACD,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;wBACvC,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,SAAS,EAAE,KAAK,CAAC,KAAK;wBACtB,sBAAsB,EAAE,KAAK,CAAC,kBAAkB;qBACjD;iBACF,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YACjB,KAAK,EAAE;gBACL,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;gBACnE,GAAG,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,sBAAsB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE;oBAC9F,CAAC,CAAC,EAAE,CAAC;aACR;YACD,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE;YAC9D,eAAe,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC;gBACjF,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE;gBACnD,CAAC,CAAC,SAAS;YACb,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;YACxD,IAAI;SACL,CAAA;IACH,CAAC;CACF,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ import type { Recipe } from './types.js';
3
+ export declare const nestedDonutInputShape: {
4
+ width: z.ZodDefault<z.ZodNumber>;
5
+ height: z.ZodDefault<z.ZodNumber>;
6
+ theme: z.ZodDefault<z.ZodEnum<["light", "dark"]>>;
7
+ title: z.ZodOptional<z.ZodString>;
8
+ colors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ framework: z.ZodDefault<z.ZodEnum<["ts", "react", "svelte", "vue", "angular", "solid"]>>;
10
+ outputType: z.ZodDefault<z.ZodEnum<["svg", "png", "html", "interactive", "config", "code"]>>;
11
+ outputPath: z.ZodOptional<z.ZodString>;
12
+ scale: z.ZodDefault<z.ZodNumber>;
13
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
14
+ layers: z.ZodArray<z.ZodString, "many">;
15
+ value: z.ZodOptional<z.ZodString>;
16
+ centralLabel: z.ZodOptional<z.ZodString>;
17
+ centralSubLabel: z.ZodOptional<z.ZodString>;
18
+ layerPadding: z.ZodDefault<z.ZodNumber>;
19
+ cornerRadius: z.ZodDefault<z.ZodNumber>;
20
+ showSegmentLabels: z.ZodDefault<z.ZodBoolean>;
21
+ };
22
+ export declare const nestedDonutRecipe: Recipe<typeof nestedDonutInputShape>;