ggaction 0.0.17 → 0.0.18

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 (263) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +2 -2
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/intent-taxonomy.json +1 -1
  6. package/knowledge/mcp-resources.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +3 -3
  9. package/src/BasicChartProgram.js +1 -1
  10. package/src/accessibility.js +3 -2
  11. package/src/actions/boxPlots/create.js +14 -4
  12. package/src/actions/boxPlots/edit.js +39 -33
  13. package/src/actions/boxPlots/materialize.js +7 -3
  14. package/src/actions/boxPlots/options.js +37 -11
  15. package/src/actions/canvas/actions.js +70 -95
  16. package/src/actions/canvas/fitting.js +16 -1
  17. package/src/actions/canvas/index.js +3 -0
  18. package/src/actions/canvas/plotBorder.js +28 -0
  19. package/src/actions/charts/area.js +2 -2
  20. package/src/actions/charts/bar.js +34 -7
  21. package/src/actions/charts/ecdf.js +4 -18
  22. package/src/actions/charts/endpoints.js +4 -18
  23. package/src/actions/charts/heatmap.js +4 -4
  24. package/src/actions/charts/index.js +2 -0
  25. package/src/actions/charts/interval-regression.js +2 -2
  26. package/src/actions/charts/line.js +1 -1
  27. package/src/actions/charts/pie.js +3 -47
  28. package/src/actions/charts/radial.js +34 -12
  29. package/src/actions/charts/scatter.js +16 -2
  30. package/src/actions/charts/shared.js +2 -2
  31. package/src/actions/charts/text.js +35 -0
  32. package/src/actions/composition/actions.js +6 -2
  33. package/src/actions/data/box.js +2 -1
  34. package/src/actions/data/edit.js +1 -1
  35. package/src/actions/data/regression.js +2 -1
  36. package/src/actions/data/shared.js +3 -2
  37. package/src/actions/data/stack.js +3 -1
  38. package/src/actions/encodings/appearance.js +37 -29
  39. package/src/actions/encodings/barWidth.js +36 -11
  40. package/src/actions/encodings/channels.js +0 -1
  41. package/src/actions/encodings/color/continuous.js +1 -1
  42. package/src/actions/encodings/color/index.js +1 -1
  43. package/src/actions/encodings/color/policy.js +10 -3
  44. package/src/actions/encodings/density/resolve.js +1 -6
  45. package/src/actions/encodings/position/policies/arc.js +12 -10
  46. package/src/actions/encodings/position/policies/area.js +3 -3
  47. package/src/actions/encodings/position/policies/bar.js +15 -6
  48. package/src/actions/encodings/position/policies/line.js +17 -6
  49. package/src/actions/encodings/position/resolve.js +3 -2
  50. package/src/actions/encodings/ranged.js +17 -0
  51. package/src/actions/encodings/remove.js +3 -2
  52. package/src/actions/encodings/seriesLayout.js +1 -0
  53. package/src/actions/encodings/text.js +6 -3
  54. package/src/actions/errorBands/create.js +2 -2
  55. package/src/actions/errorBands/edit.js +2 -1
  56. package/src/actions/facets/actions.js +158 -240
  57. package/src/actions/gradientPlots/resolve.js +2 -17
  58. package/src/actions/guides/applicability.js +1 -1
  59. package/src/actions/guides/axes/axis.js +16 -4
  60. package/src/actions/guides/axes/edit.js +4 -4
  61. package/src/actions/guides/axes/labels.js +120 -46
  62. package/src/actions/guides/axes/lines.js +6 -5
  63. package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
  64. package/src/actions/guides/axes/parallel/policy.js +8 -7
  65. package/src/actions/guides/axes/remove.js +3 -2
  66. package/src/actions/guides/axes/tickGroups.js +5 -2
  67. package/src/actions/guides/axes/ticks.js +6 -3
  68. package/src/actions/guides/axes/titles.js +71 -26
  69. package/src/actions/guides/basic.js +2 -0
  70. package/src/actions/guides/facadeLegend.js +10 -2
  71. package/src/actions/guides/grids/grid.js +7 -1
  72. package/src/actions/guides/grids/resolve.js +59 -12
  73. package/src/actions/guides/legends/blocks.js +3 -1
  74. package/src/actions/guides/legends/categorical/actions.js +70 -17
  75. package/src/actions/guides/legends/categorical/components.js +12 -8
  76. package/src/actions/guides/legends/categorical/index.js +6 -0
  77. package/src/actions/guides/legends/categorical/layout.js +37 -8
  78. package/src/actions/guides/legends/categorical/options.js +31 -20
  79. package/src/actions/guides/legends/categorical/resolve.js +2 -2
  80. package/src/actions/guides/legends/categorical/symbols.js +18 -12
  81. package/src/actions/guides/legends/categorical/validation.js +1 -6
  82. package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
  83. package/src/actions/guides/legends/continuous/common.js +1 -447
  84. package/src/actions/guides/legends/continuous/gradient.js +47 -34
  85. package/src/actions/guides/legends/continuous/interval.js +4 -4
  86. package/src/actions/guides/legends/continuous/opacity.js +19 -12
  87. package/src/actions/guides/legends/edit.js +1 -604
  88. package/src/actions/guides/legends/focused.js +2 -2
  89. package/src/actions/guides/legends/group.js +1 -0
  90. package/src/actions/guides/legends/lane.js +1 -516
  91. package/src/actions/guides/legends/remove.js +3 -0
  92. package/src/actions/guides/legends/sampling.js +1 -1
  93. package/src/actions/guides/legends/size.js +51 -43
  94. package/src/actions/guides/legends/strokeWidth.js +11 -29
  95. package/src/actions/guides/legends/target.js +3 -3
  96. package/src/actions/guides/legends/transition.js +21 -7
  97. package/src/actions/guides/polar/axes/labels.js +4 -2
  98. package/src/actions/guides/polar/axes/titles.js +7 -5
  99. package/src/actions/guides/polar/resolve.js +6 -14
  100. package/src/actions/index.js +16 -16
  101. package/src/actions/marks/arc/actions.js +3 -10
  102. package/src/actions/marks/area/actions.js +8 -5
  103. package/src/actions/marks/area/materialize.js +8 -9
  104. package/src/actions/marks/bar/create.js +10 -4
  105. package/src/actions/marks/bar/edit.js +8 -4
  106. package/src/actions/marks/bar/materialize.js +9 -6
  107. package/src/actions/marks/line/actions.js +11 -4
  108. package/src/actions/marks/line/materialize.js +9 -5
  109. package/src/actions/marks/point/edit.js +1 -1
  110. package/src/actions/marks/rect/actions.js +3 -3
  111. package/src/actions/marks/remove.js +2 -0
  112. package/src/actions/marks/rule/actions.js +7 -4
  113. package/src/actions/marks/text/actions.js +17 -5
  114. package/src/actions/marks/text/layout.js +3 -0
  115. package/src/actions/primitives/semanticValidation/layer.js +4 -0
  116. package/src/actions/regression/create.js +1 -1
  117. package/src/actions/regression/edit.js +3 -3
  118. package/src/actions/regression/resolve.js +2 -6
  119. package/src/actions/scales/channels.js +9 -4
  120. package/src/actions/scales/consumers/families.js +16 -5
  121. package/src/actions/scales/create.js +8 -3
  122. package/src/actions/scales/definitions.js +1 -425
  123. package/src/actions/scales/edit.js +2 -2
  124. package/src/actions/scales/editPolicy.js +9 -3
  125. package/src/actions/scales/materialize.js +1 -1
  126. package/src/actions/scales/preview.js +21 -1
  127. package/src/actions/scales/quantitativeColor.js +3 -3
  128. package/src/actions/selection/actions.js +1 -13
  129. package/src/actions/theme/reconcile.js +81 -27
  130. package/src/actions/theme/state.js +12 -0
  131. package/src/actions/titles/actions.js +5 -18
  132. package/src/actions/titles/resolve.js +41 -19
  133. package/src/actions/violinPlots/edit.js +3 -20
  134. package/src/core/compositionState.js +4 -1
  135. package/src/core/font.js +9 -2
  136. package/src/core/optionRequirements.js +1 -0
  137. package/src/core/resourceReferences.js +3 -0
  138. package/src/core/textMetricProfile.js +3 -2
  139. package/src/core/textMetrics.js +41 -4
  140. package/src/core/validation.js +26 -0
  141. package/src/core/vocabulary.js +4 -0
  142. package/src/grammar/aggregate.js +4 -18
  143. package/src/grammar/arcs.js +1 -386
  144. package/src/grammar/areaPaint.js +10 -0
  145. package/src/grammar/areaSeries.js +18 -10
  146. package/src/grammar/bars/geometry.js +30 -3
  147. package/src/grammar/bars/policy.js +12 -1
  148. package/src/grammar/bin.js +2 -12
  149. package/src/grammar/bin2d.js +1 -6
  150. package/src/grammar/boxPlot.js +56 -9
  151. package/src/grammar/categoryOrder.js +1 -6
  152. package/src/grammar/complete.js +15 -19
  153. package/src/grammar/computed.js +92 -25
  154. package/src/grammar/curveCommands.js +29 -16
  155. package/src/grammar/datasetSchema.js +3 -7
  156. package/src/grammar/displayLabels.js +28 -0
  157. package/src/grammar/ecdf.js +2 -9
  158. package/src/grammar/facets/dependencies.js +6 -2
  159. package/src/grammar/facets/guides.js +5 -0
  160. package/src/grammar/facets/index.js +2 -5
  161. package/src/grammar/fold.js +2 -12
  162. package/src/grammar/gradientProfile.js +1 -6
  163. package/src/grammar/impute.js +21 -48
  164. package/src/grammar/interval.js +2 -9
  165. package/src/grammar/legendGradient.js +18 -0
  166. package/src/grammar/legendGroups.js +1 -0
  167. package/src/grammar/legendTitleStyle.js +22 -0
  168. package/src/grammar/lineSeries.js +32 -17
  169. package/src/grammar/markLabels.js +5 -2
  170. package/src/grammar/normalize.js +4 -54
  171. package/src/grammar/numeric.js +1 -290
  172. package/src/grammar/parallelCoordinates.js +1 -6
  173. package/src/grammar/parseTime.js +41 -0
  174. package/src/grammar/pathCommands.js +11 -4
  175. package/src/grammar/polar.js +1 -184
  176. package/src/grammar/positionCompatibility.js +3 -3
  177. package/src/grammar/regression/derive.js +7 -1
  178. package/src/grammar/regression/models.js +83 -55
  179. package/src/grammar/regression/parameters.js +14 -3
  180. package/src/grammar/roundedRect.js +42 -54
  181. package/src/grammar/scales/appearance.js +1 -206
  182. package/src/grammar/scales/color.js +1 -382
  183. package/src/grammar/scales/colorConsumers.js +5 -2
  184. package/src/grammar/scales/definition.js +1 -197
  185. package/src/grammar/scales/discretized.js +1 -195
  186. package/src/grammar/scales/size.js +1 -456
  187. package/src/grammar/scales/temporal.js +2 -13
  188. package/src/grammar/scales/transformed.js +1 -383
  189. package/src/grammar/scales/types.js +1 -1
  190. package/src/grammar/scales/validation.js +1 -66
  191. package/src/grammar/schemas/concreteGraphic.js +11 -0
  192. package/src/grammar/schemas/graphic.js +3 -0
  193. package/src/grammar/schemas/semanticPath.js +2 -1
  194. package/src/grammar/stack.js +2 -10
  195. package/src/grammar/statisticalReference.js +1 -6
  196. package/src/grammar/summary.js +3 -26
  197. package/src/grammar/text.js +19 -0
  198. package/src/grammar/timeUnit.js +16 -7
  199. package/src/grammar/transformKeys.js +47 -0
  200. package/src/grammar/transforms.js +4 -1
  201. package/src/grammar/valueFormat.js +17 -5
  202. package/src/grammar/weightedStatistics.js +1 -6
  203. package/src/grammar/window.js +4 -58
  204. package/src/inspectionDescriptors.js +1 -1
  205. package/src/layout/canvas.js +1 -110
  206. package/src/layout/facets.js +1 -244
  207. package/src/layout/labels.js +1 -0
  208. package/src/layout/legend.js +13 -0
  209. package/src/layout/legendGroup.js +1 -0
  210. package/src/layout/legendItems.js +59 -15
  211. package/src/layout/legendLane.js +1 -441
  212. package/src/layout/legendText.js +1 -0
  213. package/src/layout/title.js +35 -13
  214. package/src/materialization/bars/aggregate.js +11 -5
  215. package/src/materialization/bars/histogram.js +4 -1
  216. package/src/materialization/bars/ranged.js +19 -6
  217. package/src/materialization/bars/resolve.js +22 -1
  218. package/src/materialization/coordinateBounds.js +8 -0
  219. package/src/materialization/dependencies.js +4 -44
  220. package/src/materialization/facetGuides/layout.js +1 -0
  221. package/src/materialization/facetGuides/placement.js +19 -8
  222. package/src/materialization/facetGuides/preparation.js +15 -7
  223. package/src/materialization/facetHeaders.js +1 -347
  224. package/src/materialization/facets.js +1 -185
  225. package/src/materialization/graphicHierarchy.js +1 -1
  226. package/src/materialization/guides/layout.js +1 -57
  227. package/src/materialization/guides/resources.js +1 -123
  228. package/src/materialization/layout.js +53 -0
  229. package/src/materialization/legendGroups.js +1 -0
  230. package/src/materialization/legendText.js +1 -0
  231. package/src/materialization/legends.js +1 -1
  232. package/src/materialization/marks/capabilities.js +5 -6
  233. package/src/materialization/rect.js +1 -1
  234. package/src/materialization/scaleGuideDependencies.js +1 -1
  235. package/src/materialization/scales/map.js +3 -0
  236. package/src/materialization/scales/policies/arc.js +8 -7
  237. package/src/materialization/scales/policies/bar.js +19 -7
  238. package/src/materialization/scales/policies/series.js +2 -1
  239. package/src/materialization/scales/resolve.js +5 -3
  240. package/src/materialization/selection/items/arc.js +1 -1
  241. package/src/materialization/selection/items/bar.js +7 -6
  242. package/src/materialization/selection/items/path.js +7 -6
  243. package/src/materialization/selection/items/rect.js +2 -2
  244. package/src/materialization/text.js +13 -4
  245. package/src/materialization/textLines.js +15 -0
  246. package/src/persistence/codec.js +37 -6
  247. package/src/persistence/validation.js +47 -0
  248. package/src/persistence.js +18 -5
  249. package/src/renderers/canvas/circle.js +6 -3
  250. package/src/renderers/canvas/fill.js +7 -1
  251. package/src/renderers/canvas/index.js +2 -1
  252. package/src/renderers/canvas/line.js +1 -0
  253. package/src/renderers/canvas/path.js +1 -1
  254. package/src/renderers/canvas/rect.js +11 -8
  255. package/src/renderers/canvas/stroke.js +2 -1
  256. package/src/renderers/canvas/text.js +5 -3
  257. package/src/renderers/svg.js +4 -1
  258. package/src/selectors/layers.js +19 -0
  259. package/src/theme/defaults.js +8 -2
  260. package/src/version.js +1 -1
  261. package/types/basic.d.ts +1 -0
  262. package/types/index.d.ts +7 -0
  263. package/types/program.d.ts +347 -85
@@ -1,28 +1,30 @@
1
+ import { intrinsicLegendConfig, legendGroup } from "../../../materialization/legendGroups.js";
2
+ import { formatVisibleText } from "../../../core/textMetrics.js";
1
3
  import { action, closedAction } from "../../../core/action.js";
2
4
  import {
3
- validateNonEmptyString,
4
5
  validateKeys
5
6
  } from "../../../core/validation.js";
6
7
  import {
7
8
  formatDiscretizedIntervals,
8
9
  isDiscreteSizeScaleType,
10
+ isEnumeratedSizeScaleType,
9
11
  isSizeScaleType,
10
12
  mapSizeValues
11
13
  } from "../../../grammar/scales/index.js";
12
14
  import { resolveLegendItemLayout } from "../../../layout/legendItems.js";
13
- import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
15
+ import { DEFAULT_COLORS } from
14
16
  "../../../theme/defaults.js";
15
17
  import { findLayer } from "../../../selectors/layers.js";
16
18
  import { resolveLegendGraphicPlacement } from
17
19
  "../../../materialization/graphicHierarchy.js";
18
20
  import {
21
+ ITEM_LEGEND_LABELS as SIZE_LEGEND_LABELS,
22
+ ITEM_LEGEND_TITLE_STYLE as SIZE_LEGEND_TITLE_STYLE,
23
+ normalizeItemLegendConfig,
24
+ ITEM_LEGEND_OPTIONS as SIZE_OPTIONS,
19
25
  assertLegendBoundsInsideCanvas,
20
26
  materializeItemLegend,
21
27
  createItemLegendGraphics,
22
- normalizeItemLegendLayout,
23
- normalizeLegendBorder,
24
- normalizeLegendTextOptions,
25
- normalizeLegendTitleOptions,
26
28
  resolveContinuousBounds,
27
29
  resolveLegendBackgroundFromBounds,
28
30
  formatContinuousValues,
@@ -35,23 +37,11 @@ import {
35
37
  resolveLegendSampleValues
36
38
  } from "./sampling.js";
37
39
  import { resolveEffectiveLegendBlockConfig } from "./blocks.js";
40
+ import { normalizeLegendOverflow } from "./categorical/options.js";
38
41
 
39
- const SIZE_OPTIONS = Object.freeze(["target", "count", "values", "position", "layout", "align",
40
- "direction", "columns", "titlePosition", "offset", "itemGap", "title", "labels", "titleStyle", "border"]);
41
42
 
42
- export const SIZE_LEGEND_LABELS = Object.freeze({
43
- offset: 12,
44
- color: DEFAULT_COLORS.text,
45
- fontSize: 12,
46
- fontFamily: DEFAULT_FONT_FAMILY,
47
- fontWeight: "normal"
48
- });
49
- export const SIZE_LEGEND_TITLE_STYLE = Object.freeze({
50
- color: DEFAULT_COLORS.strongText,
51
- fontSize: 13,
52
- fontFamily: DEFAULT_FONT_FAMILY,
53
- fontWeight: 600
54
- });
43
+
44
+ export { SIZE_LEGEND_LABELS, SIZE_LEGEND_TITLE_STYLE };
55
45
 
56
46
  export function isSizeLegendPoint(layer) {
57
47
  return layer?.mark?.type === "point" &&
@@ -79,6 +69,7 @@ function requireScale(program, id) {
79
69
  }
80
70
 
81
71
  export function resolveSizeLegendLayout(program, config) {
72
+ config = intrinsicLegendConfig(program, config);
82
73
  const scale = requireScale(program, config.scale);
83
74
  const categorical = [
84
75
  program.guideConfigs.legend?.series,
@@ -96,23 +87,38 @@ export function resolveSizeLegendLayout(program, config) {
96
87
  });
97
88
  const labels = effective.labels;
98
89
  const titleStyle = effective.titleStyle;
99
- const position = categorical?.position ?? config.position;
100
- if (categorical?.layout === "legacy-bottom") {
90
+ // Group ownership replaces placement inheritance, never shared typography.
91
+ const placementCategorical = legendGroup(program, config.target) === undefined &&
92
+ (config.inheritPosition !== false || categorical?.position === config.position)
93
+ ? categorical : undefined;
94
+ const position = placementCategorical?.position ?? config.position;
95
+ if (placementCategorical?.layout === "legacy-bottom") {
101
96
  throw new Error('Combined size legends require layout "edge".');
102
97
  }
103
- const horizontal = categorical !== undefined && ["top", "bottom"].includes(position);
98
+ const horizontal = placementCategorical !== undefined && ["top", "bottom"].includes(position);
104
99
  const geometry = horizontal ? {
105
100
  position, align: categorical.align, direction: categorical.direction,
106
101
  columns: categorical.columns, titlePosition: categorical.titlePosition,
107
102
  offset: categorical.offset, itemGap: effective.blockGap ?? categorical.itemGap
108
103
  } : { position };
104
+ const ordinalSize = scale.type === "ordinal";
105
+ if (ordinalSize && config.labels.format !== undefined && config.labels.format !== "auto") {
106
+ throw new Error("Categorical size legends retain original category labels.");
107
+ }
109
108
  const discrete = isDiscreteSizeScaleType(scale.type);
110
- if (discrete && readLegendSampling(config).mode === "values") {
109
+ if ((discrete || ordinalSize) && readLegendSampling(config).mode === "values") {
111
110
  throw new Error("Discrete size legends do not support exact values.");
112
111
  }
113
- const values = discrete
112
+ const allValues = discrete
114
113
  ? undefined
115
- : resolveLegendSampleValues(effective, scale, "Size legend");
114
+ : ordinalSize ? scale.domain : resolveLegendSampleValues(effective, scale, "Size legend");
115
+ const hiddenCount = ordinalSize && effective.overflow &&
116
+ allValues.length > effective.overflow.maxItems
117
+ ? allValues.length - effective.overflow.maxItems
118
+ : 0;
119
+ const values = hiddenCount > 0
120
+ ? allValues.slice(0, effective.overflow.maxItems)
121
+ : allValues;
116
122
  const areas = discrete
117
123
  ? scale.range
118
124
  : mapSizeValues(values, scale);
@@ -120,14 +126,15 @@ export function resolveSizeLegendLayout(program, config) {
120
126
  const radius = Math.max(...radii);
121
127
  const width = Math.max(32, radius * 2);
122
128
  const { plot, canvas } = resolveContinuousBounds(program);
123
- const text = discrete
129
+ const itemText = discrete
124
130
  ? formatDiscretizedIntervals(scale.thresholds, config.labels.format)
125
- : formatContinuousValues(
131
+ : ordinalSize ? values.map(formatVisibleText) : formatContinuousValues(
126
132
  values,
127
133
  scale.domain,
128
134
  "quantitative",
129
135
  config.labels.format
130
136
  );
137
+ const text = hiddenCount > 0 ? [...itemText, `…${hiddenCount} entries`] : itemText;
131
138
  const symbolStroke = effective.blockSymbol?.strokeWidth ?? 0;
132
139
  const symbolExtent = symbolStroke / 2;
133
140
  const sampleWidth = width + symbolStroke;
@@ -142,14 +149,15 @@ export function resolveSizeLegendLayout(program, config) {
142
149
  }, undefined, program.materializationConfigs.textMetrics);
143
150
  assertLegendBoundsInsideCanvas(layout.bounds, canvas, "Size legend layout", { ...effective, ...geometry });
144
151
  const background = resolveLegendBackgroundFromBounds(layout.bounds, effective.border, canvas, "Size legend", { ...effective, ...geometry });
145
- return { ...layout, symbolX: layout.symbolX.map(x => x + sampleWidth / 2), radii, text,
152
+ return { ...layout, symbolX: layout.symbolX.slice(0, radii.length).map(x => x + sampleWidth / 2),
153
+ symbolY: layout.itemY.slice(0, radii.length), radii, text,
146
154
  labels, titleStyle, background, config: effective };
147
155
  }
148
156
 
149
157
  export const rematerializeSizeLegend = /* @__PURE__ */ closedAction(
150
158
  {
151
159
  op: "rematerializeSizeLegend",
152
- description: "Rematerialize a quantitative point-size legend."
160
+ description: "Rematerialize a point-size legend."
153
161
  }, [],
154
162
  function (args = {}) {
155
163
  const config = this.guideConfigs.legend?.size;
@@ -171,13 +179,14 @@ export const rematerializeSizeLegend = /* @__PURE__ */ closedAction(
171
179
  return materializeItemLegend(this, "size", currentConfig, layout, {
172
180
  text: layout.text, labels: layout.labels, titleStyle: layout.titleStyle,
173
181
  symbols: {
174
- x: layout.symbolX, y: layout.itemY, radius: layout.radii,
182
+ x: layout.symbolX, y: layout.symbolY, radius: layout.radii,
175
183
  fill: layout.config.blockSymbol?.fill ?? DEFAULT_COLORS.sizeSymbol,
176
184
  opacity: layout.config.blockSymbol?.opacity ?? 0.7
177
185
  },
178
186
  optional: {
179
187
  stroke: layout.config.blockSymbol?.stroke,
180
- strokeWidth: layout.config.blockSymbol?.strokeWidth
188
+ strokeWidth: layout.config.blockSymbol?.strokeWidth ??
189
+ (layout.config.blockSymbol?.stroke === undefined ? undefined : 0)
181
190
  }
182
191
  });
183
192
  }
@@ -186,14 +195,16 @@ export const rematerializeSizeLegend = /* @__PURE__ */ closedAction(
186
195
 
187
196
  export function resolveSizeLegendConfig(program, args = {}) {
188
197
  validateKeys(args, [...SIZE_OPTIONS, "inheritAppearance"], "createSizeLegend");
189
- if (args.title !== undefined) validateNonEmptyString(args.title, "Legend title");
190
198
  const layer = resolveSizeLegendPoint(program, args.target);
191
199
  const encoding = layer.encoding?.size;
192
200
  if (encoding?.scale === undefined) {
193
201
  throw new Error(`Point mark "${layer.id}" requires a size encoding.`);
194
202
  }
195
203
  const scale = requireScale(program, encoding.scale);
196
- const discrete = isDiscreteSizeScaleType(scale.type);
204
+ const discrete = isEnumeratedSizeScaleType(scale.type);
205
+ if (args.overflow !== undefined && scale.type !== "ordinal") {
206
+ throw new Error("Size legend overflow requires an ordinal scale.");
207
+ }
197
208
  if (discrete && (Object.hasOwn(args, "count") || Object.hasOwn(args, "values"))) {
198
209
  throw new Error("Discrete size legends do not support count or exact values.");
199
210
  }
@@ -201,20 +212,17 @@ export function resolveSizeLegendConfig(program, args = {}) {
201
212
  operation: "create",
202
213
  label: "Size legend"
203
214
  });
204
- const count = discrete ? scale.range.length : undefined;
215
+ const count = discrete ? (scale.type === "ordinal" ? scale.domain.length : scale.range.length) : undefined;
205
216
  return {
206
217
  target: layer.id,
207
218
  scale: encoding.scale,
208
- ...normalizeItemLegendLayout({ ...args, itemGap: args.itemGap ?? 40 }),
209
- title: args.title ?? encoding.field,
210
- inferredTitle: args.title === undefined,
219
+ ...normalizeItemLegendConfig(args, encoding, 40),
220
+ ...(args.overflow === undefined ? {} : { overflow: normalizeLegendOverflow(args.overflow) }),
211
221
  domain: scale.domain,
212
222
  ...(discrete ? { count } : { sampling }),
213
223
  inheritAppearance: args.inheritAppearance === true,
214
- labels: normalizeLegendTextOptions(args.labels, "createLegend.labels", SIZE_LEGEND_LABELS),
215
- titleStyle: normalizeLegendTitleOptions(args.titleStyle, "createLegend.titleStyle", SIZE_LEGEND_TITLE_STYLE),
216
- border: normalizeLegendBorder(args.border),
217
- titleVisible: true
224
+ inheritPosition: args.position === undefined,
225
+
218
226
  };
219
227
  }
220
228
 
@@ -1,6 +1,6 @@
1
+ import { intrinsicLegendConfig } from "../../../materialization/legendGroups.js";
1
2
  import { action, closedAction } from "../../../core/action.js";
2
3
  import {
3
- validateNonEmptyString,
4
4
  validateKeys
5
5
  } from "../../../core/validation.js";
6
6
  import { mapContinuousScaleValues } from "../../../grammar/scales/index.js";
@@ -8,16 +8,16 @@ import { resolveLegendItemLayout } from "../../../layout/legendItems.js";
8
8
  import { resolveLegendGraphicPlacement } from
9
9
  "../../../materialization/graphicHierarchy.js";
10
10
  import { findLayer } from "../../../selectors/layers.js";
11
- import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
11
+ import { DEFAULT_COLORS } from
12
12
  "../../../theme/defaults.js";
13
13
  import {
14
+ ITEM_LEGEND_LABELS as STROKE_WIDTH_LEGEND_LABELS,
15
+ ITEM_LEGEND_TITLE_STYLE as STROKE_WIDTH_LEGEND_TITLE_STYLE,
16
+ normalizeItemLegendConfig,
17
+ ITEM_LEGEND_OPTIONS as OPTIONS,
14
18
  assertLegendBoundsInsideCanvas,
15
19
  materializeItemLegend,
16
20
  createItemLegendGraphics,
17
- normalizeItemLegendLayout,
18
- normalizeLegendBorder,
19
- normalizeLegendTextOptions,
20
- normalizeLegendTitleOptions,
21
21
  resolveContinuousBounds,
22
22
  resolveLegendBackgroundFromBounds,
23
23
  formatContinuousValues,
@@ -29,29 +29,16 @@ import {
29
29
  } from "./sampling.js";
30
30
  import { resolveEffectiveLegendBlockConfig } from "./blocks.js";
31
31
 
32
- const OPTIONS = Object.freeze(["target", "count", "values", "position", "layout", "align",
33
- "direction", "columns", "titlePosition", "offset", "itemGap", "title", "labels", "titleStyle", "border"]);
34
32
 
35
- export const STROKE_WIDTH_LEGEND_LABELS = Object.freeze({
36
- offset: 12,
37
- color: DEFAULT_COLORS.text,
38
- fontSize: 12,
39
- fontFamily: DEFAULT_FONT_FAMILY,
40
- fontWeight: "normal"
41
- });
42
33
 
43
- export const STROKE_WIDTH_LEGEND_TITLE_STYLE = Object.freeze({
44
- color: DEFAULT_COLORS.strongText,
45
- fontSize: 13,
46
- fontFamily: DEFAULT_FONT_FAMILY,
47
- fontWeight: 600
48
- });
34
+ export { STROKE_WIDTH_LEGEND_LABELS, STROKE_WIDTH_LEGEND_TITLE_STYLE };
49
35
 
50
36
  export function isStrokeWidthLegendLayer(layer) {
51
37
  return ["line", "rule"].includes(layer?.mark?.type) &&
52
38
  layer.encoding?.strokeWidth?.scale !== undefined;
53
39
  }
54
40
 
41
+
55
42
  function resolveLayer(program, requested) {
56
43
  const layer = selectLegendLayer(
57
44
  program,
@@ -77,6 +64,7 @@ function requireScale(program, id) {
77
64
  }
78
65
 
79
66
  export function resolveStrokeWidthLegendLayout(program, config) {
67
+ config = intrinsicLegendConfig(program, config);
80
68
  const effective = resolveEffectiveLegendBlockConfig(program, "strokeWidth", config);
81
69
  const scale = requireScale(program, config.scale);
82
70
  const { plot, canvas } = resolveContinuousBounds(program);
@@ -134,7 +122,6 @@ export const rematerializeStrokeWidthLegend = /* @__PURE__ */ closedAction(
134
122
 
135
123
  export function resolveStrokeWidthLegendConfig(program, args = {}) {
136
124
  validateKeys(args, OPTIONS, "createStrokeWidthLegend");
137
- if (args.title !== undefined) validateNonEmptyString(args.title, "Legend title");
138
125
  const layer = resolveLayer(program, args.target);
139
126
  const encoding = layer.encoding.strokeWidth;
140
127
  requireScale(program, encoding.scale);
@@ -145,14 +132,9 @@ export function resolveStrokeWidthLegendConfig(program, args = {}) {
145
132
  return {
146
133
  target: layer.id,
147
134
  scale: encoding.scale,
148
- ...normalizeItemLegendLayout({ ...args, itemGap: args.itemGap ?? 32 }),
149
- title: args.title ?? encoding.field,
150
- inferredTitle: args.title === undefined,
135
+ ...normalizeItemLegendConfig(args, encoding, 32),
151
136
  sampling,
152
- labels: normalizeLegendTextOptions(args.labels, "createLegend.labels", STROKE_WIDTH_LEGEND_LABELS),
153
- titleStyle: normalizeLegendTitleOptions(args.titleStyle, "createLegend.titleStyle", STROKE_WIDTH_LEGEND_TITLE_STYLE),
154
- border: normalizeLegendBorder(args.border),
155
- titleVisible: true
137
+
156
138
  };
157
139
  }
158
140
 
@@ -3,7 +3,7 @@ import {
3
3
  LEGEND_CHANNELS,
4
4
  LEGEND_CONFIG_KINDS
5
5
  } from "../../../core/vocabulary.js";
6
- import { isDiscreteSizeScaleType } from "../../../grammar/scales/index.js";
6
+ import { isEnumeratedSizeScaleType } from "../../../grammar/scales/index.js";
7
7
 
8
8
  export function validateLegendChannels(channels, operation) {
9
9
  if (!Array.isArray(channels)) throw new TypeError(`${operation} channels must be an array.`);
@@ -88,10 +88,10 @@ export function describeLegendBlock(program, kind, config) {
88
88
  const family = CATEGORICAL_KINDS.includes(kind)
89
89
  ? "categorical"
90
90
  : kind === "size"
91
- ? isDiscreteSizeScaleType(program.resolvedScales[scaleIds[0]].type)
91
+ ? isEnumeratedSizeScaleType(program.resolvedScales[scaleIds[0]].type)
92
92
  ? "discrete-size"
93
93
  : "sampled"
94
- : ["opacity", "strokeWidth"].includes(kind)
94
+ : ["opacity", "strokeWidth"].includes(kind) || kind === "gradient" && config.representation === "symbols"
95
95
  ? "sampled"
96
96
  : ["gradient", "strokeGradient"].includes(kind)
97
97
  ? "gradient"
@@ -1,3 +1,5 @@
1
+ import { legendResourcePolicy } from "../../../materialization/guides/resources.js";
2
+ import { isContinuousColorScaleType } from "../../../grammar/scales/types.js";
1
3
  import { isDiscretizedColorScaleType } from "../../../grammar/scales/types.js";
2
4
  import { normalizeContinuousLegend } from "./continuous/common.js";
3
5
  import { DEFAULT_GRADIENT_SIZE } from "./continuous/gradient.js";
@@ -8,8 +10,9 @@ import {
8
10
  resolveLegendBlock
9
11
  } from "./target.js";
10
12
  import { validateLegendBlockOverride } from "./blocks.js";
13
+ import { DEFAULT_VERTICAL_LEGEND_ITEM_GAP } from "../../../theme/defaults.js";
11
14
 
12
- const family = (channel, type) => type === "sequential"
15
+ const family = (channel, type) => isContinuousColorScaleType(type)
13
16
  ? channel === "stroke" ? "strokeGradient" : "gradient"
14
17
  : isDiscretizedColorScaleType(type)
15
18
  ? channel === "stroke" ? "strokeInterval" : "interval"
@@ -21,7 +24,7 @@ const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
21
24
  function categoricalFamilyCustom(program, kind, stored) {
22
25
  const side = ["left", "right"].includes(stored.position);
23
26
  const direction = side ? "vertical" : "horizontal";
24
- const itemGap = side ? 28 : stored.position === "top" ? 24 : 20;
27
+ const itemGap = side ? DEFAULT_VERTICAL_LEGEND_ITEM_GAP : stored.position === "top" ? 24 : 20;
25
28
  const order = program.semanticSpec.guides.legend?.[kind]?.order;
26
29
  return stored.inferredSymbol !== true ||
27
30
  stored.direction !== direction ||
@@ -40,7 +43,9 @@ function planChannelLegendTransition(program, scale, nextType, channel) {
40
43
  if (overrideKeys.some(key => key !== oldDescriptor.key)) {
41
44
  throw new Error(`${channel} legend transition found stale legend block overrides.`);
42
45
  }
43
- const blockOverride = stored.blockOverrides?.[oldDescriptor.key];
46
+ const storedOverride = stored.blockOverrides?.[oldDescriptor.key];
47
+ const { symbol: _sampleSymbol, labelMap: _sampleMap, gap: _sampleGap, ...commonOverride } = storedOverride ?? {};
48
+ const blockOverride = stored.representation === "symbols" && storedOverride !== undefined ? commonOverride : storedOverride;
44
49
  const side = ["left", "right"].includes(stored.position);
45
50
  const categorical = ["color", "stroke"].includes(from);
46
51
  const gradientFamily = from.toLowerCase().endsWith("gradient");
@@ -49,10 +54,11 @@ function planChannelLegendTransition(program, scale, nextType, channel) {
49
54
  const comparableSymbol = channel === "stroke" && stored.inferredStrokeWidth === true
50
55
  ? { ...stored.symbol, strokeWidth: defaults.symbol?.strokeWidth }
51
56
  : stored.symbol;
52
- const custom = categorical
57
+ const sampledColor = from === "gradient" && stored.representation === "symbols";
58
+ const custom = sampledColor ? false : categorical
53
59
  ? categoricalFamilyCustom(program, from, stored)
54
60
  : gradientFamily
55
- ? stored.count !== defaults.count || !same(stored.gradient, DEFAULT_GRADIENT_SIZE) || stored.itemGap !== defaults.itemGap
61
+ ? stored.count !== defaults.count || !same({ ...stored.gradient, opacity: stored.gradient?.opacity ?? 1 }, { ...DEFAULT_GRADIENT_SIZE, opacity: 1 }) || stored.itemGap !== defaults.itemGap
56
62
  : !same(comparableSymbol, defaults.symbol) || stored.itemGap !== defaults.itemGap ||
57
63
  stored.direction !== defaults.direction || (stored.columns !== undefined && !(side && stored.columns === 1));
58
64
  if (custom) {
@@ -70,7 +76,7 @@ function planChannelLegendTransition(program, scale, nextType, channel) {
70
76
  const args = {
71
77
  target: stored.target, channels: [channel], position: stored.position,
72
78
  labels: stored.labels, titleStyle: stored.titleStyle, border: stored.border,
73
- align: stored.align, offset: stored.offset, titlePosition: stored.titlePosition,
79
+ align: stored.align, offset: stored.offset, titlePosition: sampledColor ? "top" : stored.titlePosition,
74
80
  ...(stored.inferredTitle ? {} : { title: stored.title })
75
81
  };
76
82
  try {
@@ -83,7 +89,7 @@ function planChannelLegendTransition(program, scale, nextType, channel) {
83
89
  } catch (error) {
84
90
  throw new Error(`${channel} legend transition has incompatible layout or style: ${error.message}`);
85
91
  }
86
- return { args, channel, titleVisible: stored.titleVisible !== false, blockOverride };
92
+ return { args, channel, titleVisible: stored.titleVisible !== false, inferredOffset: stored.inferredOffset, blockOverride };
87
93
  }
88
94
 
89
95
  export function planColorLegendTransitions(program, scale, nextType) {
@@ -95,6 +101,11 @@ export function planColorLegendTransitions(program, scale, nextType) {
95
101
 
96
102
  export function applyColorLegendTransition(program, plan) {
97
103
  let next = program.createLegend(plan.args);
104
+ for (const [kind, config] of Object.entries(next.guideConfigs.legend ?? {})) {
105
+ if (config.target === plan.args.target && legendResourcePolicy(kind).semanticKind === plan.channel) {
106
+ next = next._withLegendConfig(kind, { ...config, inferredOffset: plan.inferredOffset === true });
107
+ }
108
+ }
98
109
  if (!plan.titleVisible) {
99
110
  next = next.editLegend({ target: plan.args.target, title: false });
100
111
  }
@@ -160,6 +171,9 @@ export function planLegendBlockTransitions(program, target, plans) {
160
171
  let override;
161
172
  if (incoming.length === 1 && incoming[0].key === descriptor.key) {
162
173
  override = incoming[0].config.blockOverrides?.[incoming[0].key];
174
+ if (incoming[0].config.representation === "symbols" && descriptor.kind === "gradient" && descriptor.config.representation !== "symbols" && override !== undefined) {
175
+ const { symbol: _symbol, labelMap: _labelMap, ...common } = override; override = common;
176
+ }
163
177
  } else if (incoming.length === 1) {
164
178
  const old = incoming[0];
165
179
  override = old.config.blockOverrides?.[old.key];
@@ -1,3 +1,4 @@
1
+ import { axisThemeTypography } from "../../../theme/state.js";
1
2
  import { action } from "../../../../core/action.js";
2
3
  import { validateNonNegativeFinite } from "../../../../core/validation.js";
3
4
  import {
@@ -99,6 +100,7 @@ function resolveLabelConfig(program, kind, args, resources, previous) {
99
100
  } else {
100
101
  mode = normalizePolarTickMode(program, resources.scale, {}, count);
101
102
  }
103
+ const typography = axisThemeTypography(program.materializationConfigs.theme, "labels");
102
104
  const config = {
103
105
  ...(previous ?? {}),
104
106
  scale: resources.scale,
@@ -110,9 +112,9 @@ function resolveLabelConfig(program, kind, args, resources, previous) {
110
112
  format: args.format ?? previous?.format ??
111
113
  POLAR_AXIS_DEFAULTS.labels.format,
112
114
  color: args.color ?? previous?.color ?? POLAR_AXIS_DEFAULTS.labels.color,
113
- fontSize: args.fontSize ?? previous?.fontSize ??
115
+ fontSize: args.fontSize ?? previous?.fontSize ?? typography.fontSize ??
114
116
  POLAR_AXIS_DEFAULTS.labels.fontSize,
115
- fontFamily: args.fontFamily ?? previous?.fontFamily ??
117
+ fontFamily: args.fontFamily ?? previous?.fontFamily ?? typography.fontFamily ??
116
118
  POLAR_AXIS_DEFAULTS.labels.fontFamily,
117
119
  fontWeight: args.fontWeight ?? previous?.fontWeight ??
118
120
  POLAR_AXIS_DEFAULTS.labels.fontWeight
@@ -1,3 +1,4 @@
1
+ import { axisThemeTypography } from "../../../theme/state.js";
1
2
  import { action } from "../../../../core/action.js";
2
3
  import {
3
4
  validateNonEmptyString,
@@ -55,7 +56,8 @@ function validateTitleGeometry(program, kind, config, geometry, text) {
55
56
  }, program.materializationConfigs.textMetrics);
56
57
  }
57
58
 
58
- function resolveTitleConfig(kind, args, resources, previous) {
59
+ function resolveTitleConfig(program, kind, args, resources, previous) {
60
+ const typography = axisThemeTypography(program.materializationConfigs.theme, "title");
59
61
  const config = {
60
62
  ...(previous ?? {}),
61
63
  scale: resources.scale,
@@ -65,9 +67,9 @@ function resolveTitleConfig(kind, args, resources, previous) {
65
67
  ? POLAR_AXIS_DEFAULTS.title.thetaOffset
66
68
  : POLAR_AXIS_DEFAULTS.title.radiusOffset),
67
69
  color: args.color ?? previous?.color ?? POLAR_AXIS_DEFAULTS.title.color,
68
- fontSize: args.fontSize ?? previous?.fontSize ??
70
+ fontSize: args.fontSize ?? previous?.fontSize ?? typography.fontSize ??
69
71
  POLAR_AXIS_DEFAULTS.title.fontSize,
70
- fontFamily: args.fontFamily ?? previous?.fontFamily ??
72
+ fontFamily: args.fontFamily ?? previous?.fontFamily ?? typography.fontFamily ??
71
73
  POLAR_AXIS_DEFAULTS.title.fontFamily,
72
74
  fontWeight: args.fontWeight ?? previous?.fontWeight ??
73
75
  POLAR_AXIS_DEFAULTS.title.fontWeight
@@ -106,7 +108,7 @@ function makeEditTitle(kind) {
106
108
  scale: previous.scale,
107
109
  coordinate: previous.coordinate
108
110
  };
109
- const config = resolveTitleConfig(kind, args, resources, previous);
111
+ const config = resolveTitleConfig(this, kind, args, resources, previous);
110
112
  const text = Object.hasOwn(args, "text")
111
113
  ? validateNonEmptyString(args.text, "Polar axis title text")
112
114
  : config.inferredText
@@ -150,7 +152,7 @@ function makeCreateTitle(kind) {
150
152
  }
151
153
  const resources = componentResources(this, kind, args, operation.create);
152
154
  const angle = resolveAngle(this, kind, args);
153
- const config = resolveTitleConfig(kind, args, resources);
155
+ const config = resolveTitleConfig(this, kind, args, resources);
154
156
  const text = validateNonEmptyString(
155
157
  args.text ?? inferAxisTitleText(this, names.channel, resources.scale),
156
158
  "Polar axis title text"
@@ -1,9 +1,9 @@
1
1
  import { validateUserId } from "../../../core/identifiers.js";
2
2
  import {
3
3
  validateGeneratedItemLimit,
4
+ validateTextStyle,
4
5
  validateNonEmptyString,
5
- validateNonNegativeFinite,
6
- validatePositiveFinite
6
+ validateNonNegativeFinite
7
7
  } from "../../../core/validation.js";
8
8
  import {
9
9
  formatTransformedTick,
@@ -15,7 +15,7 @@ import { formatTimeTick, formatTimeTicks } from "../../../grammar/ticks.js";
15
15
  import { resolveCoordinatePolarFrame } from
16
16
  "../../../materialization/coordinateBounds.js";
17
17
  import { findCoordinate } from "../../../selectors/coordinates.js";
18
- import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
18
+ import { AXIS_LABEL_FONT_SIZES, AXIS_TITLE_FONT_SIZE, DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
19
19
  "../../../theme/defaults.js";
20
20
  import {
21
21
  findGraphicParent,
@@ -41,7 +41,7 @@ export const POLAR_AXIS_DEFAULTS = Object.freeze({
41
41
  radiusOffset: 10,
42
42
  format: "auto",
43
43
  color: DEFAULT_COLORS.text,
44
- fontSize: 11,
44
+ fontSize: AXIS_LABEL_FONT_SIZES.polar,
45
45
  fontFamily: DEFAULT_FONT_FAMILY,
46
46
  fontWeight: "normal"
47
47
  }),
@@ -49,7 +49,7 @@ export const POLAR_AXIS_DEFAULTS = Object.freeze({
49
49
  thetaOffset: 42,
50
50
  radiusOffset: 8,
51
51
  color: DEFAULT_COLORS.strongText,
52
- fontSize: 13,
52
+ fontSize: AXIS_TITLE_FONT_SIZE,
53
53
  fontFamily: DEFAULT_FONT_FAMILY,
54
54
  fontWeight: 600
55
55
  })
@@ -264,15 +264,7 @@ export function validatePolarLineStyle(config, label) {
264
264
  validateNonNegativeFinite(config.lineWidth, `${label} lineWidth`);
265
265
  }
266
266
 
267
- export function validatePolarTextStyle(config, label) {
268
- validateNonEmptyString(config.color, `${label} color`);
269
- validatePositiveFinite(config.fontSize, `${label} fontSize`);
270
- validateNonEmptyString(config.fontFamily, `${label} fontFamily`);
271
- if (typeof config.fontWeight !== "string" &&
272
- !Number.isFinite(config.fontWeight)) {
273
- throw new TypeError(`${label} fontWeight must be a string or number.`);
274
- }
275
- }
267
+ export { validateTextStyle as validatePolarTextStyle };
276
268
 
277
269
  export function validatePolarLabelFormat(format) {
278
270
  return validateAxisFormat(format);
@@ -1,27 +1,27 @@
1
- import { registerTextMetricActions } from "./textMetrics/index.js";
2
1
  import { registerPrimitiveActions } from "./primitives/index.js";
3
- import { registerSelectionActions } from "./selection/index.js";
4
- import { registerDataActions } from "./data/index.js";
5
- import { registerCategoryOrderActions } from "./categoryOrder/index.js";
6
- import { registerEncodingActions } from "./encodings/index.js";
7
- import { registerScaleActions } from "./scales/index.js";
8
- import { registerMarkActions } from "./marks/index.js";
2
+ import { registerCanvasActions } from "./canvas/index.js";
9
3
  import { registerBasicCoordinateActions } from "./coordinates/actions.js";
10
4
  import { registerCoordinateEditActions } from "./coordinates/edit.js";
11
- import { registerFacetActions } from "./facets/index.js";
12
- import { registerCompositionActions } from "./composition/index.js";
13
- import { registerTitleActions } from "./titles/index.js";
14
- import { registerCanvasActions } from "./canvas/index.js";
5
+ import { registerDataActions } from "./data/index.js";
6
+ import { registerMarkActions } from "./marks/index.js";
7
+ import { registerScaleActions } from "./scales/index.js";
8
+ import { registerEncodingActions } from "./encodings/index.js";
15
9
  import { registerGuideActions } from "./guides/index.js";
16
- import { registerGradientPlotActions } from "./gradientPlots/index.js";
17
- import { registerBoxPlotActions } from "./boxPlots/index.js";
18
- import { registerErrorBarActions } from "./errorBars/index.js";
10
+ import { registerTitleActions } from "./titles/index.js";
19
11
  import { registerRegressionActions } from "./regression/index.js";
20
- import { registerViolinPlotActions } from "./violinPlots/index.js";
12
+ import { registerErrorBarActions } from "./errorBars/index.js";
21
13
  import { registerErrorBandActions } from "./errorBands/index.js";
14
+ import { registerBoxPlotActions } from "./boxPlots/index.js";
15
+ import { registerGradientPlotActions } from "./gradientPlots/index.js";
16
+ import { registerViolinPlotActions } from "./violinPlots/index.js";
22
17
  import { registerChartActions } from "./charts/index.js";
23
- import { registerThemeActions } from "./theme/index.js";
18
+ import { registerCategoryOrderActions } from "./categoryOrder/index.js";
19
+ import { registerSelectionActions } from "./selection/index.js";
24
20
  import { registerResourceActions } from "./resources/index.js";
21
+ import { registerTextMetricActions } from "./textMetrics/index.js";
22
+ import { registerCompositionActions } from "./composition/index.js";
23
+ import { registerFacetActions } from "./facets/index.js";
24
+ import { registerThemeActions } from "./theme/index.js";
25
25
  import {
26
26
  applyCompositionTheme,
27
27
  removeCompositionTheme
@@ -1,3 +1,4 @@
1
+ import { normalizeArcInnerRadius } from "../../../grammar/arcs.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
  import {
@@ -49,14 +50,6 @@ const CREATE_OPTIONS = Object.freeze(["id", "data", ...ARC_OPTIONS]);
49
50
  const EDIT_OPTIONS = Object.freeze(["target", ...ARC_OPTIONS]);
50
51
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
51
52
 
52
- function validateInnerRadius(value) {
53
- if (!Number.isFinite(value) || value < 0 || value >= 1) {
54
- throw new RangeError(
55
- "Arc innerRadius must be from 0 (inclusive) to 1 (exclusive)."
56
- );
57
- }
58
- return value;
59
- }
60
53
 
61
54
  function normalizeConfig(
62
55
  args,
@@ -67,7 +60,7 @@ function normalizeConfig(
67
60
  ...previous,
68
61
  ...strokeDetails,
69
62
  ...(Object.hasOwn(args, "innerRadius")
70
- ? { innerRadius: validateInnerRadius(args.innerRadius), innerRadiusExplicit: true }
63
+ ? { innerRadius: normalizeArcInnerRadius(args.innerRadius), innerRadiusExplicit: true }
71
64
  : {}),
72
65
  ...(Object.hasOwn(args, "padAngle")
73
66
  ? { padAngle: validateNonNegativeFinite(args.padAngle, "Arc padAngle") }
@@ -204,7 +197,7 @@ const rematerializeArcMark = /* @__PURE__ */ action(
204
197
  ? {}
205
198
  : { radiusScale: resolved.resolvedScales[radiusScaleId] }),
206
199
  frame,
207
- innerRadiusRatio: config.innerRadius ?? 0
200
+ innerRadius: config.innerRadius ?? 0
208
201
  });
209
202
  const commands = derived.sectors.map(sector => buildAnnularSectorCommands({
210
203
  frame,