@opendata-ai/openchart-core 2.0.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 (51) hide show
  1. package/README.md +130 -0
  2. package/dist/index.d.ts +2030 -0
  3. package/dist/index.js +1176 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/styles.css +757 -0
  6. package/package.json +61 -0
  7. package/src/accessibility/__tests__/alt-text.test.ts +110 -0
  8. package/src/accessibility/__tests__/aria.test.ts +125 -0
  9. package/src/accessibility/alt-text.ts +120 -0
  10. package/src/accessibility/aria.ts +73 -0
  11. package/src/accessibility/index.ts +6 -0
  12. package/src/colors/__tests__/colorblind.test.ts +63 -0
  13. package/src/colors/__tests__/contrast.test.ts +71 -0
  14. package/src/colors/__tests__/palettes.test.ts +54 -0
  15. package/src/colors/colorblind.ts +122 -0
  16. package/src/colors/contrast.ts +94 -0
  17. package/src/colors/index.ts +27 -0
  18. package/src/colors/palettes.ts +118 -0
  19. package/src/helpers/__tests__/spec-builders.test.ts +336 -0
  20. package/src/helpers/spec-builders.ts +410 -0
  21. package/src/index.ts +129 -0
  22. package/src/labels/__tests__/collision.test.ts +197 -0
  23. package/src/labels/collision.ts +154 -0
  24. package/src/labels/index.ts +6 -0
  25. package/src/layout/__tests__/chrome.test.ts +114 -0
  26. package/src/layout/__tests__/text-measure.test.ts +49 -0
  27. package/src/layout/chrome.ts +223 -0
  28. package/src/layout/index.ts +6 -0
  29. package/src/layout/text-measure.ts +54 -0
  30. package/src/locale/__tests__/format.test.ts +90 -0
  31. package/src/locale/format.ts +132 -0
  32. package/src/locale/index.ts +6 -0
  33. package/src/responsive/__tests__/breakpoints.test.ts +58 -0
  34. package/src/responsive/breakpoints.ts +92 -0
  35. package/src/responsive/index.ts +18 -0
  36. package/src/styles/viz.css +757 -0
  37. package/src/theme/__tests__/dark-mode.test.ts +68 -0
  38. package/src/theme/__tests__/defaults.test.ts +47 -0
  39. package/src/theme/__tests__/resolve.test.ts +61 -0
  40. package/src/theme/dark-mode.ts +123 -0
  41. package/src/theme/defaults.ts +85 -0
  42. package/src/theme/index.ts +7 -0
  43. package/src/theme/resolve.ts +190 -0
  44. package/src/types/__tests__/spec.test.ts +387 -0
  45. package/src/types/encoding.ts +144 -0
  46. package/src/types/events.ts +96 -0
  47. package/src/types/index.ts +141 -0
  48. package/src/types/layout.ts +794 -0
  49. package/src/types/spec.ts +563 -0
  50. package/src/types/table.ts +105 -0
  51. package/src/types/theme.ts +159 -0
@@ -0,0 +1,2030 @@
1
+ /**
2
+ * Responsive breakpoints and layout strategies.
3
+ *
4
+ * Three breakpoints based on container width:
5
+ * - compact: < 400px (mobile, small embeds)
6
+ * - medium: 400-700px (tablet, sidebars)
7
+ * - full: > 700px (desktop, full-width)
8
+ */
9
+ /** Responsive breakpoint based on container width. */
10
+ type Breakpoint = 'compact' | 'medium' | 'full';
11
+ /**
12
+ * Determine the breakpoint for a given container width.
13
+ */
14
+ declare function getBreakpoint(width: number): Breakpoint;
15
+ /** Label display mode at a given breakpoint. */
16
+ type LabelMode = 'all' | 'important' | 'none';
17
+ /** Legend position at a given breakpoint. */
18
+ type LegendPosition = 'top' | 'right' | 'bottom' | 'bottom-right' | 'inline';
19
+ /** Annotation position strategy. */
20
+ type AnnotationPosition = 'inline' | 'tooltip-only';
21
+ /** Axis label density (controls tick count reduction). */
22
+ type AxisLabelDensity = 'full' | 'reduced' | 'minimal';
23
+ /**
24
+ * Layout strategy defining how the visualization adapts to available space.
25
+ * Returned by getLayoutStrategy() based on the current breakpoint.
26
+ */
27
+ interface LayoutStrategy {
28
+ /** How data labels are displayed. */
29
+ labelMode: LabelMode;
30
+ /** Where the legend is positioned. */
31
+ legendPosition: LegendPosition;
32
+ /** How annotations are displayed. */
33
+ annotationPosition: AnnotationPosition;
34
+ /** Axis tick density. */
35
+ axisLabelDensity: AxisLabelDensity;
36
+ }
37
+ /**
38
+ * Get the layout strategy for a given breakpoint.
39
+ *
40
+ * Compact: minimal chrome, no inline labels, legend on top, reduced axes.
41
+ * Medium: moderate labels, legend on top, reduced axes.
42
+ * Full: all labels, legend on right, full axes.
43
+ */
44
+ declare function getLayoutStrategy(breakpoint: Breakpoint): LayoutStrategy;
45
+
46
+ /**
47
+ * Table column configuration types.
48
+ *
49
+ * These types define how individual columns in a TableSpec are displayed,
50
+ * formatted, and enhanced with visual features like heatmaps, bars,
51
+ * sparklines, images, and category colors.
52
+ */
53
+ /** Heatmap coloring configuration for a table column. */
54
+ interface HeatmapColumnConfig {
55
+ /**
56
+ * Color palette name or array of color stops.
57
+ * Uses sequential palette from theme if a string name is provided.
58
+ */
59
+ palette?: string | string[];
60
+ /** Explicit domain [min, max] for the color scale. Auto-derived from data if omitted. */
61
+ domain?: [number, number];
62
+ /**
63
+ * Use a different field's values for coloring while displaying this column's values.
64
+ * Useful for coloring a label column based on a numeric column.
65
+ */
66
+ colorByField?: string;
67
+ }
68
+ /** Inline bar configuration for a table column. */
69
+ interface BarColumnConfig {
70
+ /** Maximum value for the bar scale. Auto-derived from data if omitted. */
71
+ maxValue?: number;
72
+ /** Bar fill color. Uses the first categorical palette color if omitted. */
73
+ color?: string;
74
+ }
75
+ /** Inline sparkline configuration for a table column. */
76
+ interface SparklineColumnConfig {
77
+ /** Sparkline chart type. Defaults to "line". */
78
+ type?: 'line' | 'bar' | 'column';
79
+ /** Field containing the array of values to plot. */
80
+ valuesField?: string;
81
+ /** Sparkline color. Uses the first categorical palette color if omitted. */
82
+ color?: string;
83
+ }
84
+ /** Image cell configuration for a table column. */
85
+ interface ImageColumnConfig {
86
+ /** Image width in pixels. Defaults to 24. */
87
+ width?: number;
88
+ /** Image height in pixels. Defaults to 24. */
89
+ height?: number;
90
+ /** Whether to apply border-radius for rounded/circular images. */
91
+ rounded?: boolean;
92
+ }
93
+ /** Category color mapping for a table column. Maps category values to CSS colors. */
94
+ type CategoryColorsConfig = Record<string, string>;
95
+ /**
96
+ * Configuration for a single table column.
97
+ *
98
+ * At minimum, `key` identifies the data field. All other properties
99
+ * control display, sorting, formatting, and visual features.
100
+ *
101
+ * Only one visual feature (heatmap, bar, sparkline, image, flag, categoryColors)
102
+ * should be active per column. If multiple are provided, the engine picks
103
+ * the first one in this precedence order: sparkline > bar > heatmap > image > flag > categoryColors.
104
+ */
105
+ interface ColumnConfig {
106
+ /** Data field key (must match a key in the data rows). */
107
+ key: string;
108
+ /** Display label for the column header. Defaults to the key if omitted. */
109
+ label?: string;
110
+ /** Whether this column is sortable. Defaults to true. */
111
+ sortable?: boolean;
112
+ /** Text alignment in the column. Defaults to "left" for text, "right" for numbers. */
113
+ align?: 'left' | 'center' | 'right';
114
+ /** Explicit column width (CSS value like "200px" or "20%"). Auto-sized if omitted. */
115
+ width?: string;
116
+ /**
117
+ * Number/date format string (d3-format or d3-time-format).
118
+ * Applied to the raw value before display. e.g. ",.0f" or "%Y-%m-%d".
119
+ */
120
+ format?: string;
121
+ /** Heatmap: color the cell background based on numeric value. */
122
+ heatmap?: HeatmapColumnConfig;
123
+ /** Inline bar: render a proportional bar in the cell. */
124
+ bar?: BarColumnConfig;
125
+ /** Sparkline: render a mini line/bar chart in the cell. */
126
+ sparkline?: SparklineColumnConfig;
127
+ /** Image: render the cell value as an image URL. */
128
+ image?: ImageColumnConfig;
129
+ /** Flag: render the cell value as a country flag emoji or image. */
130
+ flag?: boolean;
131
+ /** Category colors: color-code the cell based on its categorical value. */
132
+ categoryColors?: CategoryColorsConfig;
133
+ }
134
+
135
+ /**
136
+ * Spec types: the user-facing input contract.
137
+ *
138
+ * These types define what a user (or Claude) writes to describe a visualization.
139
+ * The engine validates, normalizes, and compiles specs into layout objects.
140
+ *
141
+ * Encoding vocabulary follows Vega-Lite conventions (field/type/aggregate)
142
+ * with editorial extensions for chrome, annotations, responsive, and dark mode.
143
+ */
144
+
145
+ /** Supported chart types. Graph is separate since it uses nodes/edges, not data + encoding. */
146
+ type ChartType = 'line' | 'area' | 'bar' | 'column' | 'pie' | 'donut' | 'dot' | 'scatter';
147
+ /** Data field type, following Vega-Lite conventions. */
148
+ type FieldType = 'quantitative' | 'temporal' | 'nominal' | 'ordinal';
149
+ /** Aggregate function applied to a field before encoding. */
150
+ type AggregateOp = 'count' | 'sum' | 'mean' | 'median' | 'min' | 'max';
151
+ /** Axis configuration for an encoding channel. */
152
+ interface AxisConfig {
153
+ /** Axis label text. If omitted, the field name is used. */
154
+ label?: string;
155
+ /** Number format string (d3-format). e.g. ",.0f" for comma-separated integers. */
156
+ format?: string;
157
+ /** Override tick count. Engine picks a sensible default if omitted. */
158
+ tickCount?: number;
159
+ /** Whether to show gridlines for this axis. */
160
+ grid?: boolean;
161
+ }
162
+ /** Scale configuration for an encoding channel. */
163
+ interface ScaleConfig {
164
+ /** Explicit domain override. Auto-derived from data if omitted. */
165
+ domain?: [number, number] | string[];
166
+ /** Scale type override. Usually inferred from field type. */
167
+ type?: 'linear' | 'log' | 'time' | 'band' | 'point' | 'ordinal';
168
+ /** Whether to nice-ify the domain for clean tick values. Defaults to true. */
169
+ nice?: boolean;
170
+ /** Whether the domain should include zero. Defaults to true for quantitative. */
171
+ zero?: boolean;
172
+ }
173
+ /**
174
+ * A single encoding channel mapping a data field to a visual property.
175
+ *
176
+ * Follows the Vega-Lite encoding model: field identifies the column,
177
+ * type determines how the engine interprets values, aggregate applies
178
+ * a transformation before encoding.
179
+ */
180
+ interface EncodingChannel {
181
+ /** Data field name (column in the data array). */
182
+ field: string;
183
+ /**
184
+ * How to interpret the field values.
185
+ * - quantitative: continuous numbers (scale: linear)
186
+ * - temporal: dates/times (scale: time)
187
+ * - nominal: unordered categories (scale: ordinal)
188
+ * - ordinal: ordered categories (scale: ordinal)
189
+ */
190
+ type: FieldType;
191
+ /** Optional aggregate to apply before encoding. */
192
+ aggregate?: AggregateOp;
193
+ /** Axis configuration. Only relevant for x and y channels. */
194
+ axis?: AxisConfig;
195
+ /** Scale configuration. */
196
+ scale?: ScaleConfig;
197
+ }
198
+ /**
199
+ * Encoding object mapping visual channels to data fields.
200
+ * Which channels are required depends on the chart type.
201
+ * See ChartEncodingRules in encoding.ts for per-type requirements.
202
+ */
203
+ interface Encoding {
204
+ /** Horizontal position channel. */
205
+ x?: EncodingChannel;
206
+ /** Vertical position channel. */
207
+ y?: EncodingChannel;
208
+ /** Color channel (series differentiation or heatmap). */
209
+ color?: EncodingChannel;
210
+ /** Size channel (bubble charts, dot plots). */
211
+ size?: EncodingChannel;
212
+ /** Detail channel (group without encoding to a visual property). */
213
+ detail?: EncodingChannel;
214
+ }
215
+ /** Encoding channel for graph nodes and edges. Same structure as EncodingChannel. */
216
+ interface GraphEncodingChannel {
217
+ /** Data field name on the node/edge object. */
218
+ field: string;
219
+ /** How to interpret the field values. */
220
+ type?: FieldType;
221
+ }
222
+ /** Graph-specific encoding mapping visual properties to node/edge data fields. */
223
+ interface GraphEncoding {
224
+ /** Color mapping for nodes. */
225
+ nodeColor?: GraphEncodingChannel;
226
+ /** Size mapping for nodes. */
227
+ nodeSize?: GraphEncodingChannel;
228
+ /** Color mapping for edges. */
229
+ edgeColor?: GraphEncodingChannel;
230
+ /** Width mapping for edges. */
231
+ edgeWidth?: GraphEncodingChannel;
232
+ /** Label field for nodes. */
233
+ nodeLabel?: GraphEncodingChannel;
234
+ }
235
+ /** Layout algorithm for graph visualization. */
236
+ interface GraphLayoutConfig {
237
+ /** Layout algorithm type. */
238
+ type: 'force' | 'radial' | 'hierarchical';
239
+ /** Optional clustering configuration. */
240
+ clustering?: {
241
+ /** Field to group nodes by for cluster forces. */
242
+ field: string;
243
+ };
244
+ /** Charge strength for force layout. Negative values create repulsion. */
245
+ chargeStrength?: number;
246
+ /** Target distance between linked nodes. */
247
+ linkDistance?: number;
248
+ }
249
+ /** Style overrides for a chrome text element. */
250
+ interface ChromeTextStyle {
251
+ /** Font size in pixels. */
252
+ fontSize?: number;
253
+ /** Font weight (400 = normal, 600 = semibold, 700 = bold). */
254
+ fontWeight?: number;
255
+ /** Font family override. */
256
+ fontFamily?: string;
257
+ /** Text color (CSS color string). */
258
+ color?: string;
259
+ }
260
+ /** A chrome text element with optional style overrides. */
261
+ interface ChromeText {
262
+ /** The text content to display. */
263
+ text: string;
264
+ /** Optional style overrides. Theme defaults are used for any omitted property. */
265
+ style?: ChromeTextStyle;
266
+ /** Pixel offset for fine-tuning position. */
267
+ offset?: AnnotationOffset;
268
+ }
269
+ /**
270
+ * Editorial chrome elements: title, subtitle, source attribution, byline, footer.
271
+ * These are first-class structural elements, not string-only afterthoughts.
272
+ * Each element can be a simple string or a ChromeText object with style overrides.
273
+ */
274
+ interface Chrome {
275
+ /** Main title displayed above the visualization. */
276
+ title?: string | ChromeText;
277
+ /** Subtitle displayed below the title, typically providing context. */
278
+ subtitle?: string | ChromeText;
279
+ /** Data source attribution, displayed below the chart area. */
280
+ source?: string | ChromeText;
281
+ /** Author or organization byline. */
282
+ byline?: string | ChromeText;
283
+ /** Footer text, displayed at the very bottom. */
284
+ footer?: string | ChromeText;
285
+ }
286
+ /** Pixel offset for fine-grained annotation positioning. */
287
+ interface AnnotationOffset {
288
+ /** Horizontal pixel offset. */
289
+ dx?: number;
290
+ /** Vertical pixel offset. */
291
+ dy?: number;
292
+ }
293
+ /** Anchor direction for annotation label placement relative to the data point. */
294
+ type AnnotationAnchor = 'top' | 'bottom' | 'left' | 'right' | 'auto';
295
+ /** Base properties shared by all annotation types. */
296
+ interface AnnotationBase {
297
+ /** Human-readable label for the annotation. */
298
+ label?: string;
299
+ /** Fill color for the annotation element. */
300
+ fill?: string;
301
+ /** Stroke color for the annotation element. */
302
+ stroke?: string;
303
+ /** Opacity from 0 to 1. */
304
+ opacity?: number;
305
+ /** Z-index for render ordering. Higher values render on top. */
306
+ zIndex?: number;
307
+ }
308
+ /**
309
+ * Text annotation positioned at a data coordinate.
310
+ * Shows a callout label at a specific point in the chart.
311
+ */
312
+ interface TextAnnotation extends AnnotationBase {
313
+ type: 'text';
314
+ /** X-axis data value or position. */
315
+ x: string | number;
316
+ /** Y-axis data value or position. */
317
+ y: string | number;
318
+ /** The annotation text. Required for text annotations. */
319
+ text: string;
320
+ /** Font size override. */
321
+ fontSize?: number;
322
+ /** Font weight override. */
323
+ fontWeight?: number;
324
+ /** Pixel offset from the computed position. */
325
+ offset?: AnnotationOffset;
326
+ /** Anchor direction for label placement relative to the data point. */
327
+ anchor?: AnnotationAnchor;
328
+ /**
329
+ * Connector from label to anchor point.
330
+ * - `true` (default): straight line
331
+ * - `'curve'`: curved arrow with arrowhead
332
+ * - `false`: no connector
333
+ */
334
+ connector?: boolean | 'curve';
335
+ /** Per-endpoint offsets for the connector line. Allows fine-tuning where the connector starts and ends. */
336
+ connectorOffset?: {
337
+ /** Offset for the label-end of the connector. */
338
+ from?: AnnotationOffset;
339
+ /** Offset for the data-point-end of the connector. */
340
+ to?: AnnotationOffset;
341
+ };
342
+ /** Background color behind the text. Useful for readability over chart lines. */
343
+ background?: string;
344
+ }
345
+ /**
346
+ * Range annotation highlighting a region of the chart.
347
+ * Defined by x1/x2 (vertical band) or y1/y2 (horizontal band) or both (rectangle).
348
+ */
349
+ interface RangeAnnotation extends AnnotationBase {
350
+ type: 'range';
351
+ /** Start of the range on the x-axis. */
352
+ x1?: string | number;
353
+ /** End of the range on the x-axis. */
354
+ x2?: string | number;
355
+ /** Start of the range on the y-axis. */
356
+ y1?: string | number;
357
+ /** End of the range on the y-axis. */
358
+ y2?: string | number;
359
+ /** Pixel offset for the range label. */
360
+ labelOffset?: AnnotationOffset;
361
+ /** Anchor direction for the range label. */
362
+ labelAnchor?: AnnotationAnchor;
363
+ }
364
+ /**
365
+ * Reference line annotation: a horizontal or vertical line at a data value.
366
+ * Useful for baselines (zero), targets, or thresholds.
367
+ */
368
+ interface RefLineAnnotation extends AnnotationBase {
369
+ type: 'refline';
370
+ /** X-axis value for a vertical reference line. */
371
+ x?: string | number;
372
+ /** Y-axis value for a horizontal reference line. */
373
+ y?: string | number;
374
+ /** Line style. */
375
+ style?: 'solid' | 'dashed' | 'dotted';
376
+ /** Line width in pixels. */
377
+ strokeWidth?: number;
378
+ /** Pixel offset for the reference line label. */
379
+ labelOffset?: AnnotationOffset;
380
+ /** Anchor direction for the reference line label. */
381
+ labelAnchor?: AnnotationAnchor;
382
+ }
383
+ /** Discriminated union of all annotation types. */
384
+ type Annotation = TextAnnotation | RangeAnnotation | RefLineAnnotation;
385
+ /**
386
+ * Dark mode behavior.
387
+ * - "auto": respect system preference (prefers-color-scheme)
388
+ * - "force": always render in dark mode
389
+ * - "off": always render in light mode (default)
390
+ */
391
+ type DarkMode = 'auto' | 'force' | 'off';
392
+ /**
393
+ * User-facing theme configuration for overriding defaults.
394
+ * All fields are optional. The engine deep-merges these onto the default theme.
395
+ */
396
+ interface ThemeConfig {
397
+ /** Color palette overrides. */
398
+ colors?: {
399
+ /** Categorical palette for nominal data (array of CSS color strings). */
400
+ categorical?: string[];
401
+ /** Sequential palettes keyed by name. Each is an array of color stops. */
402
+ sequential?: Record<string, string[]>;
403
+ /** Diverging palettes keyed by name. Each is an array of color stops with a neutral midpoint. */
404
+ diverging?: Record<string, string[]>;
405
+ /** Background color. */
406
+ background?: string;
407
+ /** Default text color. */
408
+ text?: string;
409
+ /** Gridline color. */
410
+ gridline?: string;
411
+ /** Axis line and tick color. */
412
+ axis?: string;
413
+ };
414
+ /** Font overrides. */
415
+ fonts?: {
416
+ /** Primary font family. */
417
+ family?: string;
418
+ /** Monospace font family (for tabular numbers). */
419
+ mono?: string;
420
+ };
421
+ /** Spacing overrides in pixels. */
422
+ spacing?: {
423
+ /** Padding inside the chart container. */
424
+ padding?: number;
425
+ /** Gap between chrome elements (title to subtitle, etc.). */
426
+ chromeGap?: number;
427
+ };
428
+ /** Border radius for chart container and tooltips. */
429
+ borderRadius?: number;
430
+ }
431
+ /**
432
+ * Label density mode controlling how many data labels are shown.
433
+ * - 'all': show every label, skip collision detection
434
+ * - 'auto': show labels with collision detection (default)
435
+ * - 'endpoints': show only first and last per series (useful for line charts)
436
+ * - 'none': hide all labels (rely on tooltips and legend)
437
+ */
438
+ type LabelDensity = 'all' | 'auto' | 'endpoints' | 'none';
439
+ /** Label display configuration for chart data labels. */
440
+ interface LabelConfig {
441
+ /** How many labels to show. Defaults to 'auto'. */
442
+ density?: LabelDensity;
443
+ /** Number format override for label values (d3-format string, e.g. ",.0f"). */
444
+ format?: string;
445
+ /** Per-series pixel offsets for fine-tuning label positions, keyed by series name. */
446
+ offsets?: Record<string, AnnotationOffset>;
447
+ }
448
+ /** Legend display configuration. Overrides the responsive-default position. */
449
+ interface LegendConfig {
450
+ /** Override the legend position. If omitted, the responsive strategy decides. */
451
+ position?: LegendPosition;
452
+ /** Pixel offset for fine-tuning legend position. */
453
+ offset?: AnnotationOffset;
454
+ }
455
+ /** Data row: a plain object with string keys. */
456
+ type DataRow = Record<string, unknown>;
457
+ /**
458
+ * Chart specification: the primary input for standard chart types.
459
+ *
460
+ * Combines a chart type with data, encoding channels, editorial chrome,
461
+ * annotations, and configuration. The engine validates, normalizes, and
462
+ * compiles this into a ChartLayout.
463
+ */
464
+ interface ChartSpec {
465
+ /** The chart type to render. */
466
+ type: ChartType;
467
+ /** Data array: each element is a row with field values. */
468
+ data: DataRow[];
469
+ /** Encoding mapping data fields to visual channels. */
470
+ encoding: Encoding;
471
+ /** Editorial chrome (title, subtitle, source, etc.). */
472
+ chrome?: Chrome;
473
+ /** Data annotations (text callouts, highlighted ranges, reference lines). */
474
+ annotations?: Annotation[];
475
+ /** Label display configuration (density, format). */
476
+ labels?: LabelConfig;
477
+ /** Legend display configuration (position override). */
478
+ legend?: LegendConfig;
479
+ /** Whether the chart adapts to container width. Defaults to true. */
480
+ responsive?: boolean;
481
+ /** Theme configuration overrides. */
482
+ theme?: ThemeConfig;
483
+ /** Dark mode behavior. Defaults to "off". */
484
+ darkMode?: DarkMode;
485
+ }
486
+ /**
487
+ * Table specification: input for data table visualizations.
488
+ *
489
+ * Tables are a visualization type, not just an HTML grid. They support
490
+ * heatmap coloring, inline sparklines, sorted columns, search, and pagination.
491
+ */
492
+ interface TableSpec {
493
+ /** Discriminant: always "table". */
494
+ type: 'table';
495
+ /** Data array: each element is a row. */
496
+ data: DataRow[];
497
+ /** Column definitions controlling display, sorting, formatting, and mini-charts. */
498
+ columns: ColumnConfig[];
499
+ /** Optional field to use as a unique row identifier. */
500
+ rowKey?: string;
501
+ /** Editorial chrome. */
502
+ chrome?: Chrome;
503
+ /** Theme configuration overrides. */
504
+ theme?: ThemeConfig;
505
+ /** Dark mode behavior. */
506
+ darkMode?: DarkMode;
507
+ /** Enable client-side search/filter. */
508
+ search?: boolean;
509
+ /** Pagination configuration. True for defaults, or an object with pageSize. */
510
+ pagination?: boolean | {
511
+ pageSize: number;
512
+ };
513
+ /** Whether to stick the first column during horizontal scroll. */
514
+ stickyFirstColumn?: boolean;
515
+ /** Compact mode: reduced padding and font sizes. */
516
+ compact?: boolean;
517
+ /** Whether the table adapts to container width. Defaults to true. */
518
+ responsive?: boolean;
519
+ }
520
+ /** Graph node: must have an id, plus arbitrary data fields. */
521
+ interface GraphNode {
522
+ /** Unique identifier for the node. */
523
+ id: string;
524
+ /** Arbitrary data fields. */
525
+ [key: string]: unknown;
526
+ }
527
+ /** Graph edge: connects two nodes by id. */
528
+ interface GraphEdge {
529
+ /** Source node id. */
530
+ source: string;
531
+ /** Target node id. */
532
+ target: string;
533
+ /** Arbitrary data fields (weight, type, confidence, etc.). */
534
+ [key: string]: unknown;
535
+ }
536
+ /**
537
+ * Graph specification: input for network/relationship visualizations.
538
+ *
539
+ * Uses a nodes + edges data model instead of the flat data + encoding model
540
+ * used by chart types. The graph type is defined here for forward compatibility
541
+ * but rendering is deferred to a future phase.
542
+ */
543
+ interface GraphSpec {
544
+ /** Discriminant: always "graph". */
545
+ type: 'graph';
546
+ /** Node array. Each node must have an id field. */
547
+ nodes: GraphNode[];
548
+ /** Edge array. Each edge connects source and target node ids. */
549
+ edges: GraphEdge[];
550
+ /** Graph-specific encoding mapping visual properties to node/edge fields. */
551
+ encoding?: GraphEncoding;
552
+ /** Layout algorithm configuration. */
553
+ layout?: GraphLayoutConfig;
554
+ /** Editorial chrome. */
555
+ chrome?: Chrome;
556
+ /** Annotations. */
557
+ annotations?: Annotation[];
558
+ /** Theme configuration overrides. */
559
+ theme?: ThemeConfig;
560
+ /** Dark mode behavior. */
561
+ darkMode?: DarkMode;
562
+ }
563
+ /**
564
+ * Top-level visualization spec: discriminated union on the `type` field.
565
+ *
566
+ * This is the primary API contract. Users (and Claude) write VizSpec objects,
567
+ * the engine validates and compiles them into layout objects for rendering.
568
+ */
569
+ type VizSpec = ChartSpec | TableSpec | GraphSpec;
570
+ /** Chart spec without runtime data, for persistence/storage. */
571
+ type ChartSpecWithoutData = Omit<ChartSpec, 'data'>;
572
+ /** Table spec without runtime data and columns, for persistence/storage. Columns can be auto-generated via dataTable(). */
573
+ type TableSpecWithoutData = Omit<TableSpec, 'data' | 'columns'>;
574
+ /** Graph spec without runtime data, for persistence/storage. */
575
+ type GraphSpecWithoutData = Omit<GraphSpec, 'nodes' | 'edges'>;
576
+ /** Union of data-stripped spec types for persistence/storage. */
577
+ type StoredVizSpec = ChartSpecWithoutData | TableSpecWithoutData | GraphSpecWithoutData;
578
+ /** All valid chart type strings for runtime checking. */
579
+ declare const CHART_TYPES: ReadonlySet<string>;
580
+ /** Check if a spec is a ChartSpec (any standard chart type). */
581
+ declare function isChartSpec(spec: VizSpec): spec is ChartSpec;
582
+ /** Check if a spec is a TableSpec. */
583
+ declare function isTableSpec(spec: VizSpec): spec is TableSpec;
584
+ /** Check if a spec is a GraphSpec. */
585
+ declare function isGraphSpec(spec: VizSpec): spec is GraphSpec;
586
+ /** Check if an annotation is a TextAnnotation. */
587
+ declare function isTextAnnotation(annotation: Annotation): annotation is TextAnnotation;
588
+ /** Check if an annotation is a RangeAnnotation. */
589
+ declare function isRangeAnnotation(annotation: Annotation): annotation is RangeAnnotation;
590
+ /** Check if an annotation is a RefLineAnnotation. */
591
+ declare function isRefLineAnnotation(annotation: Annotation): annotation is RefLineAnnotation;
592
+
593
+ /**
594
+ * Per-chart-type encoding validation rules.
595
+ *
596
+ * Defines which encoding channels are required vs optional for each chart type.
597
+ * The engine compiler uses these rules to validate specs at runtime (TypeScript
598
+ * catches compile-time errors; these catch runtime JSON from Claude or APIs).
599
+ */
600
+
601
+ /** Constraint on what field types are valid for an encoding channel. */
602
+ interface ChannelRule {
603
+ /** Whether this channel is required for the chart type. */
604
+ required: boolean;
605
+ /** Allowed field types. If empty, any field type is accepted. */
606
+ allowedTypes: FieldType[];
607
+ }
608
+ /** Encoding rules for a single chart type: which channels are required/optional. */
609
+ interface EncodingRule {
610
+ x: ChannelRule;
611
+ y: ChannelRule;
612
+ color: ChannelRule;
613
+ size: ChannelRule;
614
+ detail: ChannelRule;
615
+ }
616
+ /**
617
+ * Encoding rules per chart type.
618
+ *
619
+ * Defines which channels are required and what field types they accept.
620
+ * The compiler uses this map to validate user specs at runtime.
621
+ *
622
+ * Key design decisions:
623
+ * - line/area: x is temporal/ordinal (the axis), y is quantitative (the value)
624
+ * - bar: horizontal bars, so y is the category axis, x is the value
625
+ * - column: vertical columns, so x is the category axis, y is the value
626
+ * - pie/donut: no x axis; y is the value (quantitative), color is the category
627
+ * - dot: y is the category, x is quantitative
628
+ * - scatter: both axes are quantitative
629
+ */
630
+ declare const CHART_ENCODING_RULES: Record<ChartType, EncodingRule>;
631
+ /** Encoding rule for a single graph visual channel. */
632
+ interface GraphChannelRule {
633
+ /** Whether this channel is required. */
634
+ required: boolean;
635
+ /** Allowed field types. Empty means any type. */
636
+ allowedTypes: FieldType[];
637
+ }
638
+ /**
639
+ * Encoding rules for graph visualizations.
640
+ *
641
+ * All graph encoding channels are optional since a graph can be rendered
642
+ * with just nodes and edges (uniform appearance). Encoding channels add
643
+ * visual differentiation based on data fields.
644
+ */
645
+ declare const GRAPH_ENCODING_RULES: Record<string, GraphChannelRule>;
646
+
647
+ /**
648
+ * Chart interaction event types.
649
+ *
650
+ * These types define the callback signatures for user interactions with
651
+ * chart elements: clicking marks, hovering, legend toggles, and annotation clicks.
652
+ *
653
+ * Event handlers are optional and passed through MountOptions (vanilla) or
654
+ * ChartProps (React). The vanilla adapter wires DOM event listeners to
655
+ * mark elements and constructs these typed events from the raw browser events.
656
+ */
657
+
658
+ /** Identifies a specific chrome text element (title, subtitle, source, byline, footer). */
659
+ type ChromeKey = 'title' | 'subtitle' | 'source' | 'byline' | 'footer';
660
+ /**
661
+ * Discriminated union of all element edit events.
662
+ * Fired by the `onEdit` callback when any editable chart element is repositioned.
663
+ */
664
+ type ElementEdit = {
665
+ type: 'annotation';
666
+ annotation: TextAnnotation;
667
+ offset: AnnotationOffset;
668
+ } | {
669
+ type: 'annotation-connector';
670
+ annotation: TextAnnotation;
671
+ endpoint: 'from' | 'to';
672
+ offset: AnnotationOffset;
673
+ } | {
674
+ type: 'range-label';
675
+ annotation: RangeAnnotation;
676
+ labelOffset: AnnotationOffset;
677
+ } | {
678
+ type: 'refline-label';
679
+ annotation: RefLineAnnotation;
680
+ labelOffset: AnnotationOffset;
681
+ } | {
682
+ type: 'chrome';
683
+ key: ChromeKey;
684
+ text: string;
685
+ offset: AnnotationOffset;
686
+ } | {
687
+ type: 'series-label';
688
+ series: string;
689
+ offset: AnnotationOffset;
690
+ } | {
691
+ type: 'legend';
692
+ offset: AnnotationOffset;
693
+ };
694
+ /**
695
+ * Event fired when a user interacts with a data mark (bar, point, line segment, etc.).
696
+ *
697
+ * Contains the underlying data row, the series it belongs to (if multi-series),
698
+ * the position within the chart container, and the raw browser MouseEvent.
699
+ */
700
+ interface MarkEvent {
701
+ /** The data row associated with the mark that was interacted with. */
702
+ datum: DataRow;
703
+ /** Series identifier, if the chart has multiple series (e.g. multi-line). */
704
+ series?: string;
705
+ /** Position of the interaction relative to the chart container. */
706
+ position: {
707
+ x: number;
708
+ y: number;
709
+ };
710
+ /** The raw browser MouseEvent. */
711
+ event: MouseEvent;
712
+ }
713
+ /**
714
+ * Event handler callbacks for chart interactions.
715
+ *
716
+ * All handlers are optional. Pass these through MountOptions (vanilla adapter)
717
+ * or ChartProps (React component) to receive interaction callbacks.
718
+ */
719
+ interface ChartEventHandlers {
720
+ /** Called when a data mark is clicked. */
721
+ onMarkClick?: (event: MarkEvent) => void;
722
+ /** Called when the mouse enters a data mark. */
723
+ onMarkHover?: (event: MarkEvent) => void;
724
+ /** Called when the mouse leaves a data mark. */
725
+ onMarkLeave?: () => void;
726
+ /** Called when a legend entry is toggled (clicked to show/hide a series). */
727
+ onLegendToggle?: (series: string, visible: boolean) => void;
728
+ /** Called when an annotation element is clicked. */
729
+ onAnnotationClick?: (annotation: Annotation, event: MouseEvent) => void;
730
+ /** Called when a text annotation label is dragged to a new position. */
731
+ onAnnotationEdit?: (annotation: TextAnnotation, updatedOffset: AnnotationOffset) => void;
732
+ /** Unified edit callback. Fires for any editable chart element (annotations, chrome, legend, series labels). */
733
+ onEdit?: (edit: ElementEdit) => void;
734
+ }
735
+
736
+ /**
737
+ * Theme types: color palettes, typography, spacing, and chrome defaults.
738
+ *
739
+ * Theme is the user-facing partial config (all optional).
740
+ * ResolvedTheme is the engine-internal fully resolved version (no optionals).
741
+ */
742
+ /** Color palettes for the visualization. */
743
+ interface ThemeColors {
744
+ /** Categorical palette for nominal data. Array of CSS color strings. */
745
+ categorical: string[];
746
+ /** Sequential palettes keyed by name. Each is an array of color stops from light to dark. */
747
+ sequential: Record<string, string[]>;
748
+ /** Diverging palettes keyed by name. Each is an array of color stops with a neutral midpoint. */
749
+ diverging: Record<string, string[]>;
750
+ /** Background color for the visualization container. */
751
+ background: string;
752
+ /** Default text color. */
753
+ text: string;
754
+ /** Gridline color. */
755
+ gridline: string;
756
+ /** Axis line and tick color. */
757
+ axis: string;
758
+ /** Annotation fill color. */
759
+ annotationFill: string;
760
+ /** Annotation text color. */
761
+ annotationText: string;
762
+ }
763
+ /** Font size presets for the typography scale. */
764
+ interface ThemeFontSizes {
765
+ /** Title font size in pixels. */
766
+ title: number;
767
+ /** Subtitle font size in pixels. */
768
+ subtitle: number;
769
+ /** Body/label font size in pixels. */
770
+ body: number;
771
+ /** Small text (source, footer) font size in pixels. */
772
+ small: number;
773
+ /** Axis tick label font size in pixels. */
774
+ axisTick: number;
775
+ }
776
+ /** Font weight presets. */
777
+ interface ThemeFontWeights {
778
+ /** Normal text weight. */
779
+ normal: number;
780
+ /** Medium text weight (subtitles). */
781
+ medium: number;
782
+ /** Semibold text weight (titles). */
783
+ semibold: number;
784
+ /** Bold text weight. */
785
+ bold: number;
786
+ }
787
+ /** Complete typography configuration. */
788
+ interface ThemeFonts {
789
+ /** Primary font family. */
790
+ family: string;
791
+ /** Monospace font family (for tabular numbers). */
792
+ mono: string;
793
+ /** Font sizes. */
794
+ sizes: ThemeFontSizes;
795
+ /** Font weights. */
796
+ weights: ThemeFontWeights;
797
+ }
798
+ /** Spacing configuration in pixels. */
799
+ interface ThemeSpacing {
800
+ /** Padding inside the visualization container (all sides). */
801
+ padding: number;
802
+ /** Gap between chrome elements (title to subtitle, subtitle to chart, etc.). */
803
+ chromeGap: number;
804
+ /** Gap between the last chrome element and the chart area. */
805
+ chromeToChart: number;
806
+ /** Gap between chart area and source/footer below. */
807
+ chartToFooter: number;
808
+ /** Internal padding within the chart area (axes margins). */
809
+ axisMargin: number;
810
+ }
811
+ /** Default style configuration for a chrome text element. */
812
+ interface ChromeDefaults {
813
+ /** Font size in pixels. */
814
+ fontSize: number;
815
+ /** Font weight. */
816
+ fontWeight: number;
817
+ /** Text color (CSS color string). */
818
+ color: string;
819
+ /** Line height multiplier. */
820
+ lineHeight: number;
821
+ }
822
+ /** Default chrome styles for each element type. */
823
+ interface ThemeChromeDefaults {
824
+ title: ChromeDefaults;
825
+ subtitle: ChromeDefaults;
826
+ source: ChromeDefaults;
827
+ byline: ChromeDefaults;
828
+ footer: ChromeDefaults;
829
+ }
830
+ /**
831
+ * Complete theme interface. Used internally after merging user overrides
832
+ * onto defaults. All fields are required here (this is what the engine
833
+ * works with).
834
+ *
835
+ * Users provide ThemeConfig (from spec.ts) which is the partial/optional
836
+ * version. The theme resolver deep-merges ThemeConfig onto the default Theme
837
+ * to produce a ResolvedTheme.
838
+ */
839
+ interface Theme {
840
+ /** Color palettes. */
841
+ colors: ThemeColors;
842
+ /** Typography settings. */
843
+ fonts: ThemeFonts;
844
+ /** Spacing values in pixels. */
845
+ spacing: ThemeSpacing;
846
+ /** Border radius for containers and tooltips. */
847
+ borderRadius: number;
848
+ /** Default chrome text styles. */
849
+ chrome: ThemeChromeDefaults;
850
+ }
851
+ /**
852
+ * Fully resolved theme with no optional fields.
853
+ *
854
+ * This is the result of resolveTheme(): the default theme with user
855
+ * overrides deep-merged in. Every property is guaranteed to have a value.
856
+ * The engine uses ResolvedTheme internally so it never needs null checks.
857
+ *
858
+ * Structurally identical to Theme (both have all required fields), but
859
+ * exists as a separate type for semantic clarity: Theme is the default
860
+ * definition, ResolvedTheme is the runtime-resolved instance.
861
+ */
862
+ interface ResolvedTheme extends Theme {
863
+ /** Whether dark mode adaptations have been applied to this theme. */
864
+ isDark: boolean;
865
+ }
866
+
867
+ /** A rectangle defined by position and dimensions. */
868
+ interface Rect {
869
+ x: number;
870
+ y: number;
871
+ width: number;
872
+ height: number;
873
+ }
874
+ /** Margins around a region (top, right, bottom, left). */
875
+ interface Margins {
876
+ top: number;
877
+ right: number;
878
+ bottom: number;
879
+ left: number;
880
+ }
881
+ /** A 2D point. */
882
+ interface Point {
883
+ x: number;
884
+ y: number;
885
+ }
886
+ /** Resolved text style with all computed values. */
887
+ interface TextStyle {
888
+ /** Font family. */
889
+ fontFamily: string;
890
+ /** Font size in pixels. */
891
+ fontSize: number;
892
+ /** Font weight. */
893
+ fontWeight: number;
894
+ /** Text color (CSS color string). */
895
+ fill: string;
896
+ /** Line height multiplier. */
897
+ lineHeight: number;
898
+ /** Text anchor for SVG: start, middle, or end. */
899
+ textAnchor?: 'start' | 'middle' | 'end';
900
+ /** Dominant baseline for SVG text vertical alignment. */
901
+ dominantBaseline?: 'auto' | 'hanging' | 'central' | 'text-after-edge';
902
+ /** Font variant (e.g. "tabular-nums" for fixed-width digits). */
903
+ fontVariant?: string;
904
+ }
905
+ /** Cell style for table cells. */
906
+ interface CellStyle {
907
+ /** Background color. */
908
+ backgroundColor?: string;
909
+ /** Text color. */
910
+ color?: string;
911
+ /** Font weight. */
912
+ fontWeight?: number;
913
+ /** Font variant. */
914
+ fontVariant?: string;
915
+ }
916
+ /** A single resolved chrome text element with computed position and style. */
917
+ interface ResolvedChromeElement {
918
+ /** The text content. */
919
+ text: string;
920
+ /** X position in the layout coordinate system. */
921
+ x: number;
922
+ /** Y position (baseline) in the layout coordinate system. */
923
+ y: number;
924
+ /** Maximum width for line wrapping. */
925
+ maxWidth: number;
926
+ /** Computed text style. */
927
+ style: TextStyle;
928
+ }
929
+ /**
930
+ * Fully resolved chrome with computed positions for all elements.
931
+ * Only present elements are included (no undefined checks needed at render time).
932
+ */
933
+ interface ResolvedChrome {
934
+ /** Total height consumed by chrome elements above the chart area. */
935
+ topHeight: number;
936
+ /** Total height consumed by chrome elements below the chart area. */
937
+ bottomHeight: number;
938
+ /** Resolved chrome elements. Only present if specified in the spec. */
939
+ title?: ResolvedChromeElement;
940
+ subtitle?: ResolvedChromeElement;
941
+ source?: ResolvedChromeElement;
942
+ byline?: ResolvedChromeElement;
943
+ footer?: ResolvedChromeElement;
944
+ }
945
+ /** A single axis tick with computed position and formatted label. */
946
+ interface AxisTick {
947
+ /** The raw data value at this tick. */
948
+ value: unknown;
949
+ /** Pixel position along the axis. */
950
+ position: number;
951
+ /** Formatted label string for display. */
952
+ label: string;
953
+ }
954
+ /** A single gridline with computed positions. */
955
+ interface Gridline {
956
+ /** Pixel position along the axis. */
957
+ position: number;
958
+ /** Whether this is a major or minor gridline. */
959
+ major: boolean;
960
+ }
961
+ /** Resolved axis layout with computed tick positions and labels. */
962
+ interface AxisLayout {
963
+ /** Axis ticks with positions and labels. */
964
+ ticks: AxisTick[];
965
+ /** Gridlines at tick positions. */
966
+ gridlines: Gridline[];
967
+ /** Axis label text (e.g. "GDP Growth (%)"). */
968
+ label?: string;
969
+ /** Label style. */
970
+ labelStyle?: TextStyle;
971
+ /** Tick label style. */
972
+ tickLabelStyle: TextStyle;
973
+ /** Axis line start position. */
974
+ start: Point;
975
+ /** Axis line end position. */
976
+ end: Point;
977
+ }
978
+ /** Accessibility attributes for a mark. */
979
+ interface MarkAria {
980
+ /** ARIA label for the mark. */
981
+ label: string;
982
+ /** Optional longer description. */
983
+ description?: string;
984
+ /** ARIA role override. */
985
+ role?: string;
986
+ }
987
+ /**
988
+ * Line mark: a series of connected points.
989
+ * Used by line charts and area chart boundaries.
990
+ */
991
+ interface LineMark {
992
+ type: 'line';
993
+ /** Ordered array of points defining the line path. */
994
+ points: Point[];
995
+ /** Pre-computed SVG path string (D3 monotone curve). When present, renderers
996
+ * should use this instead of reconstructing straight M/L segments from points. */
997
+ path?: string;
998
+ /** Stroke color. */
999
+ stroke: string;
1000
+ /** Stroke width in pixels. */
1001
+ strokeWidth: number;
1002
+ /** Line dash pattern (empty for solid). */
1003
+ strokeDasharray?: string;
1004
+ /** Series identifier (for multi-series charts). */
1005
+ seriesKey?: string;
1006
+ /** Original data rows for this series. */
1007
+ data: Record<string, unknown>[];
1008
+ /** Resolved label after collision detection. */
1009
+ label?: ResolvedLabel;
1010
+ /** Accessibility attributes. */
1011
+ aria: MarkAria;
1012
+ }
1013
+ /**
1014
+ * Area mark: a filled region bounded by a top line and a baseline.
1015
+ * Used by area charts.
1016
+ */
1017
+ interface AreaMark {
1018
+ type: 'area';
1019
+ /** Upper boundary points. */
1020
+ topPoints: Point[];
1021
+ /** Lower boundary points (baseline, usually y=0). */
1022
+ bottomPoints: Point[];
1023
+ /** SVG path string for the complete area shape. */
1024
+ path: string;
1025
+ /** SVG path string for just the top boundary (for stroking the data line only). */
1026
+ topPath: string;
1027
+ /** Fill color. */
1028
+ fill: string;
1029
+ /** Fill opacity. */
1030
+ fillOpacity: number;
1031
+ /** Optional stroke for the top boundary. */
1032
+ stroke?: string;
1033
+ /** Stroke width. */
1034
+ strokeWidth?: number;
1035
+ /** Series identifier. */
1036
+ seriesKey?: string;
1037
+ /** Original data rows. */
1038
+ data: Record<string, unknown>[];
1039
+ /** Accessibility attributes. */
1040
+ aria: MarkAria;
1041
+ }
1042
+ /**
1043
+ * Rect mark: a rectangle.
1044
+ * Used by bar charts, column charts, and heatmap cells.
1045
+ */
1046
+ interface RectMark {
1047
+ type: 'rect';
1048
+ /** X position. */
1049
+ x: number;
1050
+ /** Y position. */
1051
+ y: number;
1052
+ /** Width. */
1053
+ width: number;
1054
+ /** Height. */
1055
+ height: number;
1056
+ /** Fill color. */
1057
+ fill: string;
1058
+ /** Stroke color. */
1059
+ stroke?: string;
1060
+ /** Stroke width. */
1061
+ strokeWidth?: number;
1062
+ /** Corner radius. */
1063
+ cornerRadius?: number;
1064
+ /** Original data row. */
1065
+ data: Record<string, unknown>;
1066
+ /** Resolved label. */
1067
+ label?: ResolvedLabel;
1068
+ /** Accessibility attributes. */
1069
+ aria: MarkAria;
1070
+ }
1071
+ /**
1072
+ * Arc mark: a pie/donut slice.
1073
+ * Used by pie and donut charts.
1074
+ */
1075
+ interface ArcMark {
1076
+ type: 'arc';
1077
+ /** SVG path string for the arc. */
1078
+ path: string;
1079
+ /** Centroid point (center of the arc, for label positioning). */
1080
+ centroid: Point;
1081
+ /** Center of the pie/donut chart (for SVG translate). */
1082
+ center: Point;
1083
+ /** Inner radius (0 for pie, >0 for donut). */
1084
+ innerRadius: number;
1085
+ /** Outer radius. */
1086
+ outerRadius: number;
1087
+ /** Start angle in radians. */
1088
+ startAngle: number;
1089
+ /** End angle in radians. */
1090
+ endAngle: number;
1091
+ /** Fill color. */
1092
+ fill: string;
1093
+ /** Stroke color (usually white for slice separation). */
1094
+ stroke: string;
1095
+ /** Stroke width. */
1096
+ strokeWidth: number;
1097
+ /** Original data row. */
1098
+ data: Record<string, unknown>;
1099
+ /** Resolved label. */
1100
+ label?: ResolvedLabel;
1101
+ /** Accessibility attributes. */
1102
+ aria: MarkAria;
1103
+ }
1104
+ /**
1105
+ * Point mark: a circle or dot.
1106
+ * Used by scatter/bubble charts and dot plots.
1107
+ */
1108
+ interface PointMark {
1109
+ type: 'point';
1110
+ /** Center x position. */
1111
+ cx: number;
1112
+ /** Center y position. */
1113
+ cy: number;
1114
+ /** Radius in pixels. */
1115
+ r: number;
1116
+ /** Fill color. */
1117
+ fill: string;
1118
+ /** Stroke color. */
1119
+ stroke: string;
1120
+ /** Stroke width. */
1121
+ strokeWidth: number;
1122
+ /** Fill opacity. */
1123
+ fillOpacity?: number;
1124
+ /** Original data row. */
1125
+ data: Record<string, unknown>;
1126
+ /** Resolved label. */
1127
+ label?: ResolvedLabel;
1128
+ /** Accessibility attributes. */
1129
+ aria: MarkAria;
1130
+ }
1131
+ /** Discriminated union of all mark types. */
1132
+ type Mark = LineMark | AreaMark | RectMark | ArcMark | PointMark;
1133
+ /**
1134
+ * A resolved label: text with a computed position after collision detection.
1135
+ * The collision engine determines whether labels are visible or demoted to tooltip-only.
1136
+ */
1137
+ interface ResolvedLabel {
1138
+ /** Label text content. */
1139
+ text: string;
1140
+ /** Computed x position. */
1141
+ x: number;
1142
+ /** Computed y position (baseline). */
1143
+ y: number;
1144
+ /** Text style. */
1145
+ style: TextStyle;
1146
+ /** Whether this label is visible or was demoted to tooltip-only by collision detection. */
1147
+ visible: boolean;
1148
+ /** If not at the anchor point, draw a connector line from label to anchor. */
1149
+ connector?: {
1150
+ /** Connector start (at the label). */
1151
+ from: Point;
1152
+ /** Connector end (at the data point). */
1153
+ to: Point;
1154
+ /** Connector line color. */
1155
+ stroke: string;
1156
+ /** Connector style: straight line, curved arrow, or directional caret. */
1157
+ style: 'straight' | 'curve' | 'caret';
1158
+ };
1159
+ /** Background color behind the label text. */
1160
+ background?: string;
1161
+ }
1162
+ /** A resolved annotation with computed pixel positions. */
1163
+ interface ResolvedAnnotation {
1164
+ /** Original annotation type. */
1165
+ type: 'text' | 'range' | 'refline';
1166
+ /** Label text (if any). */
1167
+ label?: ResolvedLabel;
1168
+ /** For range: the highlighted rectangle in pixel coordinates. */
1169
+ rect?: Rect;
1170
+ /** For refline: the line start and end in pixel coordinates. */
1171
+ line?: {
1172
+ start: Point;
1173
+ end: Point;
1174
+ };
1175
+ /** Fill color. */
1176
+ fill?: string;
1177
+ /** Stroke color. */
1178
+ stroke?: string;
1179
+ /** Opacity. */
1180
+ opacity?: number;
1181
+ /** Line dash pattern for reflines. */
1182
+ strokeDasharray?: string;
1183
+ /** Stroke width. */
1184
+ strokeWidth?: number;
1185
+ /** Z-index for render ordering. Higher values render on top. */
1186
+ zIndex?: number;
1187
+ }
1188
+ /** A single entry in the legend. */
1189
+ interface LegendEntry {
1190
+ /** The label text (category name or range description). */
1191
+ label: string;
1192
+ /** The color swatch. */
1193
+ color: string;
1194
+ /** Shape of the swatch (matches the mark type). */
1195
+ shape: 'circle' | 'square' | 'line';
1196
+ /** Whether this entry is currently highlighted/active. */
1197
+ active?: boolean;
1198
+ }
1199
+ /** Resolved legend layout with position and entries. */
1200
+ interface LegendLayout {
1201
+ /** Where the legend is positioned relative to the chart area. */
1202
+ position: 'top' | 'right' | 'bottom' | 'bottom-right' | 'inline';
1203
+ /** Legend entries. */
1204
+ entries: LegendEntry[];
1205
+ /** Bounding box for the legend (pixel coordinates). */
1206
+ bounds: Rect;
1207
+ /** Entry label style. */
1208
+ labelStyle: TextStyle;
1209
+ /** Swatch size in pixels. */
1210
+ swatchSize: number;
1211
+ /** Gap between swatch and label. */
1212
+ swatchGap: number;
1213
+ /** Gap between entries. */
1214
+ entryGap: number;
1215
+ }
1216
+ /** A single field-value pair in a tooltip. */
1217
+ interface TooltipField {
1218
+ /** Field label (e.g. "GDP Growth"). */
1219
+ label: string;
1220
+ /** Formatted value (e.g. "4.2%"). */
1221
+ value: string;
1222
+ /** Optional color swatch for series identification. */
1223
+ color?: string;
1224
+ }
1225
+ /** Tooltip content descriptor for a data point. */
1226
+ interface TooltipContent {
1227
+ /** Title line (e.g. the x-axis value like "2020-Q1"). */
1228
+ title?: string;
1229
+ /** Field-value pairs to display. */
1230
+ fields: TooltipField[];
1231
+ }
1232
+ /** Accessibility metadata for the entire visualization. */
1233
+ interface A11yMetadata {
1234
+ /** Generated alt text describing the visualization. */
1235
+ altText: string;
1236
+ /** Tabular data fallback for screen readers. Each inner array is a row. */
1237
+ dataTableFallback: unknown[][];
1238
+ /** ARIA role for the visualization root element. */
1239
+ role: string;
1240
+ /** Whether the visualization is keyboard-navigable. */
1241
+ keyboardNavigable: boolean;
1242
+ }
1243
+ /**
1244
+ * ChartLayout: the complete engine output for chart visualizations.
1245
+ *
1246
+ * Contains everything an adapter needs to render the chart: dimensions,
1247
+ * chrome text, axes, data marks, annotations, legend, tooltip descriptors,
1248
+ * and accessibility metadata. All values are fully computed pixel positions
1249
+ * and resolved colors.
1250
+ */
1251
+ interface ChartLayout {
1252
+ /** The chart drawing area (after chrome, axes, and legend are subtracted). */
1253
+ area: Rect;
1254
+ /** Resolved chrome text elements with positions and styles. */
1255
+ chrome: ResolvedChrome;
1256
+ /** Resolved axis layouts. */
1257
+ axes: {
1258
+ x?: AxisLayout;
1259
+ y?: AxisLayout;
1260
+ };
1261
+ /** Data marks: the visual representation of data points. */
1262
+ marks: Mark[];
1263
+ /** Resolved annotations with pixel positions. */
1264
+ annotations: ResolvedAnnotation[];
1265
+ /** Legend layout (position, entries, bounds). */
1266
+ legend: LegendLayout;
1267
+ /** Tooltip descriptors keyed by a mark identifier. */
1268
+ tooltipDescriptors: Map<string, TooltipContent>;
1269
+ /** Accessibility metadata. */
1270
+ a11y: A11yMetadata;
1271
+ /** The resolved theme used for rendering. */
1272
+ theme: ResolvedTheme;
1273
+ /** Total SVG dimensions. */
1274
+ dimensions: {
1275
+ width: number;
1276
+ height: number;
1277
+ };
1278
+ }
1279
+ /** A resolved column definition with computed properties. */
1280
+ interface ResolvedColumn {
1281
+ /** Column key (data field name). */
1282
+ key: string;
1283
+ /** Display label. */
1284
+ label: string;
1285
+ /** Computed width in pixels. */
1286
+ width: number;
1287
+ /** Whether sorting is enabled. */
1288
+ sortable: boolean;
1289
+ /** Text alignment. */
1290
+ align: 'left' | 'center' | 'right';
1291
+ /** Column cell type (determines rendering strategy). */
1292
+ cellType: 'text' | 'heatmap' | 'category' | 'bar' | 'sparkline' | 'image' | 'flag';
1293
+ }
1294
+ /** Base properties for all table cell types. */
1295
+ interface TableCellBase {
1296
+ /** Raw value from the data. */
1297
+ value: unknown;
1298
+ /** Formatted display value. */
1299
+ formattedValue: string;
1300
+ /** Computed cell style. */
1301
+ style: CellStyle;
1302
+ /** ARIA label for the cell. */
1303
+ aria?: string;
1304
+ }
1305
+ /** Plain text cell. */
1306
+ interface TextTableCell extends TableCellBase {
1307
+ cellType: 'text';
1308
+ }
1309
+ /** Heatmap-colored cell. */
1310
+ interface HeatmapTableCell extends TableCellBase {
1311
+ cellType: 'heatmap';
1312
+ }
1313
+ /** Category-colored cell. */
1314
+ interface CategoryTableCell extends TableCellBase {
1315
+ cellType: 'category';
1316
+ }
1317
+ /** Cell with an inline bar visualization. */
1318
+ interface BarTableCell extends TableCellBase {
1319
+ cellType: 'bar';
1320
+ /** Bar width as a proportion (0 to 1) of available cell width. */
1321
+ barWidth: number;
1322
+ /** Bar left-edge offset as a proportion (0 to 1). 0 = left edge. */
1323
+ barOffset: number;
1324
+ /** Bar fill color. */
1325
+ barColor: string;
1326
+ /** Whether this bar represents a negative value. */
1327
+ isNegative: boolean;
1328
+ }
1329
+ /** Normalized sparkline data ready for rendering. */
1330
+ interface SparklineData {
1331
+ /** Sparkline type. */
1332
+ type: 'line' | 'bar' | 'column';
1333
+ /** Normalized points in 0-1 range (for line type: x/y coordinates). */
1334
+ points: Array<{
1335
+ x: number;
1336
+ y: number;
1337
+ }>;
1338
+ /** For bar/column: widths or heights as 0-1 proportions. */
1339
+ bars: number[];
1340
+ /** Sparkline stroke/fill color. */
1341
+ color: string;
1342
+ /** Number of data points. */
1343
+ count: number;
1344
+ /** Raw value of the first data point. */
1345
+ startValue: number;
1346
+ /** Raw value of the last data point. */
1347
+ endValue: number;
1348
+ }
1349
+ /** Cell with an inline sparkline. */
1350
+ interface SparklineTableCell extends TableCellBase {
1351
+ cellType: 'sparkline';
1352
+ /** Sparkline rendering data (normalized points, color, type). Null when no valid data. */
1353
+ sparklineData: SparklineData | null;
1354
+ }
1355
+ /** Cell with an image. */
1356
+ interface ImageTableCell extends TableCellBase {
1357
+ cellType: 'image';
1358
+ /** Image URL. */
1359
+ src: string;
1360
+ /** Image width. */
1361
+ imageWidth: number;
1362
+ /** Image height. */
1363
+ imageHeight: number;
1364
+ /** Whether to apply rounded styling. */
1365
+ rounded: boolean;
1366
+ }
1367
+ /** Cell displaying a flag. */
1368
+ interface FlagTableCell extends TableCellBase {
1369
+ cellType: 'flag';
1370
+ /** Country code or flag identifier. */
1371
+ countryCode: string;
1372
+ }
1373
+ /** Discriminated union of all table cell types. */
1374
+ type TableCell = TextTableCell | HeatmapTableCell | CategoryTableCell | BarTableCell | SparklineTableCell | ImageTableCell | FlagTableCell;
1375
+ /** A resolved table row. */
1376
+ interface TableRow {
1377
+ /** Unique row identifier. */
1378
+ id: string;
1379
+ /** Resolved cells in column order. */
1380
+ cells: TableCell[];
1381
+ /** Original data row. */
1382
+ data: Record<string, unknown>;
1383
+ }
1384
+ /** Pagination state for the table. */
1385
+ interface PaginationState {
1386
+ /** Current page (0-indexed). */
1387
+ page: number;
1388
+ /** Rows per page. */
1389
+ pageSize: number;
1390
+ /** Total number of rows. */
1391
+ totalRows: number;
1392
+ /** Total number of pages. */
1393
+ totalPages: number;
1394
+ }
1395
+ /** Sort state for the table. */
1396
+ interface SortState {
1397
+ /** Column key being sorted. */
1398
+ column: string;
1399
+ /** Sort direction. */
1400
+ direction: 'asc' | 'desc';
1401
+ }
1402
+ /**
1403
+ * TableLayout: the complete engine output for table visualizations.
1404
+ *
1405
+ * Contains resolved columns, rows with computed cell values and styles,
1406
+ * pagination, sort, search state, and accessibility metadata.
1407
+ */
1408
+ interface TableLayout {
1409
+ /** Resolved chrome text elements. */
1410
+ chrome: ResolvedChrome;
1411
+ /** Resolved column definitions. */
1412
+ columns: ResolvedColumn[];
1413
+ /** Resolved table rows with computed cell values and styles. */
1414
+ rows: TableRow[];
1415
+ /** Current sort state. */
1416
+ sort?: SortState;
1417
+ /** Pagination state. */
1418
+ pagination?: PaginationState;
1419
+ /** Whether search is enabled. */
1420
+ search: {
1421
+ enabled: boolean;
1422
+ placeholder: string;
1423
+ query: string;
1424
+ };
1425
+ /** Whether the first column is sticky. */
1426
+ stickyFirstColumn: boolean;
1427
+ /** Whether compact mode is active. */
1428
+ compact: boolean;
1429
+ /** Accessibility metadata. */
1430
+ a11y: {
1431
+ caption: string;
1432
+ summary: string;
1433
+ };
1434
+ /** The resolved theme. */
1435
+ theme: ResolvedTheme;
1436
+ }
1437
+ /** A resolved graph node with computed position and visual properties. */
1438
+ interface GraphNodeLayout {
1439
+ /** Node id. */
1440
+ id: string;
1441
+ /** Computed x position. */
1442
+ x: number;
1443
+ /** Computed y position. */
1444
+ y: number;
1445
+ /** Node radius in pixels. */
1446
+ radius: number;
1447
+ /** Fill color. */
1448
+ fill: string;
1449
+ /** Stroke color. */
1450
+ stroke: string;
1451
+ /** Stroke width. */
1452
+ strokeWidth: number;
1453
+ /** Node label. */
1454
+ label?: ResolvedLabel;
1455
+ /** Original node data. */
1456
+ data: Record<string, unknown>;
1457
+ /** Community/cluster identifier (from clustering config). */
1458
+ community?: string;
1459
+ /** Accessibility attributes. */
1460
+ aria: MarkAria;
1461
+ }
1462
+ /** A resolved graph edge with computed positions and visual properties. */
1463
+ interface GraphEdgeLayout {
1464
+ /** Source node id. */
1465
+ source: string;
1466
+ /** Target node id. */
1467
+ target: string;
1468
+ /** Source x position. */
1469
+ x1: number;
1470
+ /** Source y position. */
1471
+ y1: number;
1472
+ /** Target x position. */
1473
+ x2: number;
1474
+ /** Target y position. */
1475
+ y2: number;
1476
+ /** Stroke color. */
1477
+ stroke: string;
1478
+ /** Stroke width. */
1479
+ strokeWidth: number;
1480
+ /** Line style. */
1481
+ style: 'solid' | 'dashed' | 'dotted';
1482
+ /** Original edge data. */
1483
+ data: Record<string, unknown>;
1484
+ }
1485
+ /**
1486
+ * GraphLayout: the complete engine output for network graph visualizations.
1487
+ *
1488
+ * Note: GraphLayout is defined here for forward compatibility but the engine
1489
+ * won't produce it until the graph renderer is implemented in a future phase.
1490
+ */
1491
+ interface GraphLayout {
1492
+ /** The graph drawing area. */
1493
+ area: Rect;
1494
+ /** Resolved chrome text. */
1495
+ chrome: ResolvedChrome;
1496
+ /** Resolved node positions and visual properties. */
1497
+ nodes: GraphNodeLayout[];
1498
+ /** Resolved edge positions and visual properties. */
1499
+ edges: GraphEdgeLayout[];
1500
+ /** Legend layout. */
1501
+ legend: LegendLayout;
1502
+ /** Tooltip descriptors. */
1503
+ tooltipDescriptors: Map<string, TooltipContent>;
1504
+ /** Accessibility metadata. */
1505
+ a11y: A11yMetadata;
1506
+ /** The resolved theme. */
1507
+ theme: ResolvedTheme;
1508
+ /** Total dimensions. */
1509
+ dimensions: {
1510
+ width: number;
1511
+ height: number;
1512
+ };
1513
+ }
1514
+ /** Function signature for text measurement provided by adapters. */
1515
+ type MeasureTextFn = (text: string, fontSize: number, fontWeight?: number) => {
1516
+ width: number;
1517
+ height: number;
1518
+ };
1519
+ /**
1520
+ * Options passed to the engine's compile functions.
1521
+ *
1522
+ * Width and height define the total available space. The engine subtracts
1523
+ * chrome, axes, and legend to compute the chart drawing area.
1524
+ */
1525
+ interface CompileOptions {
1526
+ /** Total available width in pixels. */
1527
+ width: number;
1528
+ /** Total available height in pixels. */
1529
+ height: number;
1530
+ /** Theme overrides. */
1531
+ theme?: ThemeConfig;
1532
+ /**
1533
+ * Resolved dark mode boolean.
1534
+ *
1535
+ * Note: this is a boolean, not the DarkMode union ("auto" | "force" | "off").
1536
+ * Adapters resolve "auto" by checking window.matchMedia('(prefers-color-scheme: dark)')
1537
+ * before calling compile. The engine always receives a resolved boolean.
1538
+ */
1539
+ darkMode?: boolean;
1540
+ /**
1541
+ * Real text measurement function provided by the adapter.
1542
+ * Uses a hidden canvas or DOM element for accurate text dimensions.
1543
+ * If not provided, the engine falls back to heuristic estimation.
1544
+ */
1545
+ measureText?: MeasureTextFn;
1546
+ }
1547
+ /** Extended compile options for table visualizations. */
1548
+ interface CompileTableOptions extends CompileOptions {
1549
+ /** Current sort state to apply. */
1550
+ sort?: SortState;
1551
+ /** Search query to filter rows. */
1552
+ search?: string;
1553
+ /** Current page (0-indexed). */
1554
+ page?: number;
1555
+ /** Rows per page. */
1556
+ pageSize?: number;
1557
+ }
1558
+
1559
+ /**
1560
+ * Color blindness simulation and palette distinguishability checks.
1561
+ *
1562
+ * Uses Brettel, Vienot, and Mollon (1997) simulation matrices for
1563
+ * protanopia, deuteranopia, and tritanopia.
1564
+ *
1565
+ * These are approximations suitable for checking palette accessibility,
1566
+ * not medical-grade simulations.
1567
+ */
1568
+ /** The three common types of color vision deficiency. */
1569
+ type ColorBlindnessType = 'protanopia' | 'deuteranopia' | 'tritanopia';
1570
+ /**
1571
+ * Simulate how a color appears under a given color blindness type.
1572
+ * Returns a hex color string.
1573
+ */
1574
+ declare function simulateColorBlindness(color: string, type: ColorBlindnessType): string;
1575
+ /**
1576
+ * Check if colors in a palette are distinguishable under a given
1577
+ * color blindness type.
1578
+ *
1579
+ * Uses a minimum perceptual distance threshold in simulated space.
1580
+ * Returns true if all pairs of colors are sufficiently different.
1581
+ */
1582
+ declare function checkPaletteDistinguishability(colors: string[], type: ColorBlindnessType, minDistance?: number): boolean;
1583
+
1584
+ /**
1585
+ * WCAG contrast ratio utilities.
1586
+ *
1587
+ * Uses d3-color for color space parsing and manipulation.
1588
+ * All functions accept CSS color strings (hex, rgb, hsl, named colors).
1589
+ */
1590
+ /**
1591
+ * Compute the WCAG contrast ratio between two colors.
1592
+ * Returns a value between 1 (identical) and 21 (black on white).
1593
+ */
1594
+ declare function contrastRatio(fg: string, bg: string): number;
1595
+ /**
1596
+ * Check if two colors meet WCAG AA contrast requirements.
1597
+ * Normal text: 4.5:1, large text (18px+ bold or 24px+): 3:1.
1598
+ */
1599
+ declare function meetsAA(fg: string, bg: string, largeText?: boolean): boolean;
1600
+ /**
1601
+ * Find an accessible variant of `baseColor` against `bg`.
1602
+ *
1603
+ * Preserves the hue and saturation of baseColor but adjusts lightness
1604
+ * until the target contrast ratio is met. Returns the original color
1605
+ * if it already meets the target.
1606
+ */
1607
+ declare function findAccessibleColor(baseColor: string, bg: string, targetRatio?: number): string;
1608
+
1609
+ /**
1610
+ * Color palettes for @opendata-ai.
1611
+ *
1612
+ * Categorical palette is Infrographic-influenced with WCAG AA contrast
1613
+ * for large text (3:1 ratio) on both light (#ffffff) and dark (#1a1a2e)
1614
+ * backgrounds. Several colors do not meet the stricter 4.5:1 ratio
1615
+ * required for normal-sized body text. This is acceptable because chart
1616
+ * marks (bars, lines, areas, points) are large visual elements.
1617
+ *
1618
+ * Sequential palettes: 5-7 stops from light to dark.
1619
+ * Diverging palettes: 7 stops with a neutral midpoint.
1620
+ */
1621
+ /**
1622
+ * Default categorical palette. 10 visually distinct colors that meet
1623
+ * WCAG AA contrast for large text (3:1) on both white and near-black
1624
+ * backgrounds. Some colors fall below the 4.5:1 threshold for normal
1625
+ * body text. Influenced by Infrographic's editorial palette with tweaks
1626
+ * for accessibility and colorblind distinguishability.
1627
+ */
1628
+ declare const CATEGORICAL_PALETTE: readonly ["#1b7fa3", "#c44e52", "#6a9f58", "#d47215", "#507e79", "#9a6a8d", "#c4636b", "#9c755f", "#a88f22", "#858078"];
1629
+ type CategoricalPalette = typeof CATEGORICAL_PALETTE;
1630
+ /** Sequential palette definition: an array of color stops from light to dark. */
1631
+ interface SequentialPalette {
1632
+ readonly name: string;
1633
+ readonly stops: readonly string[];
1634
+ }
1635
+ /** All sequential palettes keyed by name. */
1636
+ declare const SEQUENTIAL_PALETTES: Record<string, string[]>;
1637
+ /** Diverging palette definition: an array of color stops with a neutral midpoint. */
1638
+ interface DivergingPalette {
1639
+ readonly name: string;
1640
+ readonly stops: readonly string[];
1641
+ }
1642
+ /** All diverging palettes keyed by name. */
1643
+ declare const DIVERGING_PALETTES: Record<string, string[]>;
1644
+
1645
+ /**
1646
+ * Dark mode theme adaptation.
1647
+ *
1648
+ * Preserves hue of colors while adjusting lightness and saturation
1649
+ * to maintain the same relative contrast ratios on a dark background.
1650
+ */
1651
+
1652
+ /**
1653
+ * Adapt a single color for dark mode.
1654
+ *
1655
+ * Preserves the hue and adjusts lightness/saturation so the adapted
1656
+ * color has the same contrast ratio against darkBg as the original
1657
+ * had against lightBg.
1658
+ */
1659
+ declare function adaptColorForDarkMode(color: string, lightBg: string, darkBg: string): string;
1660
+ /**
1661
+ * Adapt an entire resolved theme for dark mode.
1662
+ *
1663
+ * Swaps background/text, adapts categorical and annotation colors,
1664
+ * adjusts gridline and axis colors for the dark background.
1665
+ */
1666
+ declare function adaptTheme(theme: ResolvedTheme): ResolvedTheme;
1667
+
1668
+ /**
1669
+ * Default theme definition.
1670
+ *
1671
+ * Tuned to match Infrographic's visual weight and editorial style.
1672
+ * Inter font family, typography hierarchy for chrome, and color
1673
+ * palettes from the colors module.
1674
+ */
1675
+
1676
+ /**
1677
+ * The default theme. All fields are required and fully specified.
1678
+ * resolveTheme() deep-merges user overrides onto this base.
1679
+ */
1680
+ declare const DEFAULT_THEME: Theme;
1681
+
1682
+ /**
1683
+ * Theme resolver: deep-merges user overrides onto default theme.
1684
+ *
1685
+ * Produces a ResolvedTheme where every property is guaranteed to have
1686
+ * a value. The engine uses ResolvedTheme internally so it never needs
1687
+ * null checks on theme properties.
1688
+ *
1689
+ * Auto-detects dark backgrounds and adapts chrome text colors so
1690
+ * custom themes with dark canvases are readable without explicitly
1691
+ * enabling darkMode.
1692
+ */
1693
+
1694
+ /**
1695
+ * Resolve a theme by deep-merging user overrides onto a base theme.
1696
+ *
1697
+ * Auto-detects dark backgrounds: if the resolved background color is
1698
+ * perceptually dark and chrome text colors are still the light-mode
1699
+ * defaults, they're adapted for readability.
1700
+ *
1701
+ * @param userTheme - Optional partial theme overrides from the spec.
1702
+ * @param base - Base theme to merge onto. Defaults to DEFAULT_THEME.
1703
+ * @returns A ResolvedTheme with all properties guaranteed.
1704
+ */
1705
+ declare function resolveTheme(userTheme?: ThemeConfig, base?: Theme): ResolvedTheme;
1706
+
1707
+ /**
1708
+ * Chrome layout computation.
1709
+ *
1710
+ * Takes a Chrome spec + resolved theme and produces a ResolvedChrome
1711
+ * with computed text positions, styles, and total chrome heights.
1712
+ */
1713
+
1714
+ /**
1715
+ * Compute resolved chrome layout from a Chrome spec and resolved theme.
1716
+ *
1717
+ * Produces positioned text elements and total chrome heights (top and bottom).
1718
+ * Top chrome: title, subtitle. Bottom chrome: source, byline, footer.
1719
+ *
1720
+ * @param chrome - The Chrome spec from the user's VizSpec.
1721
+ * @param theme - The fully resolved theme.
1722
+ * @param width - Total available width in pixels.
1723
+ * @param measureText - Optional real text measurement function from the adapter.
1724
+ */
1725
+ declare function computeChrome(chrome: Chrome | undefined, theme: ResolvedTheme, width: number, measureText?: MeasureTextFn): ResolvedChrome;
1726
+
1727
+ /**
1728
+ * Heuristic text measurement for environments without a DOM.
1729
+ *
1730
+ * These are intentionally approximate. Adapters can provide a real
1731
+ * measureText function via CompileOptions for higher accuracy.
1732
+ * The engine uses the real function when available, falls back to
1733
+ * these heuristics when not.
1734
+ */
1735
+ /**
1736
+ * Estimate the rendered width of a text string.
1737
+ *
1738
+ * Uses a per-character average width based on font size, adjusted
1739
+ * for font weight. Accurate to within ~20% for Latin text in Inter.
1740
+ *
1741
+ * @param text - The text string to measure.
1742
+ * @param fontSize - Font size in pixels.
1743
+ * @param fontWeight - Font weight (100-900). Defaults to 400.
1744
+ */
1745
+ declare function estimateTextWidth(text: string, fontSize: number, fontWeight?: number): number;
1746
+
1747
+ /**
1748
+ * Label collision detection and resolution.
1749
+ *
1750
+ * Greedy algorithm: sort by priority, place in order, try offset
1751
+ * positions for conflicts, demote to tooltip-only if no position works.
1752
+ * Targeting ~60% of Infrographic quality for Phase 0.
1753
+ */
1754
+
1755
+ /** Priority levels for label placement. Data labels win over annotations which win over axes. */
1756
+ type LabelPriority = 'data' | 'annotation' | 'axis';
1757
+ /**
1758
+ * A label candidate for collision resolution.
1759
+ * The collision engine decides its final position and visibility.
1760
+ */
1761
+ interface LabelCandidate {
1762
+ /** The label text. */
1763
+ text: string;
1764
+ /** Preferred anchor position (before collision resolution). */
1765
+ anchorX: number;
1766
+ /** Preferred anchor position (before collision resolution). */
1767
+ anchorY: number;
1768
+ /** Estimated width of the label text. */
1769
+ width: number;
1770
+ /** Estimated height of the label text. */
1771
+ height: number;
1772
+ /** Label priority for collision resolution. */
1773
+ priority: LabelPriority;
1774
+ /** Text style to apply. */
1775
+ style: TextStyle;
1776
+ }
1777
+ /**
1778
+ * Resolve label collisions using a greedy placement algorithm.
1779
+ *
1780
+ * Sorts labels by priority (data > annotation > axis), then places
1781
+ * each label at its preferred position. If it collides with an already-placed
1782
+ * label, tries offset positions. If no position works, the label is
1783
+ * demoted to tooltip-only (visible: false).
1784
+ *
1785
+ * @param labels - Array of label candidates to position.
1786
+ * @returns Array of resolved labels with computed positions and visibility.
1787
+ */
1788
+ declare function resolveCollisions(labels: LabelCandidate[]): ResolvedLabel[];
1789
+
1790
+ /**
1791
+ * Locale-aware number and date formatting utilities.
1792
+ *
1793
+ * Uses d3-format and d3-time-format for formatting,
1794
+ * with convenience wrappers for common patterns.
1795
+ */
1796
+ /**
1797
+ * Format a number with locale-appropriate separators.
1798
+ *
1799
+ * Uses d3-format under the hood. Default format: comma-separated
1800
+ * with auto-precision (e.g. 1500000 -> "1,500,000").
1801
+ *
1802
+ * @param value - The number to format.
1803
+ * @param locale - Locale string (currently unused, reserved for i18n).
1804
+ */
1805
+ declare function formatNumber(value: number, _locale?: string): string;
1806
+ /**
1807
+ * Abbreviate a large number with a suffix.
1808
+ *
1809
+ * Examples:
1810
+ * - 1500000 -> "1.5M"
1811
+ * - 2300 -> "2.3K"
1812
+ * - 42 -> "42"
1813
+ * - 1000000000 -> "1B"
1814
+ */
1815
+ declare function abbreviateNumber(value: number): string;
1816
+ /** Granularity levels for date formatting. */
1817
+ type DateGranularity = 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour' | 'minute';
1818
+ /**
1819
+ * Format a date value for display.
1820
+ *
1821
+ * @param value - Date object, ISO string, or timestamp number.
1822
+ * @param locale - Locale string (currently unused, reserved for i18n).
1823
+ * @param granularity - Time granularity for format selection.
1824
+ */
1825
+ declare function formatDate(value: Date | string | number, _locale?: string, granularity?: DateGranularity): string;
1826
+
1827
+ /**
1828
+ * Automatic alt text generation for chart accessibility.
1829
+ *
1830
+ * Produces human-readable descriptions of chart content for screen readers
1831
+ * and a tabular fallback for data access.
1832
+ */
1833
+
1834
+ /**
1835
+ * Generate alt text describing a chart's content.
1836
+ *
1837
+ * Produces a description like:
1838
+ * "Line chart showing GDP Growth Rate from 2020 to 2024 with 2 series (US, UK)"
1839
+ *
1840
+ * @param spec - The chart spec.
1841
+ * @param data - The data array.
1842
+ */
1843
+ declare function generateAltText(spec: ChartSpec, data: DataRow[]): string;
1844
+ /**
1845
+ * Generate a tabular data fallback for screen readers.
1846
+ *
1847
+ * Returns a 2D array where the first row is headers and subsequent
1848
+ * rows are data values. Only includes fields referenced in the encoding.
1849
+ *
1850
+ * @param spec - The chart spec.
1851
+ * @param data - The data array.
1852
+ */
1853
+ declare function generateDataTable(spec: ChartSpec, data: DataRow[]): unknown[][];
1854
+
1855
+ /**
1856
+ * ARIA label generation for individual marks.
1857
+ *
1858
+ * Produces per-mark labels for screen reader navigation, enabling
1859
+ * users to explore data points individually.
1860
+ */
1861
+
1862
+ /**
1863
+ * Generate ARIA labels for a set of marks.
1864
+ *
1865
+ * Returns a Map keyed by a mark identifier (index-based) with
1866
+ * descriptive labels like "Data point: US GDP 42 in 2020-01".
1867
+ *
1868
+ * @param marks - Array of mark objects from the compiled chart layout.
1869
+ */
1870
+ declare function generateAriaLabels(marks: Mark[]): Map<string, string>;
1871
+
1872
+ /**
1873
+ * Spec construction helpers: typed builder functions for common chart types.
1874
+ *
1875
+ * These builders reduce boilerplate when creating specs programmatically.
1876
+ * They accept field names as strings (simple case) or full EncodingChannel
1877
+ * objects (when you need to customize type, aggregate, axis, or scale).
1878
+ *
1879
+ * Type inference: when a string field name is provided, the builder samples
1880
+ * data values to infer the encoding type (quantitative, temporal, nominal).
1881
+ */
1882
+
1883
+ /** A field reference: either a plain string (field name) or a full EncodingChannel. */
1884
+ type FieldRef = string | EncodingChannel;
1885
+ /** Common options shared by all chart builder functions. */
1886
+ interface ChartBuilderOptions {
1887
+ /** Color encoding: field name or full channel config for series differentiation. */
1888
+ color?: FieldRef;
1889
+ /** Size encoding: field name or full channel config. */
1890
+ size?: FieldRef;
1891
+ /** Editorial chrome (title, subtitle, source, etc.). */
1892
+ chrome?: Chrome;
1893
+ /** Data annotations. */
1894
+ annotations?: Annotation[];
1895
+ /** Whether the chart adapts to container width. Defaults to true. */
1896
+ responsive?: boolean;
1897
+ /** Theme configuration overrides. */
1898
+ theme?: ThemeConfig;
1899
+ /** Dark mode behavior. */
1900
+ darkMode?: DarkMode;
1901
+ }
1902
+ /** Options for the dataTable builder. */
1903
+ interface TableBuilderOptions {
1904
+ /** Column definitions. Auto-generated from data keys if omitted. */
1905
+ columns?: ColumnConfig[];
1906
+ /** Field to use as a unique row identifier. */
1907
+ rowKey?: string;
1908
+ /** Editorial chrome. */
1909
+ chrome?: Chrome;
1910
+ /** Theme configuration overrides. */
1911
+ theme?: ThemeConfig;
1912
+ /** Dark mode behavior. */
1913
+ darkMode?: DarkMode;
1914
+ /** Enable client-side search/filter. */
1915
+ search?: boolean;
1916
+ /** Pagination configuration. */
1917
+ pagination?: boolean | {
1918
+ pageSize: number;
1919
+ };
1920
+ /** Stick the first column during horizontal scroll. */
1921
+ stickyFirstColumn?: boolean;
1922
+ /** Compact mode. */
1923
+ compact?: boolean;
1924
+ /** Whether the table adapts to container width. */
1925
+ responsive?: boolean;
1926
+ }
1927
+ /**
1928
+ * Infer the encoding field type from data values.
1929
+ *
1930
+ * Samples up to 20 values from the data array for the given field.
1931
+ * - If all sampled values are numbers (or null/undefined), returns "quantitative".
1932
+ * - If all sampled string values match ISO date patterns, returns "temporal".
1933
+ * - Otherwise returns "nominal".
1934
+ */
1935
+ declare function inferFieldType(data: DataRow[], field: string): FieldType;
1936
+ /**
1937
+ * Create a line chart spec.
1938
+ *
1939
+ * @param data - Array of data rows.
1940
+ * @param x - X-axis field (typically temporal or ordinal).
1941
+ * @param y - Y-axis field (typically quantitative).
1942
+ * @param options - Optional color, size, chrome, annotations, theme, etc.
1943
+ */
1944
+ declare function lineChart(data: DataRow[], x: FieldRef, y: FieldRef, options?: ChartBuilderOptions): ChartSpec;
1945
+ /**
1946
+ * Create a bar chart spec (horizontal bars).
1947
+ *
1948
+ * Convention: category goes on y-axis, value on x-axis.
1949
+ * The `category` param maps to y, `value` maps to x.
1950
+ *
1951
+ * @param data - Array of data rows.
1952
+ * @param category - Category field (y-axis, nominal/ordinal).
1953
+ * @param value - Value field (x-axis, quantitative).
1954
+ * @param options - Optional color, size, chrome, annotations, theme, etc.
1955
+ */
1956
+ declare function barChart(data: DataRow[], category: FieldRef, value: FieldRef, options?: ChartBuilderOptions): ChartSpec;
1957
+ /**
1958
+ * Create a column chart spec (vertical columns).
1959
+ *
1960
+ * @param data - Array of data rows.
1961
+ * @param x - X-axis field (category or temporal).
1962
+ * @param y - Y-axis field (quantitative value).
1963
+ * @param options - Optional color, size, chrome, annotations, theme, etc.
1964
+ */
1965
+ declare function columnChart(data: DataRow[], x: FieldRef, y: FieldRef, options?: ChartBuilderOptions): ChartSpec;
1966
+ /**
1967
+ * Create a pie chart spec.
1968
+ *
1969
+ * Convention: category maps to the color channel, value maps to y.
1970
+ * Pie charts have no x-axis.
1971
+ *
1972
+ * @param data - Array of data rows.
1973
+ * @param category - Category field (color channel, nominal).
1974
+ * @param value - Value field (y channel, quantitative).
1975
+ * @param options - Optional chrome, annotations, theme, etc.
1976
+ * Note: color option is ignored since category is used for color.
1977
+ */
1978
+ declare function pieChart(data: DataRow[], category: FieldRef, value: FieldRef, options?: ChartBuilderOptions): ChartSpec;
1979
+ /**
1980
+ * Create an area chart spec.
1981
+ *
1982
+ * @param data - Array of data rows.
1983
+ * @param x - X-axis field (typically temporal or ordinal).
1984
+ * @param y - Y-axis field (typically quantitative).
1985
+ * @param options - Optional color, size, chrome, annotations, theme, etc.
1986
+ */
1987
+ declare function areaChart(data: DataRow[], x: FieldRef, y: FieldRef, options?: ChartBuilderOptions): ChartSpec;
1988
+ /**
1989
+ * Create a donut chart spec.
1990
+ *
1991
+ * Convention: category maps to the color channel, value maps to y.
1992
+ * Donut charts have no x-axis.
1993
+ *
1994
+ * @param data - Array of data rows.
1995
+ * @param category - Category field (color channel, nominal).
1996
+ * @param value - Value field (y channel, quantitative).
1997
+ * @param options - Optional chrome, annotations, theme, etc.
1998
+ * Note: color option is ignored since category is used for color.
1999
+ */
2000
+ declare function donutChart(data: DataRow[], category: FieldRef, value: FieldRef, options?: ChartBuilderOptions): ChartSpec;
2001
+ /**
2002
+ * Create a dot chart spec (strip plot / dot plot).
2003
+ *
2004
+ * @param data - Array of data rows.
2005
+ * @param x - X-axis field (quantitative or temporal).
2006
+ * @param y - Y-axis field (nominal/categorical grouping).
2007
+ * @param options - Optional color, size, chrome, annotations, theme, etc.
2008
+ */
2009
+ declare function dotChart(data: DataRow[], x: FieldRef, y: FieldRef, options?: ChartBuilderOptions): ChartSpec;
2010
+ /**
2011
+ * Create a scatter chart spec.
2012
+ *
2013
+ * @param data - Array of data rows.
2014
+ * @param x - X-axis field (quantitative).
2015
+ * @param y - Y-axis field (quantitative).
2016
+ * @param options - Optional color, size, chrome, annotations, theme, etc.
2017
+ */
2018
+ declare function scatterChart(data: DataRow[], x: FieldRef, y: FieldRef, options?: ChartBuilderOptions): ChartSpec;
2019
+ /**
2020
+ * Create a data table spec.
2021
+ *
2022
+ * If no columns are specified, auto-generates column configs from the
2023
+ * keys of the first data row.
2024
+ *
2025
+ * @param data - Array of data rows.
2026
+ * @param options - Column definitions, chrome, pagination, search, etc.
2027
+ */
2028
+ declare function dataTable(data: DataRow[], options?: TableBuilderOptions): TableSpec;
2029
+
2030
+ export { type A11yMetadata, type AggregateOp, type Annotation, type AnnotationAnchor, type AnnotationOffset, type AnnotationPosition, type ArcMark, type AreaMark, type AxisConfig, type AxisLabelDensity, type AxisLayout, type AxisTick, type BarColumnConfig, type BarTableCell, type Breakpoint, CATEGORICAL_PALETTE, CHART_ENCODING_RULES, CHART_TYPES, type CategoricalPalette, type CategoryColorsConfig, type CategoryTableCell, type CellStyle, type ChannelRule, type ChartBuilderOptions, type ChartEventHandlers, type ChartLayout, type ChartSpec, type ChartSpecWithoutData, type ChartType, type Chrome, type ChromeDefaults, type ChromeKey, type ChromeText, type ChromeTextStyle, type ColorBlindnessType, type ColumnConfig, type CompileOptions, type CompileTableOptions, DEFAULT_THEME, DIVERGING_PALETTES, type DarkMode, type DataRow, type DateGranularity, type DivergingPalette, type ElementEdit, type Encoding, type EncodingChannel, type EncodingRule, type FieldRef, type FieldType, type FlagTableCell, GRAPH_ENCODING_RULES, type GraphChannelRule, type GraphEdge, type GraphEdgeLayout, type GraphEncoding, type GraphEncodingChannel, type GraphLayout, type GraphLayoutConfig, type GraphNode, type GraphNodeLayout, type GraphSpec, type GraphSpecWithoutData, type Gridline, type HeatmapColumnConfig, type HeatmapTableCell, type ImageColumnConfig, type ImageTableCell, type LabelCandidate, type LabelConfig, type LabelDensity, type LabelMode, type LabelPriority, type LayoutStrategy, type LegendConfig, type LegendEntry, type LegendLayout, type LegendPosition, type LineMark, type Margins, type Mark, type MarkAria, type MarkEvent, type MeasureTextFn, type PaginationState, type Point, type PointMark, type RangeAnnotation, type Rect, type RectMark, type RefLineAnnotation, type ResolvedAnnotation, type ResolvedChrome, type ResolvedChromeElement, type ResolvedColumn, type ResolvedLabel, type ResolvedTheme, SEQUENTIAL_PALETTES, type ScaleConfig, type SequentialPalette, type SortState, type SparklineColumnConfig, type SparklineData, type SparklineTableCell, type StoredVizSpec, type TableBuilderOptions, type TableCell, type TableCellBase, type TableLayout, type TableRow, type TableSpec, type TableSpecWithoutData, type TextAnnotation, type TextStyle, type TextTableCell, type Theme, type ThemeChromeDefaults, type ThemeColors, type ThemeConfig, type ThemeFontSizes, type ThemeFontWeights, type ThemeFonts, type ThemeSpacing, type TooltipContent, type TooltipField, type VizSpec, abbreviateNumber, adaptColorForDarkMode, adaptTheme, areaChart, barChart, checkPaletteDistinguishability, columnChart, computeChrome, contrastRatio, dataTable, donutChart, dotChart, estimateTextWidth, findAccessibleColor, formatDate, formatNumber, generateAltText, generateAriaLabels, generateDataTable, getBreakpoint, getLayoutStrategy, inferFieldType, isChartSpec, isGraphSpec, isRangeAnnotation, isRefLineAnnotation, isTableSpec, isTextAnnotation, lineChart, meetsAA, pieChart, resolveCollisions, resolveTheme, scatterChart, simulateColorBlindness };