@opendata-ai/openchart-core 7.10.0 → 8.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/index.d.ts +1154 -119
  2. package/dist/index.js +530 -41
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +2 -1
  5. package/dist/styles.css.map +1 -0
  6. package/package.json +9 -3
  7. package/schema/chart.schema.json +8957 -0
  8. package/schema/table.schema.json +861 -0
  9. package/schema/vizspec.schema.json +17694 -0
  10. package/src/accessibility/alt-text.ts +39 -1
  11. package/src/accessibility/aria.ts +4 -2
  12. package/src/colors/__tests__/colorblind.test.ts +12 -0
  13. package/src/colors/colorblind.ts +11 -2
  14. package/src/colors/contrast.ts +11 -0
  15. package/src/colors/index.ts +9 -1
  16. package/src/colors/palettes.ts +47 -0
  17. package/src/helpers/__tests__/deep-merge.test.ts +54 -0
  18. package/src/helpers/__tests__/spec-builders.test.ts +3 -3
  19. package/src/helpers/deep-merge.ts +29 -0
  20. package/src/helpers/spec-builders.ts +7 -7
  21. package/src/index.ts +29 -1
  22. package/src/labels/collision.ts +1 -0
  23. package/src/layout/chrome.ts +24 -0
  24. package/src/layout/index.ts +1 -1
  25. package/src/locale/__tests__/format.test.ts +347 -11
  26. package/src/locale/format.ts +243 -18
  27. package/src/locale/index.ts +10 -1
  28. package/src/responsive/index.ts +2 -0
  29. package/src/responsive/metrics.ts +74 -9
  30. package/src/schema/__tests__/generated-artifacts.test.ts +42 -0
  31. package/src/schema/__tests__/schema.test.ts +179 -0
  32. package/src/styles/__tests__/reduced-motion-selectors.test.ts +28 -0
  33. package/src/styles/animation.css +197 -168
  34. package/src/styles/base.css +89 -62
  35. package/src/styles/chrome.css +173 -179
  36. package/src/styles/dark.css +38 -35
  37. package/src/styles/graph.css +116 -111
  38. package/src/styles/index.css +5 -0
  39. package/src/styles/keyframes.css +115 -100
  40. package/src/styles/legend.css +14 -12
  41. package/src/styles/reduced-motion.css +61 -40
  42. package/src/styles/series-search.css +153 -0
  43. package/src/styles/sparkline.css +14 -12
  44. package/src/styles/table-animation.css +82 -80
  45. package/src/styles/table.css +314 -302
  46. package/src/styles/token-definitions.ts +199 -0
  47. package/src/styles/tokens.css +132 -128
  48. package/src/styles/tooltip.css +109 -115
  49. package/src/styles/you-draw-it.css +126 -0
  50. package/src/types/__tests__/encoding.test.ts +86 -17
  51. package/src/types/__tests__/spec.test.ts +16 -12
  52. package/src/types/encoding.ts +69 -25
  53. package/src/types/events.ts +12 -0
  54. package/src/types/index.ts +39 -3
  55. package/src/types/layout.ts +414 -8
  56. package/src/types/schema-roots.ts +32 -0
  57. package/src/types/spec.ts +643 -84
  58. package/src/types/table.ts +3 -2
@@ -28,15 +28,11 @@ export interface EncodingRule {
28
28
  y2?: ChannelRule;
29
29
  color: ChannelRule;
30
30
  size: ChannelRule;
31
- shape?: ChannelRule;
32
31
  opacity?: ChannelRule;
33
32
  strokeDash?: ChannelRule;
34
33
  text?: ChannelRule;
35
34
  tooltip?: ChannelRule;
36
- href?: ChannelRule;
37
- order?: ChannelRule;
38
35
  theta?: ChannelRule;
39
- radius?: ChannelRule;
40
36
  detail: ChannelRule;
41
37
  }
42
38
 
@@ -70,6 +66,15 @@ function optional(...types: FieldType[]): ChannelRule {
70
66
  * - point: both axes are quantitative
71
67
  * - text/rule: fully optional positioning
72
68
  * - tick/rect: both axes required, any type
69
+ * - beeswarm: both axes optional at the channel level; the compiler enforces
70
+ * the combination (exactly one quantitative value axis, the other axis an
71
+ * optional nominal/ordinal lane channel)
72
+ * - waffle: no positional axes; y is the share value (quantitative, with
73
+ * theta accepted as an alias like arc), color is the category
74
+ * - calendar: x is the daily date (temporal), color the per-day value
75
+ * (quantitative); no y channel (the calendar owns its own geometry)
76
+ * - parliament: no positional axes; theta (aliased to y) is the seat count
77
+ * (quantitative), color the party
73
78
  */
74
79
  export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
75
80
  bar: {
@@ -81,8 +86,6 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
81
86
  size: optional(),
82
87
  opacity: optional('quantitative'),
83
88
  tooltip: optional(),
84
- href: optional(),
85
- order: optional('quantitative', 'ordinal'),
86
89
  detail: optional('nominal'),
87
90
  },
88
91
  line: {
@@ -93,8 +96,6 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
93
96
  opacity: optional('quantitative'),
94
97
  strokeDash: optional('nominal', 'ordinal'),
95
98
  tooltip: optional(),
96
- href: optional(),
97
- order: optional('quantitative', 'ordinal'),
98
99
  detail: optional('nominal'),
99
100
  },
100
101
  area: {
@@ -105,8 +106,6 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
105
106
  size: optional(),
106
107
  opacity: optional('quantitative'),
107
108
  tooltip: optional(),
108
- href: optional(),
109
- order: optional('quantitative', 'ordinal'),
110
109
  detail: optional('nominal'),
111
110
  },
112
111
  point: {
@@ -114,11 +113,8 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
114
113
  y: required('quantitative', 'temporal', 'nominal', 'ordinal'),
115
114
  color: optional('nominal', 'ordinal', 'quantitative'),
116
115
  size: optional('quantitative'),
117
- shape: optional('nominal', 'ordinal'),
118
116
  opacity: optional('quantitative'),
119
117
  tooltip: optional(),
120
- href: optional(),
121
- order: optional('quantitative', 'ordinal'),
122
118
  detail: optional('nominal'),
123
119
  },
124
120
  circle: {
@@ -128,8 +124,6 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
128
124
  size: optional('quantitative'),
129
125
  opacity: optional('quantitative'),
130
126
  tooltip: optional(),
131
- href: optional(),
132
- order: optional('quantitative', 'ordinal'),
133
127
  detail: optional('nominal'),
134
128
  },
135
129
  lollipop: {
@@ -139,21 +133,63 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
139
133
  size: optional('quantitative'),
140
134
  opacity: optional('quantitative'),
141
135
  tooltip: optional(),
142
- href: optional(),
143
- order: optional('quantitative', 'ordinal'),
136
+ detail: optional('nominal'),
137
+ },
138
+ beeswarm: {
139
+ x: optional('quantitative', 'nominal', 'ordinal'),
140
+ y: optional('quantitative', 'nominal', 'ordinal'),
141
+ color: optional('nominal', 'ordinal', 'quantitative'),
142
+ size: optional('quantitative'),
143
+ opacity: optional('quantitative'),
144
+ tooltip: optional(),
145
+ detail: optional('nominal'),
146
+ },
147
+ // Range: x+x2 with nominal y (horizontal) or y+y2 with nominal x (vertical).
148
+ // The orientation-dependent x2/y2 requirement is enforced by a dedicated
149
+ // check in the validator; the static table can only mark them optional.
150
+ range: {
151
+ x: required('quantitative', 'nominal', 'ordinal'),
152
+ y: required('quantitative', 'nominal', 'ordinal'),
153
+ x2: optional('quantitative'),
154
+ y2: optional('quantitative'),
155
+ color: optional('nominal', 'ordinal'),
156
+ size: optional(),
157
+ opacity: optional('quantitative'),
158
+ tooltip: optional(),
144
159
  detail: optional('nominal'),
145
160
  },
146
161
  arc: {
162
+ x: optional(),
163
+ y: optional('quantitative'),
164
+ theta: required('quantitative'),
165
+ color: required('nominal', 'ordinal'),
166
+ size: optional(),
167
+ opacity: optional('quantitative'),
168
+ tooltip: optional(),
169
+ detail: optional('nominal'),
170
+ },
171
+ waffle: {
172
+ x: optional(),
173
+ y: required('quantitative'),
174
+ color: required('nominal', 'ordinal'),
175
+ size: optional(),
176
+ opacity: optional('quantitative'),
177
+ tooltip: optional(),
178
+ theta: optional('quantitative'),
179
+ detail: optional('nominal'),
180
+ },
181
+ // parliament: hemicycle seat chart. Like arc/waffle, no positional axes;
182
+ // color is the party (required), theta the seat count (aliased to y in the
183
+ // sugar pass). y is accepted so the theta alias resolves before the rules
184
+ // check runs.
185
+ parliament: {
147
186
  x: optional(),
148
187
  y: required('quantitative'),
149
188
  color: required('nominal', 'ordinal'),
150
189
  size: optional(),
151
190
  opacity: optional('quantitative'),
152
191
  tooltip: optional(),
153
- href: optional(),
154
- order: optional('quantitative', 'ordinal'),
155
192
  theta: optional('quantitative'),
156
- radius: optional('quantitative'),
157
193
  detail: optional('nominal'),
158
194
  },
159
195
  text: {
@@ -164,7 +200,6 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
164
200
  opacity: optional('quantitative'),
165
201
  text: required(),
166
202
  tooltip: optional(),
167
- href: optional(),
168
203
  detail: optional('nominal'),
169
204
  },
170
205
  rule: {
@@ -177,7 +212,6 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
177
212
  opacity: optional('quantitative'),
178
213
  strokeDash: optional('nominal', 'ordinal'),
179
214
  tooltip: optional(),
180
- href: optional(),
181
215
  detail: optional('nominal'),
182
216
  },
183
217
  tick: {
@@ -187,7 +221,6 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
187
221
  size: optional(),
188
222
  opacity: optional('quantitative'),
189
223
  tooltip: optional(),
190
- href: optional(),
191
224
  detail: optional('nominal'),
192
225
  },
193
226
  rect: {
@@ -199,8 +232,19 @@ export const MARK_ENCODING_RULES: Record<MarkType, EncodingRule> = {
199
232
  size: optional(),
200
233
  opacity: optional('quantitative'),
201
234
  tooltip: optional(),
202
- href: optional(),
203
- order: optional('quantitative', 'ordinal'),
235
+ detail: optional('nominal'),
236
+ },
237
+ // calendar: x is the daily date (temporal), color the per-day value
238
+ // (quantitative). No y channel: the calendar computes its own
239
+ // weeks-x-weekdays geometry, so y is left optional here and the dedicated
240
+ // validator rejects it with a pointed message.
241
+ calendar: {
242
+ x: required('temporal'),
243
+ y: optional(),
244
+ color: required('quantitative'),
245
+ size: optional(),
246
+ opacity: optional('quantitative'),
247
+ tooltip: optional(),
204
248
  detail: optional('nominal'),
205
249
  },
206
250
  };
@@ -127,6 +127,12 @@ export interface ChartEventHandlers {
127
127
  onMarkLeave?: () => void;
128
128
  /** Called when a legend entry is toggled (clicked to show/hide a series). */
129
129
  onLegendToggle?: (series: string, visible: boolean) => void;
130
+ /**
131
+ * Called when the series search (`seriesSearch`) changes the highlight set.
132
+ * Receives the full set of highlighted values after the change, including
133
+ * the authored `encoding.color.highlight` baseline.
134
+ */
135
+ onHighlightChange?: (values: string[]) => void;
130
136
  /** Called when an annotation element is clicked. */
131
137
  onAnnotationClick?: (annotation: Annotation, event: MouseEvent) => void;
132
138
  /** Called when a text annotation label is dragged to a new position. */
@@ -139,4 +145,10 @@ export interface ChartEventHandlers {
139
145
  onDeselect?: (element: ElementRef) => void;
140
146
  /** Fired when inline text editing commits. Also flows through onEdit as a 'text-edit' event. */
141
147
  onTextEdit?: (element: ElementRef, oldText: string, newText: string) => void;
148
+ /**
149
+ * Fired when a "you draw it" (`youDrawIt`) drawing is revealed (button click
150
+ * or programmatic reveal), with the reader's guess in data coordinates,
151
+ * ordered by x. For newsrooms aggregating reader guesses.
152
+ */
153
+ onReveal?: (guess: Array<{ x: string | number; y: number }>) => void;
142
154
  }
@@ -12,7 +12,6 @@ export type {
12
12
  GraphChannelRule,
13
13
  } from './encoding';
14
14
  export {
15
- CHART_ENCODING_RULES,
16
15
  GRAPH_ENCODING_RULES,
17
16
  MARK_ENCODING_RULES,
18
17
  } from './encoding';
@@ -43,10 +42,15 @@ export type {
43
42
  ChartLayout,
44
43
  CompileOptions,
45
44
  CompileTableOptions,
45
+ CompileWarning,
46
+ ContinuousLegendBin,
47
+ ContinuousLegendLayout,
48
+ ContinuousLegendTick,
46
49
  EndpointLabelEntry,
47
50
  EndpointLabelsLayout,
48
51
  FacetLayout,
49
52
  FacetPanelLayout,
53
+ FillPatternType,
50
54
  FlagTableCell,
51
55
  GradientColorStop,
52
56
  GradientLegendLayout,
@@ -56,10 +60,15 @@ export type {
56
60
  Gridline,
57
61
  HeatmapTableCell,
58
62
  ImageTableCell,
63
+ LegendChannel,
59
64
  LegendEntry,
60
65
  LegendEntryPosition,
61
66
  LegendLayout,
62
67
  LineMark,
68
+ MapBorders,
69
+ MapFeatureMark,
70
+ MapFocusLayout,
71
+ MapLayout,
63
72
  Margins,
64
73
  Mark,
65
74
  MarkAria,
@@ -75,13 +84,18 @@ export type {
75
84
  ResolvedChrome,
76
85
  ResolvedChromeElement,
77
86
  ResolvedColumn,
87
+ ResolvedFillPattern,
78
88
  ResolvedLabel,
79
89
  ResolvedMetricBar,
80
90
  ResolvedMetricCell,
91
+ ResolvedSeriesSearch,
92
+ ResolvedYouDrawIt,
81
93
  RuleMarkLayout,
82
94
  SankeyLayout,
83
95
  SankeyLinkMark,
84
96
  SankeyNodeMark,
97
+ SizeLegendCircle,
98
+ SizeLegendLayout,
85
99
  SortState,
86
100
  SparklineData,
87
101
  SparklineTableCell,
@@ -97,9 +111,12 @@ export type {
97
111
  TileMapTileMark,
98
112
  TooltipContent,
99
113
  TooltipField,
114
+ YouDrawItSample,
115
+ YouDrawItYInvert,
100
116
  } from './layout';
101
117
  // Spec types (user input)
102
118
  export type {
119
+ A11yConfig,
103
120
  AggregateOp,
104
121
  AggregateTransform,
105
122
  AnimationConfig,
@@ -117,14 +134,15 @@ export type {
117
134
  BarListEncoding,
118
135
  BarListSpec,
119
136
  BarListSpecWithoutData,
137
+ BeeswarmEncoding,
120
138
  BinParams,
121
139
  BinTransform,
122
140
  CalculateExpression,
123
141
  CalculateTransform,
142
+ CalendarEncoding,
124
143
  ChartSpec,
125
144
  ChartSpecOverride,
126
145
  ChartSpecWithoutData,
127
- ChartType,
128
146
  Chrome,
129
147
  ChromeText,
130
148
  ChromeTextStyle,
@@ -132,11 +150,14 @@ export type {
132
150
  CircleEncoding,
133
151
  Condition,
134
152
  ConditionalValueDef,
153
+ ConnectorConfig,
154
+ ConnectorType,
135
155
  DarkMode,
136
156
  DataRow,
137
157
  Display,
138
158
  Encoding,
139
159
  EncodingChannel,
160
+ EndpointLabelContent,
140
161
  EndpointLabelsConfig,
141
162
  FacetChannel,
142
163
  FieldPredicate,
@@ -164,13 +185,21 @@ export type {
164
185
  LogicalNot,
165
186
  LogicalOr,
166
187
  LollipopEncoding,
188
+ MapEncoding,
189
+ MapFocus,
190
+ MapGeo,
191
+ MapProjection,
192
+ MapSpec,
193
+ MapSpecWithoutData,
167
194
  MarkDef,
168
195
  MarkType,
169
196
  Metric,
170
197
  NodeOverride,
198
+ ParliamentEncoding,
171
199
  PointEncoding,
172
200
  RadialGradient,
173
201
  RangeAnnotation,
202
+ RangeEncoding,
174
203
  RectEncoding,
175
204
  RefLineAnnotation,
176
205
  RelativeTimeRef,
@@ -184,7 +213,9 @@ export type {
184
213
  SankeySpecWithoutData,
185
214
  ScaleConfig,
186
215
  ScaleType,
216
+ SeriesSearchConfig,
187
217
  SeriesStyle,
218
+ SortByField,
188
219
  StoredVizSpec,
189
220
  TableSpec,
190
221
  TableSpecWithoutData,
@@ -199,15 +230,18 @@ export type {
199
230
  TimeUnit,
200
231
  TimeUnitTransform,
201
232
  Transform,
233
+ ValueDef,
202
234
  VizSpec,
235
+ WaffleEncoding,
203
236
  WindowFieldDef,
204
237
  WindowOp,
205
238
  WindowSortField,
206
239
  WindowTransform,
240
+ YouDrawItConfig,
207
241
  } from './spec';
208
242
  export {
209
- CHART_TYPES,
210
243
  getRepresentativeColor,
244
+ isAxislessMark,
211
245
  isBarListSpec,
212
246
  isChartSpec,
213
247
  isConditionalDef,
@@ -215,12 +249,14 @@ export {
215
249
  isGradientDef,
216
250
  isGraphSpec,
217
251
  isLayerSpec,
252
+ isMapSpec,
218
253
  isRangeAnnotation,
219
254
  isRefLineAnnotation,
220
255
  isSankeySpec,
221
256
  isTableSpec,
222
257
  isTextAnnotation,
223
258
  isTileMapSpec,
259
+ isValueDef,
224
260
  MARK_DISPLAY_NAMES,
225
261
  MARK_TYPES,
226
262
  resolveMarkDef,