ggaction 0.0.15 → 0.0.16

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 (236) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +22 -2
  3. package/knowledge/action-cards.json +1 -1
  4. package/knowledge/intent-taxonomy.json +1 -1
  5. package/knowledge/mcp-resources.json +1 -1
  6. package/knowledge/task-packet.schema.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +33 -6
  9. package/src/BasicChartProgram.js +3 -1
  10. package/src/ChartProgram.js +2 -0
  11. package/src/accessibility.js +157 -0
  12. package/src/actions/boxPlots/components.js +6 -8
  13. package/src/actions/boxPlots/create.js +4 -5
  14. package/src/actions/boxPlots/edit.js +3 -4
  15. package/src/actions/boxPlots/materialize.js +1 -1
  16. package/src/actions/canvas/actions.js +3 -3
  17. package/src/actions/canvas/fitting.js +1 -1
  18. package/src/actions/categoryOrder/index.js +6 -8
  19. package/src/actions/charts/area.js +1 -1
  20. package/src/actions/charts/bar.js +1 -1
  21. package/src/actions/charts/beeswarm.js +1 -1
  22. package/src/actions/charts/density.js +1 -1
  23. package/src/actions/charts/ecdf.js +2 -2
  24. package/src/actions/charts/endpoints.js +4 -4
  25. package/src/actions/charts/heatmap.js +1 -1
  26. package/src/actions/charts/histogram.js +1 -1
  27. package/src/actions/charts/horizon.js +1 -1
  28. package/src/actions/charts/interval-regression.js +2 -2
  29. package/src/actions/charts/line.js +1 -1
  30. package/src/actions/charts/parallel.js +1 -1
  31. package/src/actions/charts/pie.js +1 -1
  32. package/src/actions/charts/polar.js +2 -2
  33. package/src/actions/charts/radar.js +1 -1
  34. package/src/actions/charts/radial.js +2 -2
  35. package/src/actions/charts/raincloud.js +2 -2
  36. package/src/actions/charts/rug-strip.js +2 -2
  37. package/src/actions/charts/scatter.js +1 -1
  38. package/src/actions/composition/actions.js +20 -24
  39. package/src/actions/coordinates/actions.js +1 -1
  40. package/src/actions/coordinates/edit.js +1 -1
  41. package/src/actions/data/basicBin2d.js +4 -5
  42. package/src/actions/data/bin.js +2 -2
  43. package/src/actions/data/bin2d.js +6 -8
  44. package/src/actions/data/bin2dMaterialize.js +4 -5
  45. package/src/actions/data/box.js +4 -4
  46. package/src/actions/data/complete.js +2 -2
  47. package/src/actions/data/computed.js +2 -2
  48. package/src/actions/data/create.js +5 -12
  49. package/src/actions/data/density.js +3 -3
  50. package/src/actions/data/derived.js +10 -14
  51. package/src/actions/data/ecdf.js +2 -2
  52. package/src/actions/data/edit.js +35 -23
  53. package/src/actions/data/filter.js +14 -20
  54. package/src/actions/data/fold.js +2 -2
  55. package/src/actions/data/gradientProfile.js +2 -2
  56. package/src/actions/data/horizon.js +2 -2
  57. package/src/actions/data/impute.js +2 -2
  58. package/src/actions/data/index.js +55 -54
  59. package/src/actions/data/interval.js +2 -2
  60. package/src/actions/data/intervalEdit.js +26 -18
  61. package/src/actions/data/normalize.js +2 -2
  62. package/src/actions/data/regression.js +5 -6
  63. package/src/actions/data/revise.js +48 -0
  64. package/src/actions/data/revisionBindings.js +13 -33
  65. package/src/actions/data/stack.js +2 -2
  66. package/src/actions/data/summary.js +2 -2
  67. package/src/actions/data/timeUnit.js +2 -2
  68. package/src/actions/data/window.js +2 -2
  69. package/src/actions/encodings/angle.js +1 -1
  70. package/src/actions/encodings/appearance.js +4 -4
  71. package/src/actions/encodings/barWidth.js +1 -1
  72. package/src/actions/encodings/channels.js +2 -2
  73. package/src/actions/encodings/color/index.js +1 -1
  74. package/src/actions/encodings/density.js +2 -2
  75. package/src/actions/encodings/histogram.js +1 -1
  76. package/src/actions/encodings/horizon.js +6 -8
  77. package/src/actions/encodings/offset.js +2 -2
  78. package/src/actions/encodings/parallel.js +4 -5
  79. package/src/actions/encodings/pathOrder.js +6 -11
  80. package/src/actions/encodings/position/index.js +4 -4
  81. package/src/actions/encodings/ranged.js +5 -5
  82. package/src/actions/encodings/remove.js +4 -5
  83. package/src/actions/encodings/ruleAppearance.js +1 -1
  84. package/src/actions/encodings/seriesLayout.js +1 -1
  85. package/src/actions/encodings/stroke.js +1 -1
  86. package/src/actions/encodings/strokeDash.js +2 -2
  87. package/src/actions/encodings/text.js +1 -1
  88. package/src/actions/errorBands/create.js +11 -17
  89. package/src/actions/errorBands/edit.js +13 -131
  90. package/src/actions/errorBars/create.js +8 -13
  91. package/src/actions/errorBars/edit.js +10 -121
  92. package/src/actions/facets/actions.js +30 -16
  93. package/src/actions/facets/derive.js +8 -2
  94. package/src/actions/facets/guides.js +4 -5
  95. package/src/actions/facets/replay.js +4 -5
  96. package/src/actions/gradientPlots/components.js +5 -6
  97. package/src/actions/gradientPlots/create.js +4 -5
  98. package/src/actions/gradientPlots/edit.js +4 -5
  99. package/src/actions/gradientPlots/materialize.js +2 -2
  100. package/src/actions/gradientPlots/rebind.js +4 -5
  101. package/src/actions/guides/axes/axes.js +23 -4
  102. package/src/actions/guides/axes/axis.js +2 -2
  103. package/src/actions/guides/axes/edit.js +2 -2
  104. package/src/actions/guides/axes/labels.js +9 -9
  105. package/src/actions/guides/axes/lines.js +9 -7
  106. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  107. package/src/actions/guides/axes/parallel.js +5 -5
  108. package/src/actions/guides/axes/remove.js +4 -4
  109. package/src/actions/guides/axes/tickGroups.js +4 -4
  110. package/src/actions/guides/axes/ticks.js +13 -4
  111. package/src/actions/guides/axes/titles.js +10 -10
  112. package/src/actions/guides/grids/grid.js +18 -29
  113. package/src/actions/guides/guides.js +1 -1
  114. package/src/actions/guides/legends/blocks.js +1 -1
  115. package/src/actions/guides/legends/categorical/actions.js +4 -4
  116. package/src/actions/guides/legends/categorical/components.js +38 -33
  117. package/src/actions/guides/legends/categorical/layout.js +1 -1
  118. package/src/actions/guides/legends/categorical/symbols.js +27 -30
  119. package/src/actions/guides/legends/continuous/common.js +46 -8
  120. package/src/actions/guides/legends/continuous/gradient.js +89 -155
  121. package/src/actions/guides/legends/continuous/interval.js +13 -13
  122. package/src/actions/guides/legends/continuous/opacity.js +30 -79
  123. package/src/actions/guides/legends/continuous/stroke.js +22 -322
  124. package/src/actions/guides/legends/edit.js +1 -1
  125. package/src/actions/guides/legends/focused.js +5 -5
  126. package/src/actions/guides/legends/lane.js +6 -6
  127. package/src/actions/guides/legends/remove.js +4 -5
  128. package/src/actions/guides/legends/size.js +21 -82
  129. package/src/actions/guides/legends/strokeWidth.js +17 -77
  130. package/src/actions/guides/polar/axes/facade.js +4 -4
  131. package/src/actions/guides/polar/axes/labels.js +5 -5
  132. package/src/actions/guides/polar/axes/lines.js +9 -15
  133. package/src/actions/guides/polar/axes/ticks.js +9 -15
  134. package/src/actions/guides/polar/axes/titles.js +5 -5
  135. package/src/actions/guides/polar/grids.js +11 -13
  136. package/src/actions/index.js +2 -0
  137. package/src/actions/intervals/revision.js +126 -0
  138. package/src/actions/marks/arc/actions.js +3 -3
  139. package/src/actions/marks/area/actions.js +4 -4
  140. package/src/actions/marks/bar/create.js +1 -1
  141. package/src/actions/marks/bar/edit.js +1 -1
  142. package/src/actions/marks/bar/materialize.js +12 -38
  143. package/src/actions/marks/line/actions.js +3 -3
  144. package/src/actions/marks/point/create.js +1 -1
  145. package/src/actions/marks/point/edit.js +1 -1
  146. package/src/actions/marks/point/jitter.js +6 -8
  147. package/src/actions/marks/point/materialize.js +16 -24
  148. package/src/actions/marks/point/packing.js +6 -8
  149. package/src/actions/marks/rect/actions.js +3 -3
  150. package/src/actions/marks/references.js +8 -10
  151. package/src/actions/marks/remove.js +5 -49
  152. package/src/actions/marks/rule/actions.js +4 -4
  153. package/src/actions/marks/text/actions.js +5 -5
  154. package/src/actions/marks/text/layout.js +12 -20
  155. package/src/actions/marks/text/removal.js +1 -1
  156. package/src/actions/marks/text/selection.js +4 -5
  157. package/src/actions/marks/tick/actions.js +3 -3
  158. package/src/actions/primitives/createGraphics.js +5 -4
  159. package/src/actions/primitives/editGraphics.js +5 -4
  160. package/src/actions/primitives/graphicProperties.js +6 -0
  161. package/src/actions/primitives/semantic.js +10 -3
  162. package/src/actions/primitives/semanticAction.js +7 -4
  163. package/src/actions/primitives/semanticValidation/dataset.js +2 -4
  164. package/src/actions/regression/components.js +10 -14
  165. package/src/actions/regression/create.js +3 -4
  166. package/src/actions/regression/edit.js +3 -4
  167. package/src/actions/resources/remove.js +12 -11
  168. package/src/actions/scales/create.js +1 -1
  169. package/src/actions/scales/edit.js +1 -1
  170. package/src/actions/scales/materialize.js +1 -1
  171. package/src/actions/scales/offset.js +2 -2
  172. package/src/actions/scales/parallel.js +1 -1
  173. package/src/actions/scales/quantitativeColor.js +4 -5
  174. package/src/actions/selection/actions.js +25 -36
  175. package/src/actions/textMetrics/index.js +56 -0
  176. package/src/actions/theme/actions.js +2 -2
  177. package/src/actions/theme/reconcile.js +65 -121
  178. package/src/actions/titles/actions.js +8 -8
  179. package/src/actions/titles/resolve.js +3 -3
  180. package/src/actions/violinPlots/create.js +1 -1
  181. package/src/actions/violinPlots/edit.js +1 -1
  182. package/src/core/action.js +107 -35
  183. package/src/core/diagnostics.js +16 -0
  184. package/src/core/extensionRegistry.js +27 -0
  185. package/src/core/font.js +18 -0
  186. package/src/core/identifiers.js +5 -4
  187. package/src/core/immutable.js +10 -3
  188. package/src/core/optionRequirements.js +8 -0
  189. package/src/core/programState.js +1 -1
  190. package/src/core/resourceReferences.js +15 -6
  191. package/src/core/textMetricProfile.js +28 -0
  192. package/src/core/textMetrics.js +24 -3
  193. package/src/core/validation.js +22 -10
  194. package/src/diagnostics.js +1 -0
  195. package/src/grammar/impute.js +3 -2
  196. package/src/grammar/scales/types.js +8 -0
  197. package/src/grammar/schemas/graphicBounds.js +11 -11
  198. package/src/layout/labels.js +11 -10
  199. package/src/layout/legend.js +4 -4
  200. package/src/layout/legendItems.js +6 -6
  201. package/src/layout/text.js +10 -9
  202. package/src/layout/title.js +9 -9
  203. package/src/materialization/facetGuides/placement.js +1 -1
  204. package/src/materialization/facetGuides/preparation.js +1 -1
  205. package/src/materialization/facetHeaders.js +11 -10
  206. package/src/materialization/guides/layout.js +3 -3
  207. package/src/materialization/scaleGuideDependencies.js +10 -0
  208. package/src/materialization/selection/items/common.js +1 -1
  209. package/src/materialization/text.js +2 -2
  210. package/src/materialization/typography.js +31 -0
  211. package/src/mcp/cli.js +5 -3
  212. package/src/persistence/codec.js +65 -0
  213. package/src/persistence/validation.js +185 -0
  214. package/src/persistence.js +74 -0
  215. package/src/renderers/canvas/index.js +5 -4
  216. package/src/renderers/nativeBackend.js +10 -0
  217. package/src/renderers/options.js +13 -0
  218. package/src/renderers/pdf.js +25 -54
  219. package/src/renderers/png.js +22 -17
  220. package/src/renderers/svg.js +10 -14
  221. package/src/renderers/text.js +1 -11
  222. package/src/selectors/coordinates.js +3 -1
  223. package/src/selectors/datasets.js +8 -6
  224. package/src/selectors/layers.js +6 -4
  225. package/src/selectors/markOwners.js +46 -0
  226. package/src/selectors/scales.js +6 -4
  227. package/src/theme/defaults.js +2 -1
  228. package/src/version.js +2 -0
  229. package/types/accessibility.d.ts +37 -0
  230. package/types/basic.d.ts +4 -2
  231. package/types/diagnostics.d.ts +15 -0
  232. package/types/index.d.ts +5 -0
  233. package/types/pdf.d.ts +9 -0
  234. package/types/persistence.d.ts +7 -0
  235. package/types/png.d.ts +9 -0
  236. package/types/program.d.ts +34 -1
@@ -257,6 +257,12 @@ export function deriveFacetChildren(
257
257
  );
258
258
  }
259
259
 
260
+ function closeInheritedActions(program) {
261
+ let closed = program;
262
+ while (closed.actionStack.length > 0) closed = closed._exitAction();
263
+ return closed;
264
+ }
265
+
260
266
  export function resolveFacetChildrenScales(
261
267
  template,
262
268
  cellIds,
@@ -303,7 +309,7 @@ export function resolveFacetChildrenScales(
303
309
  cellIds.map(id => {
304
310
  const child = independentlyResolved[id];
305
311
  if (child.semanticSpec.layers.length === 0) {
306
- return [id, closeInheritedAction ? child._exitAction() : child];
312
+ return [id, closeInheritedAction ? closeInheritedActions(child) : child];
307
313
  }
308
314
  const resolved = materializeFacetCell(
309
315
  child,
@@ -312,7 +318,7 @@ export function resolveFacetChildrenScales(
312
318
  template.resolvedScales,
313
319
  Object.hasOwn(populated, id)
314
320
  );
315
- return [id, closeInheritedAction ? resolved._exitAction() : resolved];
321
+ return [id, closeInheritedAction ? closeInheritedActions(resolved) : resolved];
316
322
  })
317
323
  );
318
324
  const firstPopulatedId = Object.keys(populated)[0];
@@ -1,16 +1,15 @@
1
- import { action } from "../../core/action.js";
2
- import { validateKeys } from "../../core/validation.js";
1
+ import { closedAction } from "../../core/action.js";
2
+
3
3
  import { applyFacetGuideComposition } from
4
4
  "../../materialization/facetGuides/index.js";
5
5
 
6
- export const composeFacetGuides = action(
6
+ export const composeFacetGuides = /* @__PURE__ */ closedAction(
7
7
  {
8
8
  op: "composeFacetGuides",
9
9
  description: "Apply outer-axis ownership and promote shared facet legends.",
10
10
  scope: "composition"
11
- },
11
+ }, ["layout", "plot"],
12
12
  function ({ layout, plot } = {}) {
13
- validateKeys({ layout, plot }, ["layout", "plot"], "composeFacetGuides");
14
13
  return applyFacetGuideComposition(this, { layout, plot });
15
14
  }
16
15
  );
@@ -1,7 +1,7 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { isPlainObject } from "../../core/immutable.js";
3
3
  import { validateUserId } from "../../core/identifiers.js";
4
- import { validateKeys } from "../../core/validation.js";
4
+
5
5
  import { findTransformPolicy } from "../../grammar/transforms.js";
6
6
 
7
7
  const REPLAY_OPTIONS = Object.freeze(["id", "source", "transform"]);
@@ -22,13 +22,12 @@ function requestedTransform(transform) {
22
22
  };
23
23
  }
24
24
 
25
- export const replayDerivedData = action(
25
+ export const replayDerivedData = /* @__PURE__ */ closedAction(
26
26
  {
27
27
  op: "replayDerivedData",
28
28
  description: "Replay one stored derived-data transform for a facet cell."
29
- },
29
+ }, REPLAY_OPTIONS,
30
30
  function (args = {}) {
31
- validateKeys(args, REPLAY_OPTIONS, "replayDerivedData");
32
31
  const id = validateUserId(args.id, "Facet replay dataset id");
33
32
  const source = validateUserId(args.source, "Facet replay source id");
34
33
  const resolved = requestedTransform(args.transform);
@@ -1,5 +1,5 @@
1
1
  import { assertGuideOptions, guideConflict } from "../guides/reuse.js";
2
- import { action } from "../../core/action.js";
2
+ import { action, closedAction } from "../../core/action.js";
3
3
  import { validateKeys } from "../../core/validation.js";
4
4
  import { GRADIENT_PROFILE_FIELDS } from "../../grammar/gradientProfile.js";
5
5
  import {
@@ -17,13 +17,12 @@ const CENTER_OPTIONS = Object.freeze([
17
17
  ]);
18
18
  const LEGEND_OPTIONS = Object.freeze(["owner", "title", "position"]);
19
19
 
20
- export const createGradientPlotCenter = action(
20
+ export const createGradientPlotCenter = /* @__PURE__ */ closedAction(
21
21
  {
22
22
  op: "createGradientPlotCenter",
23
23
  description: "Create the optional center rule for one gradient plot."
24
- },
24
+ }, CENTER_OPTIONS,
25
25
  function (args = {}) {
26
- validateKeys(args, CENTER_OPTIONS, "createGradientPlotCenter");
27
26
  const categoryAction = args.orientation === "vertical" ? "encodeX" : "encodeY";
28
27
  const measureAction = args.orientation === "vertical" ? "encodeY" : "encodeX";
29
28
  const spanOrientation = args.orientation === "vertical" ? "horizontal" : "vertical";
@@ -82,7 +81,7 @@ function editProperties(program, target, properties) {
82
81
  return next;
83
82
  }
84
83
 
85
- export const rematerializeGradientPlotLegend = action(
84
+ export const rematerializeGradientPlotLegend = /* @__PURE__ */ action(
86
85
  {
87
86
  op: "rematerializeGradientPlotLegend",
88
87
  description: "Rematerialize one gradient plot density legend."
@@ -160,7 +159,7 @@ export function fulfillGradientPlotLegend(program, args) {
160
159
  return program;
161
160
  }
162
161
 
163
- export const createGradientPlotLegend = action(
162
+ export const createGradientPlotLegend = /* @__PURE__ */ action(
164
163
  {
165
164
  op: "createGradientPlotLegend",
166
165
  description: "Create the neutral density legend owned by one gradient plot."
@@ -1,5 +1,5 @@
1
- import { action } from "../../core/action.js";
2
- import { validateKeys } from "../../core/validation.js";
1
+ import { closedAction } from "../../core/action.js";
2
+
3
3
  import { findDataset } from "../../selectors/datasets.js";
4
4
  import { findSemanticScale } from "../../selectors/scales.js";
5
5
  import {
@@ -18,13 +18,12 @@ import {
18
18
  resolveGradientSourceLayer
19
19
  } from "./resolve.js";
20
20
 
21
- export const createGradientPlot = action(
21
+ export const createGradientPlot = /* @__PURE__ */ closedAction(
22
22
  {
23
23
  op: "createGradientPlot",
24
24
  description: "Create a categorical density gradient plot."
25
- },
25
+ }, GRADIENT_PLOT_OPTIONS,
26
26
  function (args = {}) {
27
- validateKeys(args, GRADIENT_PLOT_OPTIONS, "createGradientPlot");
28
27
  const id = resolveGradientPlotId(this, args.id);
29
28
  const source = resolveGradientSourceLayer(this, args.target);
30
29
  const data = args.data ?? source?.data ?? this.context.currentData ??
@@ -1,7 +1,7 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { isPlainObject } from "../../core/immutable.js";
3
3
  import { validateUserId } from "../../core/identifiers.js";
4
- import { validateKeys } from "../../core/validation.js";
4
+
5
5
  import { planDerivedDataRevision } from "../../materialization/dataProvenance.js";
6
6
  import { findDataset } from "../../selectors/datasets.js";
7
7
  import { findLayer } from "../../selectors/layers.js";
@@ -110,13 +110,12 @@ function updateGradientPositions(program, owner, current, candidate, hasCenter)
110
110
  );
111
111
  }
112
112
 
113
- export const editGradientPlot = action(
113
+ export const editGradientPlot = /* @__PURE__ */ closedAction(
114
114
  {
115
115
  op: "editGradientPlot",
116
116
  description: "Edit one stable categorical gradient plot."
117
- },
117
+ }, OPTIONS,
118
118
  function (args = {}) {
119
- validateKeys(args, OPTIONS, "editGradientPlot");
120
119
  if (!OPTIONS.slice(1).some(key => Object.hasOwn(args, key))) {
121
120
  throw new Error("editGradientPlot requires at least one gradient-plot option.");
122
121
  }
@@ -123,7 +123,7 @@ function bodyItems(program, layer, dataset, config) {
123
123
  });
124
124
  }
125
125
 
126
- export const materializeGradientPlotFill = action(
126
+ export const materializeGradientPlotFill = /* @__PURE__ */ action(
127
127
  {
128
128
  op: "materializeGradientPlotFill",
129
129
  description: "Materialize categorical density profiles as gradient strips."
@@ -170,7 +170,7 @@ export const materializeGradientPlotFill = action(
170
170
  }
171
171
  );
172
172
 
173
- export const materializeGradientPlot = action(
173
+ export const materializeGradientPlot = /* @__PURE__ */ action(
174
174
  {
175
175
  op: "materializeGradientPlot",
176
176
  description: "Materialize one complete categorical gradient plot."
@@ -1,18 +1,17 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { validateUserId } from "../../core/identifiers.js";
3
- import { validateKeys } from "../../core/validation.js";
3
+
4
4
  import { findDataset } from "../../selectors/datasets.js";
5
5
  import { findLayer } from "../../selectors/layers.js";
6
6
 
7
7
  const OPTIONS = Object.freeze(["id", "profile", "source"]);
8
8
 
9
- export const rebindGradientPlotProfile = action(
9
+ export const rebindGradientPlotProfile = /* @__PURE__ */ closedAction(
10
10
  {
11
11
  op: "rebindGradientPlotProfile",
12
12
  description: "Rebind one gradient plot to a replayed profile revision."
13
- },
13
+ }, OPTIONS,
14
14
  function (args = {}) {
15
- validateKeys(args, OPTIONS, "rebindGradientPlotProfile");
16
15
  const id = validateUserId(args.id, "Gradient-plot id");
17
16
  const profileId = validateUserId(
18
17
  args.profile,
@@ -38,6 +38,7 @@ export function validateAxesArgs(args) {
38
38
  if (!COORDINATE_API_TYPES.has(type)) {
39
39
  throw new Error(`Unknown createAxes coordinate type "${type}".`);
40
40
  }
41
+ if (coordinate.id !== undefined) validateUserId(coordinate.id, "Coordinate id");
41
42
 
42
43
  return coordinate;
43
44
  }
@@ -121,7 +122,7 @@ function resolveCoordinate(program, descriptor, cartesianLayers) {
121
122
  }
122
123
 
123
124
  if (existing.type !== "cartesian") {
124
- throw new Error("createAxes does not yet support Polar axes.");
125
+ throw new Error("createAxes x/y options require a Cartesian coordinate.");
125
126
  }
126
127
 
127
128
  return { id, layers };
@@ -184,10 +185,10 @@ function resolveAxisArgs(layers, channel, option) {
184
185
  return { ...args, scale };
185
186
  }
186
187
 
187
- const createAxes = action(
188
+ const createAxes = /* @__PURE__ */ action(
188
189
  {
189
190
  op: "createAxes",
190
- description: "Read a semantic coordinate and create its Cartesian axes."
191
+ description: "Read a stored coordinate and create its applicable axes."
191
192
  },
192
193
  function (args = {}) {
193
194
  const coordinateDescriptor = validateAxesArgs(args);
@@ -197,6 +198,16 @@ const createAxes = action(
197
198
  const requestedCoordinateType = coordinateDescriptor.id === undefined
198
199
  ? undefined
199
200
  : findCoordinate(this, coordinateDescriptor.id)?.type;
201
+ if (coordinateDescriptor.id !== undefined) {
202
+ if (requestedCoordinateType === undefined) {
203
+ throw new Error(`Unknown coordinate "${coordinateDescriptor.id}".`);
204
+ }
205
+ if (coordinateDescriptor.type !== undefined &&
206
+ coordinateDescriptor.type !== "auto" &&
207
+ coordinateDescriptor.type !== requestedCoordinateType) {
208
+ throw new Error(`Coordinate "${coordinateDescriptor.id}" has type "${requestedCoordinateType}", not "${coordinateDescriptor.type}".`);
209
+ }
210
+ }
200
211
  const explicitlyPolar = coordinateDescriptor.type === "polar" ||
201
212
  requestedCoordinateType === "polar" ||
202
213
  args.theta !== undefined || args.radius !== undefined;
@@ -206,6 +217,10 @@ const createAxes = action(
206
217
  (cartesianLayers.length === 0 && polarLayers.length === 0) ||
207
218
  explicitlyParallel
208
219
  )) {
220
+ if (coordinateDescriptor.type !== undefined &&
221
+ !["auto", "parallel"].includes(coordinateDescriptor.type)) {
222
+ throw new Error("createAxes coordinate type conflicts with Parallel encodings.");
223
+ }
209
224
  if (
210
225
  args.x !== undefined || args.y !== undefined ||
211
226
  args.theta !== undefined || args.radius !== undefined
@@ -231,7 +246,8 @@ const createAxes = action(
231
246
  }
232
247
  if (polarLayers.length > 0 &&
233
248
  (cartesianLayers.length === 0 || explicitlyPolar)) {
234
- if (coordinateDescriptor.type === "cartesian") {
249
+ if (coordinateDescriptor.type !== undefined &&
250
+ !["auto", "polar"].includes(coordinateDescriptor.type)) {
235
251
  throw new Error("createAxes coordinate type conflicts with Polar encodings.");
236
252
  }
237
253
  if (args.x !== undefined || args.y !== undefined) {
@@ -263,6 +279,9 @@ const createAxes = action(
263
279
  }
264
280
  return polarProgram;
265
281
  }
282
+ if (args.theta !== undefined || args.radius !== undefined) {
283
+ throw new Error("createAxes theta/radius options require Polar encodings.");
284
+ }
266
285
  const coordinate = resolveCoordinate(
267
286
  this,
268
287
  coordinateDescriptor,
@@ -122,8 +122,8 @@ function makeCreateAxis(channel) {
122
122
  );
123
123
  }
124
124
 
125
- const createXAxis = makeCreateAxis("x");
126
- const createYAxis = makeCreateAxis("y");
125
+ const createXAxis = /* @__PURE__ */ makeCreateAxis("x");
126
+ const createYAxis = /* @__PURE__ */ makeCreateAxis("y");
127
127
 
128
128
  export function registerAxisActions(Class) {
129
129
  Class.prototype.createXAxis = createXAxis;
@@ -164,8 +164,8 @@ function makeEditAxis(channel) {
164
164
  );
165
165
  }
166
166
 
167
- const editXAxis = makeEditAxis("x");
168
- const editYAxis = makeEditAxis("y");
167
+ const editXAxis = /* @__PURE__ */ makeEditAxis("x");
168
+ const editYAxis = /* @__PURE__ */ makeEditAxis("y");
169
169
 
170
170
  export function registerCompleteAxisEditActions(ProgramClass) {
171
171
  ProgramClass.prototype.editXAxis = editXAxis;
@@ -165,7 +165,7 @@ function assertTickCompatibility(ticks, config, operation) {
165
165
  if (config.mode === "values" && !sameOrderedValues(ticks.values, config.values)) throw new Error(`${operation} conflicts with axis ticks.`);
166
166
  }
167
167
 
168
- function expandWrappedLabels(resolved, text, config, channel) {
168
+ function expandWrappedLabels(resolved, text, config, channel, profile) {
169
169
  if (config.maxWidth === undefined) {
170
170
  return {
171
171
  ...resolved,
@@ -184,7 +184,7 @@ function expandWrappedLabels(resolved, text, config, channel) {
184
184
  const lines = wrapText(text[index], {
185
185
  maxWidth: config.maxWidth,
186
186
  mode: config.wrap,
187
- style
187
+ style, profile
188
188
  });
189
189
  validateGeneratedItemLimit(
190
190
  expanded.text.length + lines.length,
@@ -271,7 +271,7 @@ function resolve(program, channel, config) {
271
271
  offset: config.offset
272
272
  })
273
273
  };
274
- const resolved = expandWrappedLabels(geometry, text, config, channel);
274
+ const resolved = expandWrappedLabels(geometry, text, config, channel, program.materializationConfigs.textMetrics);
275
275
  const canvas = findCanvasGraphic(program)?.properties;
276
276
  const labelBounds = resolved.text.map((value, index) => resolveTextBounds({
277
277
  x: Array.isArray(resolved.x) ? resolved.x[index] : resolved.x,
@@ -283,7 +283,7 @@ function resolve(program, channel, config) {
283
283
  textAlign: resolved.textAlign,
284
284
  textBaseline: resolved.textBaseline,
285
285
  rotation: config.rotation
286
- }));
286
+ }, program.materializationConfigs.textMetrics));
287
287
  const groupedBounds = unionLabelBounds(labelBounds.map((bounds, index) => ({
288
288
  bounds,
289
289
  group: resolved.groups[index]
@@ -299,7 +299,7 @@ function resolve(program, channel, config) {
299
299
  throw new Error(`The ${channel}-axis labels overlap each other.`);
300
300
  }
301
301
  const title = program.graphicSpec.objects[`${channel}AxisTitle`]
302
- ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisTitle`)
302
+ ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisTitle`, program.materializationConfigs.textMetrics)
303
303
  : undefined;
304
304
  if (title &&
305
305
  program.guideConfigs.axis?.[channel]?.title?.inferredOffset !== true &&
@@ -366,8 +366,8 @@ function makeEdit(channel) {
366
366
  }));
367
367
  }
368
368
 
369
- const editXAxisLabels = makeEdit("x");
370
- const editYAxisLabels = makeEdit("y");
369
+ const editXAxisLabels = /* @__PURE__ */ makeEdit("x");
370
+ const editYAxisLabels = /* @__PURE__ */ makeEdit("y");
371
371
 
372
372
  function makeCreate(channel) {
373
373
  const op = channel === "x" ? "createXAxisLabels" : "createYAxisLabels";
@@ -426,8 +426,8 @@ function makeCreate(channel) {
426
426
  }));
427
427
  }
428
428
 
429
- const createXAxisLabels = makeCreate("x");
430
- const createYAxisLabels = makeCreate("y");
429
+ const createXAxisLabels = /* @__PURE__ */ makeCreate("x");
430
+ const createYAxisLabels = /* @__PURE__ */ makeCreate("y");
431
431
 
432
432
  export function registerAxisLabelActions(Class) {
433
433
  Class.prototype.editXAxisLabels = editXAxisLabels;
@@ -1,3 +1,4 @@
1
+ import { editGraphicProperties } from "../../primitives/graphicProperties.js";
1
2
  import { isSourceOwnedText } from "../../../grammar/text.js";
2
3
  import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
3
4
  import { action } from "../../../core/action.js";
@@ -119,15 +120,16 @@ function createEditAxisLine(channel) {
119
120
  next = next.editGraphics({ target: graphic, property, value: geometry[property] });
120
121
  }
121
122
 
122
- return next
123
- .editGraphics({ target: graphic, property: "stroke", value: color })
124
- .editGraphics({ target: graphic, property: "strokeWidth", value: lineWidth });
123
+ return editGraphicProperties(next, graphic, {
124
+ stroke: color,
125
+ strokeWidth: lineWidth
126
+ });
125
127
  })
126
128
  );
127
129
  }
128
130
 
129
- const editXAxisLine = createEditAxisLine("x");
130
- const editYAxisLine = createEditAxisLine("y");
131
+ const editXAxisLine = /* @__PURE__ */ createEditAxisLine("x");
132
+ const editYAxisLine = /* @__PURE__ */ createEditAxisLine("y");
131
133
 
132
134
  function createAxisLine(channel) {
133
135
  const operation = channel === "x" ? "createXAxisLine" : "createYAxisLine";
@@ -164,8 +166,8 @@ function createAxisLine(channel) {
164
166
  );
165
167
  }
166
168
 
167
- const createXAxisLine = createAxisLine("x");
168
- const createYAxisLine = createAxisLine("y");
169
+ const createXAxisLine = /* @__PURE__ */ createAxisLine("x");
170
+ const createYAxisLine = /* @__PURE__ */ createAxisLine("y");
169
171
 
170
172
  export function registerAxisLineActions(ProgramClass) {
171
173
  ProgramClass.prototype.editXAxisLine = editXAxisLine;
@@ -1,5 +1,5 @@
1
- import { action } from "../../../../core/action.js";
2
- import { validateNonEmptyString, validateOptionObject } from "../../../../core/validation.js";
1
+ import { action, closedAction } from "../../../../core/action.js";
2
+ import { validateNonEmptyString } from "../../../../core/validation.js";
3
3
  import { requireParallelAxisLayer, resolveParallelAxisTarget } from "./resolve.js";
4
4
  import {
5
5
  defaultParallelAxis, hasParallelAxisParts, PARALLEL_AXIS_GRAPHICS,
@@ -45,10 +45,10 @@ function withTitle(program, args, create) {
45
45
  ...(titles.length === 0 ? { remove: true } : { value: titles }) });
46
46
  }
47
47
 
48
- const createParallelAxes = action({
48
+ const createParallelAxes = /* @__PURE__ */ closedAction({
49
49
  op: "createParallelAxes", description: "Create axes for every encoded Parallel dimension."
50
- }, function (args = {}) {
51
- validateOptionObject(args, ["target", "coordinate"], "createParallelAxes");
50
+ }, ["target", "coordinate"], function (args = {}) {
51
+
52
52
  const resolved = owner(this, args, "createParallelAxes");
53
53
  if (resolved.stored !== undefined || this.guideConfigs.axis?.parallel !== undefined ||
54
54
  Object.values(PARALLEL_AXIS_GRAPHICS).some(id => this.graphicSpec.objects[id] !== undefined)) {
@@ -76,13 +76,13 @@ function makeAxisAction(create) {
76
76
  });
77
77
  }
78
78
 
79
- const createParallelAxis = makeAxisAction(true);
80
- const editParallelAxis = makeAxisAction(false);
79
+ const createParallelAxis = /* @__PURE__ */ makeAxisAction(true);
80
+ const editParallelAxis = /* @__PURE__ */ makeAxisAction(false);
81
81
 
82
- const removeParallelAxis = action({
82
+ const removeParallelAxis = /* @__PURE__ */ closedAction({
83
83
  op: "removeParallelAxis", description: "Remove every component of one Parallel field axis."
84
- }, function (args = {}) {
85
- validateOptionObject(args, ["field", "target"], "removeParallelAxis");
84
+ }, ["field", "target"], function (args = {}) {
85
+
86
86
  validateNonEmptyString(args.field, "Parallel axis field");
87
87
  const resolved = owner(this, args, "removeParallelAxis", true);
88
88
  const config = resolveParallelAxisConfigs(this, resolved.dimensions).dimensions.find(dimension => dimension.field === args.field);
@@ -91,10 +91,10 @@ const removeParallelAxis = action({
91
91
  ...Object.fromEntries(PARALLEL_AXIS_PARTS.filter(part => config[part] !== undefined).map(part => [part, false])) });
92
92
  });
93
93
 
94
- const removeParallelAxes = action({
94
+ const removeParallelAxes = /* @__PURE__ */ closedAction({
95
95
  op: "removeParallelAxes", description: "Remove all Parallel axis semantics, recipes and graphics."
96
- }, function (args = {}) {
97
- validateOptionObject(args, ["target", "coordinate"], "removeParallelAxes");
96
+ }, ["target", "coordinate"], function (args = {}) {
97
+
98
98
  const stored = this.semanticSpec.guides.axis?.parallel;
99
99
  if (stored === undefined) throw new Error("removeParallelAxes requires existing Parallel axes.");
100
100
  if (args.target !== undefined && args.target !== stored.target ||
@@ -1,5 +1,5 @@
1
- import { action } from "../../../core/action.js";
2
- import { validateGeneratedItemLimit, validateOptionObject } from "../../../core/validation.js";
1
+ import { closedAction } from "../../../core/action.js";
2
+ import { validateGeneratedItemLimit } from "../../../core/validation.js";
3
3
  import { resolvePlotGraphicPlacement } from "../../../materialization/graphicHierarchy.js";
4
4
  import { requireParallelAxisLayer, resolveParallelAxisTarget, resolveStyledParallelAxes } from "./parallel/resolve.js";
5
5
  import { PARALLEL_AXIS_GRAPHICS, PARALLEL_AXIS_PARTS, hasParallelAxisParts } from "./parallel/policy.js";
@@ -47,11 +47,11 @@ function collectionProperties(part, axes, bounds) {
47
47
  };
48
48
  }
49
49
 
50
- export const rematerializeParallelAxes = action({
50
+ export const rematerializeParallelAxes = /* @__PURE__ */ closedAction({
51
51
  op: "rematerializeParallelAxes",
52
52
  description: "Recompute concrete Parallel dimension axes."
53
- }, function (args = {}) {
54
- validateOptionObject(args, ["target"], "rematerializeParallelAxes");
53
+ }, ["target"], function (args = {}) {
54
+
55
55
  const stored = this.semanticSpec.guides.axis?.parallel;
56
56
  if (stored === undefined) throw new Error("rematerializeParallelAxes requires existing Parallel axes.");
57
57
  const target = resolveParallelAxisTarget(this, args.target ?? stored.target);
@@ -54,7 +54,7 @@ function makeRemoveAxis(channel) {
54
54
  );
55
55
  }
56
56
 
57
- export const removeXAxis = makeRemoveAxis("x");
58
- export const removeYAxis = makeRemoveAxis("y");
59
- export const removeThetaAxis = makeRemoveAxis("theta");
60
- export const removeRadialAxis = makeRemoveAxis("radius");
57
+ export const removeXAxis = /* @__PURE__ */ makeRemoveAxis("x");
58
+ export const removeYAxis = /* @__PURE__ */ makeRemoveAxis("y");
59
+ export const removeThetaAxis = /* @__PURE__ */ makeRemoveAxis("theta");
60
+ export const removeRadialAxis = /* @__PURE__ */ makeRemoveAxis("radius");
@@ -145,10 +145,10 @@ function makeEdit(channel) {
145
145
  );
146
146
  }
147
147
 
148
- const createXAxisTicksAndLabels = makeCreate("x");
149
- const createYAxisTicksAndLabels = makeCreate("y");
150
- const editXAxisTicksAndLabels = makeEdit("x");
151
- const editYAxisTicksAndLabels = makeEdit("y");
148
+ const createXAxisTicksAndLabels = /* @__PURE__ */ makeCreate("x");
149
+ const createYAxisTicksAndLabels = /* @__PURE__ */ makeCreate("y");
150
+ const editXAxisTicksAndLabels = /* @__PURE__ */ makeEdit("x");
151
+ const editYAxisTicksAndLabels = /* @__PURE__ */ makeEdit("y");
152
152
 
153
153
  export function registerAxisTickGroupActions(Class) {
154
154
  Class.prototype.createXAxisTicksAndLabels = createXAxisTicksAndLabels;
@@ -1,4 +1,7 @@
1
+ import { editGraphicProperties } from "../../primitives/graphicProperties.js";
1
2
  import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
3
+ import { applyMaterializationPlan } from "../../../materialization/planner.js";
4
+ import { planAxisTickGridRematerialization } from "../../../materialization/scaleGuideDependencies.js";
2
5
  import { action } from "../../../core/action.js";
3
6
  import { validateUserId } from "../../../core/identifiers.js";
4
7
  import {
@@ -161,11 +164,16 @@ function makeEdit(channel) {
161
164
  const resolved = geometry(this, channel, config);
162
165
  let next = this._withGuideConfig(channel, config).editGraphics({ target: id, property: "length", value: resolved.values.length });
163
166
  for (const property of ["x1", "y1", "x2", "y2"]) next = next.editGraphics({ target: id, property, value: resolved[property] });
164
- return next.editGraphics({ target: id, property: "stroke", value: config.color }).editGraphics({ target: id, property: "strokeWidth", value: config.lineWidth });
167
+ next = editGraphicProperties(next, id, {
168
+ stroke: config.color,
169
+ strokeWidth: config.lineWidth
170
+ });
171
+ // Structural dependency plans own grids during a scale/role handoff.
172
+ return explicitMode ? applyMaterializationPlan(next, planAxisTickGridRematerialization(next, channel)) : next;
165
173
  }));
166
174
  }
167
175
 
168
- const editXAxisTicks = makeEdit("x"), editYAxisTicks = makeEdit("y");
176
+ const editXAxisTicks = /* @__PURE__ */ makeEdit("x"), editYAxisTicks = /* @__PURE__ */ makeEdit("y");
169
177
 
170
178
  function makeCreate(channel) {
171
179
  const op = channel === "x" ? "createXAxisTicks" : "createYAxisTicks";
@@ -189,7 +197,7 @@ function makeCreate(channel) {
189
197
  const config = { scale, position: defaultAxisPosition(channel), length: DEFAULTS.length, color: DEFAULTS.color, lineWidth: DEFAULTS.lineWidth, ...options, inferredValues: inferredValues !== undefined, mode: Object.hasOwn(options, "values") ? "values" : "count" };
190
198
  if (config.mode === "values") delete config.count; else config.count ??= DEFAULTS.count;
191
199
  validateConfig(channel, config); geometry(this, channel, config);
192
- return this.editSemantic({ property: `guide.axis.${channel}.scale`, value: scale })
200
+ const next = this.editSemantic({ property: `guide.axis.${channel}.scale`, value: scale })
193
201
  .createGraphics({
194
202
  id,
195
203
  type: "line",
@@ -197,10 +205,11 @@ function makeCreate(channel) {
197
205
  ...resolvePlotGraphicPlacement(this)
198
206
  })
199
207
  ._withGuideConfig(channel, config)[edit]();
208
+ return applyMaterializationPlan(next, planAxisTickGridRematerialization(next, channel));
200
209
  }));
201
210
  }
202
211
 
203
- const createXAxisTicks = makeCreate("x"), createYAxisTicks = makeCreate("y");
212
+ const createXAxisTicks = /* @__PURE__ */ makeCreate("x"), createYAxisTicks = /* @__PURE__ */ makeCreate("y");
204
213
  export function registerAxisTickActions(Class) {
205
214
  Class.prototype.editXAxisTicks = editXAxisTicks; Class.prototype.editYAxisTicks = editYAxisTicks;
206
215
  Class.prototype.createXAxisTicks = createXAxisTicks; Class.prototype.createYAxisTicks = createYAxisTicks;
@@ -36,7 +36,7 @@ import { resolveConcreteGraphicBounds } from
36
36
  import { validateAxisTextStyle } from "./labels.js";
37
37
  import { resolveRotation } from "../../../grammar/rotation.js";
38
38
 
39
- function titleBounds(geometry, config, text) {
39
+ function titleBounds(geometry, config, text, profile) {
40
40
  return resolveTextBounds({
41
41
  ...geometry,
42
42
  text,
@@ -46,7 +46,7 @@ function titleBounds(geometry, config, text) {
46
46
  textAlign: "center",
47
47
  textBaseline: "middle",
48
48
  rotation: config.rotation
49
- });
49
+ }, profile);
50
50
  }
51
51
 
52
52
  function inferredTitleOffset(program, channel, config) {
@@ -57,7 +57,7 @@ function inferredTitleOffset(program, channel, config) {
57
57
  });
58
58
  const canvas = findCanvasGraphic(program)?.properties;
59
59
  const labels = program.graphicSpec.objects[`${channel}AxisLabels`]
60
- ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`)
60
+ ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`, program.materializationConfigs.textMetrics)
61
61
  : undefined;
62
62
  const preferred = channel === "x" ? 42 : 52;
63
63
  if (!plot || !canvas || !labels) return preferred;
@@ -71,7 +71,7 @@ function inferredTitleOffset(program, channel, config) {
71
71
  position: config.position,
72
72
  along: 0,
73
73
  offset: preferred
74
- }), config, program.semanticSpec.guides.axis?.[channel]?.title ?? "");
74
+ }), config, program.semanticSpec.guides.axis?.[channel]?.title ?? "", program.materializationConfigs.textMetrics);
75
75
  const needed = positive
76
76
  ? labels[far] + 4 - bounds[near]
77
77
  : bounds[far] - labels[near] + 4;
@@ -191,13 +191,13 @@ function resolveGeometry(program, channel, config) {
191
191
  geometry,
192
192
  config,
193
193
  program.semanticSpec.guides.axis?.[channel]?.title ?? ""
194
- );
194
+ , program.materializationConfigs.textMetrics);
195
195
  const canvas = findCanvasGraphic(program)?.properties;
196
196
  if (!canvas || !textBoundsFitCanvas(resolvedBounds, canvas)) {
197
197
  throw new Error(`The ${channel}-axis title does not fit the Canvas margin.`);
198
198
  }
199
199
  const labelsBounds = program.graphicSpec.objects[`${channel}AxisLabels`]
200
- ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`)
200
+ ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`, program.materializationConfigs.textMetrics)
201
201
  : undefined;
202
202
  if (labelsBounds && textBoundsIntersect(resolvedBounds, labelsBounds)) {
203
203
  throw new Error(`The ${channel}-axis title overlaps the axis labels.`);
@@ -269,8 +269,8 @@ function makeEdit(channel) {
269
269
  }));
270
270
  }
271
271
 
272
- const editXAxisTitle = makeEdit("x");
273
- const editYAxisTitle = makeEdit("y");
272
+ const editXAxisTitle = /* @__PURE__ */ makeEdit("x");
273
+ const editYAxisTitle = /* @__PURE__ */ makeEdit("y");
274
274
 
275
275
  function makeCreate(channel) {
276
276
  const operation = names(channel);
@@ -327,8 +327,8 @@ function makeCreate(channel) {
327
327
  }));
328
328
  }
329
329
 
330
- const createXAxisTitle = makeCreate("x");
331
- const createYAxisTitle = makeCreate("y");
330
+ const createXAxisTitle = /* @__PURE__ */ makeCreate("x");
331
+ const createYAxisTitle = /* @__PURE__ */ makeCreate("y");
332
332
 
333
333
  export function registerAxisTitleActions(Class) {
334
334
  Class.prototype.createXAxisTitle = createXAxisTitle;