ggaction 0.0.13 → 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 (359) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/README.md +41 -12
  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 +39 -7
  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/basic.js +2 -2
  13. package/src/actions/boxPlots/components.js +20 -12
  14. package/src/actions/boxPlots/create.js +4 -5
  15. package/src/actions/boxPlots/edit.js +34 -9
  16. package/src/actions/boxPlots/materialize.js +12 -4
  17. package/src/actions/boxPlots/options.js +48 -16
  18. package/src/actions/canvas/actions.js +3 -3
  19. package/src/actions/canvas/fitting.js +1 -1
  20. package/src/actions/categoryOrder/index.js +21 -12
  21. package/src/actions/charts/area.js +6 -2
  22. package/src/actions/charts/bar.js +3 -2
  23. package/src/actions/charts/beeswarm.js +1 -1
  24. package/src/actions/charts/density.js +7 -3
  25. package/src/actions/charts/ecdf.js +6 -3
  26. package/src/actions/charts/endpoints.js +29 -7
  27. package/src/actions/charts/heatmap.js +3 -2
  28. package/src/actions/charts/histogram.js +5 -4
  29. package/src/actions/charts/horizon.js +4 -2
  30. package/src/actions/charts/interval-regression.js +7 -4
  31. package/src/actions/charts/line.js +4 -2
  32. package/src/actions/charts/parallel.js +9 -3
  33. package/src/actions/charts/pie.js +11 -3
  34. package/src/actions/charts/polar.js +17 -6
  35. package/src/actions/charts/radar.js +9 -3
  36. package/src/actions/charts/radial.js +12 -4
  37. package/src/actions/charts/raincloud.js +2 -2
  38. package/src/actions/charts/rug-strip.js +8 -4
  39. package/src/actions/charts/scatter.js +4 -2
  40. package/src/actions/composition/actions.js +29 -24
  41. package/src/actions/coordinates/actions.js +2 -2
  42. package/src/actions/coordinates/edit.js +76 -0
  43. package/src/actions/data/basicBin2d.js +4 -5
  44. package/src/actions/data/bin.js +3 -3
  45. package/src/actions/data/bin2d.js +63 -193
  46. package/src/actions/data/bin2dMaterialize.js +4 -5
  47. package/src/actions/data/box.js +4 -4
  48. package/src/actions/data/complete.js +26 -0
  49. package/src/actions/data/computed.js +4 -4
  50. package/src/actions/data/create.js +7 -14
  51. package/src/actions/data/density.js +15 -23
  52. package/src/actions/data/derived.js +57 -31
  53. package/src/actions/data/ecdf.js +2 -2
  54. package/src/actions/data/edit.js +551 -0
  55. package/src/actions/data/filter.js +28 -22
  56. package/src/actions/data/fold.js +2 -2
  57. package/src/actions/data/gradientProfile.js +2 -2
  58. package/src/actions/data/horizon.js +2 -2
  59. package/src/actions/data/impute.js +26 -0
  60. package/src/actions/data/index.js +62 -47
  61. package/src/actions/data/interval.js +2 -2
  62. package/src/actions/data/intervalEdit.js +26 -18
  63. package/src/actions/data/normalize.js +27 -0
  64. package/src/actions/data/regression.js +21 -27
  65. package/src/actions/data/revise.js +48 -0
  66. package/src/actions/data/revisionBindings.js +125 -0
  67. package/src/actions/data/shared.js +20 -4
  68. package/src/actions/data/stack.js +2 -2
  69. package/src/actions/data/summary.js +3 -3
  70. package/src/actions/data/timeUnit.js +6 -3
  71. package/src/actions/data/window.js +3 -3
  72. package/src/actions/encodings/angle.js +1 -1
  73. package/src/actions/encodings/appearance.js +4 -4
  74. package/src/actions/encodings/barWidth.js +1 -1
  75. package/src/actions/encodings/channels.js +415 -0
  76. package/src/actions/encodings/color/index.js +3 -2
  77. package/src/actions/encodings/density.js +7 -4
  78. package/src/actions/encodings/histogram.js +4 -3
  79. package/src/actions/encodings/horizon.js +6 -8
  80. package/src/actions/encodings/index.js +4 -0
  81. package/src/actions/encodings/offset.js +22 -15
  82. package/src/actions/encodings/parallel.js +4 -5
  83. package/src/actions/encodings/pathOrder.js +6 -11
  84. package/src/actions/encodings/position/apply.js +53 -7
  85. package/src/actions/encodings/position/index.js +14 -6
  86. package/src/actions/encodings/position/policies/bar.js +9 -0
  87. package/src/actions/encodings/position/resolve.js +24 -7
  88. package/src/actions/encodings/ranged.js +5 -5
  89. package/src/actions/encodings/remove.js +13 -9
  90. package/src/actions/encodings/ruleAppearance.js +2 -24
  91. package/src/actions/encodings/seriesLayout.js +2 -1
  92. package/src/actions/encodings/shared.js +82 -14
  93. package/src/actions/encodings/stroke.js +226 -0
  94. package/src/actions/encodings/strokeDash.js +2 -2
  95. package/src/actions/encodings/text.js +1 -1
  96. package/src/actions/errorBands/create.js +34 -20
  97. package/src/actions/errorBands/edit.js +34 -137
  98. package/src/actions/errorBars/create.js +43 -20
  99. package/src/actions/errorBars/edit.js +29 -125
  100. package/src/actions/facets/actions.js +267 -73
  101. package/src/actions/facets/derive.js +99 -28
  102. package/src/actions/facets/guides.js +4 -5
  103. package/src/actions/facets/replay.js +4 -5
  104. package/src/actions/gradientPlots/components.js +15 -8
  105. package/src/actions/gradientPlots/create.js +4 -5
  106. package/src/actions/gradientPlots/edit.js +18 -9
  107. package/src/actions/gradientPlots/materialize.js +5 -3
  108. package/src/actions/gradientPlots/options.js +10 -2
  109. package/src/actions/gradientPlots/rebind.js +4 -5
  110. package/src/actions/guides/applicability.js +8 -2
  111. package/src/actions/guides/axes/axes.js +23 -4
  112. package/src/actions/guides/axes/axis.js +2 -2
  113. package/src/actions/guides/axes/edit.js +2 -2
  114. package/src/actions/guides/axes/labels.js +67 -21
  115. package/src/actions/guides/axes/lines.js +15 -9
  116. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  117. package/src/actions/guides/axes/parallel/resolve.js +6 -2
  118. package/src/actions/guides/axes/parallel.js +5 -5
  119. package/src/actions/guides/axes/remove.js +4 -4
  120. package/src/actions/guides/axes/tickGroups.js +6 -5
  121. package/src/actions/guides/axes/ticks.js +19 -6
  122. package/src/actions/guides/axes/titles.js +21 -13
  123. package/src/actions/guides/grids/grid.js +18 -29
  124. package/src/actions/guides/grids/resolve.js +7 -2
  125. package/src/actions/guides/guides.js +20 -4
  126. package/src/actions/guides/legends/blocks.js +426 -0
  127. package/src/actions/guides/legends/categorical/actions.js +138 -52
  128. package/src/actions/guides/legends/categorical/components.js +55 -45
  129. package/src/actions/guides/legends/categorical/index.js +37 -33
  130. package/src/actions/guides/legends/categorical/layout.js +98 -16
  131. package/src/actions/guides/legends/categorical/options.js +2 -2
  132. package/src/actions/guides/legends/categorical/recipes.js +111 -20
  133. package/src/actions/guides/legends/categorical/resolve.js +12 -8
  134. package/src/actions/guides/legends/categorical/symbols.js +104 -52
  135. package/src/actions/guides/legends/continuous/common.js +76 -20
  136. package/src/actions/guides/legends/continuous/gradient.js +95 -158
  137. package/src/actions/guides/legends/continuous/index.js +2 -0
  138. package/src/actions/guides/legends/continuous/interval.js +21 -16
  139. package/src/actions/guides/legends/continuous/opacity.js +37 -83
  140. package/src/actions/guides/legends/continuous/stroke.js +225 -0
  141. package/src/actions/guides/legends/creation.js +14 -1
  142. package/src/actions/guides/legends/edit.js +159 -60
  143. package/src/actions/guides/legends/focused.js +5 -5
  144. package/src/actions/guides/legends/index.js +2 -0
  145. package/src/actions/guides/legends/lane.js +59 -24
  146. package/src/actions/guides/legends/lifecycle.js +19 -8
  147. package/src/actions/guides/legends/remove.js +17 -8
  148. package/src/actions/guides/legends/sampling.js +140 -0
  149. package/src/actions/guides/legends/size.js +100 -108
  150. package/src/actions/guides/legends/strokeWidth.js +38 -92
  151. package/src/actions/guides/legends/target.js +112 -1
  152. package/src/actions/guides/legends/transition.js +165 -16
  153. package/src/actions/guides/polar/axes/facade.js +8 -8
  154. package/src/actions/guides/polar/axes/labels.js +29 -10
  155. package/src/actions/guides/polar/axes/lines.js +19 -19
  156. package/src/actions/guides/polar/axes/shared.js +16 -0
  157. package/src/actions/guides/polar/axes/ticks.js +10 -16
  158. package/src/actions/guides/polar/axes/titles.js +6 -6
  159. package/src/actions/guides/polar/grids.js +12 -14
  160. package/src/actions/guides/polar/resolve.js +12 -8
  161. package/src/actions/index.js +16 -3
  162. package/src/actions/intervals/revision.js +126 -0
  163. package/src/actions/marks/arc/actions.js +80 -22
  164. package/src/actions/marks/area/actions.js +38 -13
  165. package/src/actions/marks/area/materialize.js +17 -1
  166. package/src/actions/marks/bar/create.js +12 -3
  167. package/src/actions/marks/bar/edit.js +21 -4
  168. package/src/actions/marks/bar/materialize.js +34 -40
  169. package/src/actions/marks/index.js +10 -1
  170. package/src/actions/marks/line/actions.js +40 -17
  171. package/src/actions/marks/line/materialize.js +29 -10
  172. package/src/actions/marks/point/create.js +9 -3
  173. package/src/actions/marks/point/edit.js +19 -7
  174. package/src/actions/marks/point/jitter.js +6 -8
  175. package/src/actions/marks/point/materialize.js +48 -22
  176. package/src/actions/marks/point/packing.js +6 -8
  177. package/src/actions/marks/rect/actions.js +36 -15
  178. package/src/actions/marks/references.js +602 -33
  179. package/src/actions/marks/remove.js +67 -41
  180. package/src/actions/marks/rule/actions.js +51 -14
  181. package/src/actions/marks/shared.js +1 -1
  182. package/src/actions/marks/text/actions.js +79 -14
  183. package/src/actions/marks/text/index.js +4 -0
  184. package/src/actions/marks/text/layout.js +157 -17
  185. package/src/actions/marks/text/removal.js +173 -0
  186. package/src/actions/marks/text/selection.js +72 -0
  187. package/src/actions/marks/tick/actions.js +25 -8
  188. package/src/actions/primitives/createGraphics.js +5 -4
  189. package/src/actions/primitives/editGraphics.js +31 -4
  190. package/src/actions/primitives/graphicProperties.js +6 -0
  191. package/src/actions/primitives/semantic.js +11 -3
  192. package/src/actions/primitives/semanticAction.js +90 -14
  193. package/src/actions/primitives/semanticValidation/dataset.js +2 -4
  194. package/src/actions/primitives/semanticValidation/guide.js +1 -1
  195. package/src/actions/primitives/semanticValidation/index.js +9 -1
  196. package/src/actions/primitives/semanticValidation/layer.js +5 -0
  197. package/src/actions/primitives/semanticValidation/scale.js +28 -7
  198. package/src/actions/regression/components.js +36 -25
  199. package/src/actions/regression/create.js +13 -6
  200. package/src/actions/regression/edit.js +24 -11
  201. package/src/actions/resources/index.js +7 -0
  202. package/src/actions/resources/remove.js +173 -0
  203. package/src/actions/scales/channels.js +212 -0
  204. package/src/actions/scales/consumers/common.js +1 -1
  205. package/src/actions/scales/consumers/families.js +3 -2
  206. package/src/actions/scales/consumers/index.js +19 -2
  207. package/src/actions/scales/consumers/seriesLayout.js +28 -14
  208. package/src/actions/scales/create.js +55 -23
  209. package/src/actions/scales/definitions.js +94 -40
  210. package/src/actions/scales/edit.js +67 -12
  211. package/src/actions/scales/editPolicy.js +81 -11
  212. package/src/actions/scales/index.js +6 -0
  213. package/src/actions/scales/materialize.js +5 -4
  214. package/src/actions/scales/offset.js +48 -0
  215. package/src/actions/scales/parallel.js +71 -0
  216. package/src/actions/scales/preview.js +111 -10
  217. package/src/actions/scales/quantitativeColor.js +4 -5
  218. package/src/actions/selection/actions.js +179 -66
  219. package/src/actions/selection/index.js +3 -0
  220. package/src/actions/textMetrics/index.js +56 -0
  221. package/src/actions/theme/actions.js +70 -15
  222. package/src/actions/theme/composition.js +238 -0
  223. package/src/actions/theme/index.js +9 -2
  224. package/src/actions/theme/reconcile.js +313 -121
  225. package/src/actions/theme/state.js +160 -0
  226. package/src/actions/titles/actions.js +8 -8
  227. package/src/actions/titles/resolve.js +3 -3
  228. package/src/actions/violinPlots/create.js +6 -3
  229. package/src/actions/violinPlots/edit.js +2 -1
  230. package/src/core/action.js +117 -35
  231. package/src/core/compositionState.js +6 -1
  232. package/src/core/diagnostics.js +16 -0
  233. package/src/core/extensionRegistry.js +27 -0
  234. package/src/core/font.js +18 -0
  235. package/src/core/identifiers.js +5 -4
  236. package/src/core/immutable.js +10 -3
  237. package/src/core/optionRequirements.js +8 -0
  238. package/src/core/programState.js +21 -1
  239. package/src/core/resourceReferences.js +341 -0
  240. package/src/core/textMetricProfile.js +28 -0
  241. package/src/core/textMetrics.js +24 -3
  242. package/src/core/validation.js +22 -10
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/diagnostics.js +1 -0
  245. package/src/grammar/bars/aggregate.js +4 -1
  246. package/src/grammar/bars/geometry.js +44 -0
  247. package/src/grammar/bin.js +54 -9
  248. package/src/grammar/complete.js +279 -0
  249. package/src/grammar/computed.js +265 -64
  250. package/src/grammar/coordinates.js +37 -0
  251. package/src/grammar/density.js +239 -37
  252. package/src/grammar/displayLabels.js +57 -0
  253. package/src/grammar/facets/dependencies.js +133 -1
  254. package/src/grammar/facets/guides.js +3 -0
  255. package/src/grammar/facets/index.js +7 -47
  256. package/src/grammar/facets/scales.js +15 -18
  257. package/src/grammar/impute.js +341 -0
  258. package/src/grammar/markLabelSelection.js +57 -0
  259. package/src/grammar/markLabels.js +18 -1
  260. package/src/grammar/normalize.js +366 -0
  261. package/src/grammar/pathSeries.js +26 -8
  262. package/src/grammar/pointShapes.js +13 -4
  263. package/src/grammar/polar.js +90 -8
  264. package/src/grammar/regression/index.js +1 -0
  265. package/src/grammar/regression/parameters.js +23 -0
  266. package/src/grammar/roundedRect.js +180 -0
  267. package/src/grammar/rules.js +1 -0
  268. package/src/grammar/scales/colorConsumers.js +20 -1
  269. package/src/grammar/scales/continuous.js +2 -2
  270. package/src/grammar/scales/definition.js +27 -4
  271. package/src/grammar/scales/index.js +1 -0
  272. package/src/grammar/scales/ordinal.js +12 -3
  273. package/src/grammar/scales/policies.js +2 -2
  274. package/src/grammar/scales/size.js +456 -0
  275. package/src/grammar/scales/types.js +8 -0
  276. package/src/grammar/schemas/concreteGraphic.js +14 -2
  277. package/src/grammar/schemas/graphic.js +15 -0
  278. package/src/grammar/schemas/graphicBounds.js +190 -41
  279. package/src/grammar/schemas/semanticPath.js +7 -2
  280. package/src/grammar/statisticalReference.js +103 -0
  281. package/src/grammar/strokeStyle.js +77 -0
  282. package/src/grammar/summary.js +78 -16
  283. package/src/grammar/timeUnit.js +216 -5
  284. package/src/grammar/transformTopology.js +4 -0
  285. package/src/grammar/transforms.js +394 -28
  286. package/src/grammar/weightedStatistics.js +374 -0
  287. package/src/grammar/window.js +221 -16
  288. package/src/layout/aspect.js +80 -0
  289. package/src/layout/facets.js +59 -5
  290. package/src/layout/labels.js +351 -7
  291. package/src/layout/legend.js +4 -4
  292. package/src/layout/legendItems.js +6 -6
  293. package/src/layout/text.js +10 -9
  294. package/src/layout/title.js +9 -9
  295. package/src/materialization/bars/aggregate.js +25 -2
  296. package/src/materialization/bars/histogram.js +84 -24
  297. package/src/materialization/bars/ranged.js +19 -3
  298. package/src/materialization/bars/resolve.js +7 -4
  299. package/src/materialization/composition.js +3 -1
  300. package/src/materialization/coordinateBounds.js +204 -0
  301. package/src/materialization/dependencies.js +36 -0
  302. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  303. package/src/materialization/facetGuides/placement.js +9 -3
  304. package/src/materialization/facetGuides/preparation.js +13 -8
  305. package/src/materialization/facetHeaders.js +347 -0
  306. package/src/materialization/facets.js +15 -65
  307. package/src/materialization/guides/layout.js +3 -3
  308. package/src/materialization/guides/resources.js +26 -0
  309. package/src/materialization/legends.js +1 -1
  310. package/src/materialization/marks/index.js +11 -5
  311. package/src/materialization/marks/policies.js +2 -1
  312. package/src/materialization/rect.js +25 -12
  313. package/src/materialization/rectConfig.js +5 -1
  314. package/src/materialization/scaleGuideDependencies.js +10 -0
  315. package/src/materialization/scales/map.js +5 -3
  316. package/src/materialization/scales/policies/binnedPosition.js +2 -2
  317. package/src/materialization/scales/policies/offset.js +50 -8
  318. package/src/materialization/scales/policies/series.js +4 -1
  319. package/src/materialization/scales/resolve.js +22 -6
  320. package/src/materialization/selection/items/arc.js +28 -4
  321. package/src/materialization/selection/items/bar.js +30 -3
  322. package/src/materialization/selection/items/common.js +20 -5
  323. package/src/materialization/selection/items/rect.js +28 -4
  324. package/src/materialization/selection/path.js +1 -1
  325. package/src/materialization/selection/point.js +3 -1
  326. package/src/materialization/text.js +265 -14
  327. package/src/materialization/typography.js +31 -0
  328. package/src/mcp/cli.js +5 -3
  329. package/src/persistence/codec.js +65 -0
  330. package/src/persistence/validation.js +185 -0
  331. package/src/persistence.js +74 -0
  332. package/src/renderers/canvas/circle.js +2 -3
  333. package/src/renderers/canvas/index.js +5 -4
  334. package/src/renderers/canvas/line.js +2 -3
  335. package/src/renderers/canvas/native.js +4 -4
  336. package/src/renderers/canvas/path.js +2 -3
  337. package/src/renderers/canvas/rect.js +2 -3
  338. package/src/renderers/canvas/stroke.js +11 -0
  339. package/src/renderers/nativeBackend.js +10 -0
  340. package/src/renderers/options.js +13 -0
  341. package/src/renderers/pdf.js +25 -54
  342. package/src/renderers/png.js +22 -17
  343. package/src/renderers/svg.js +29 -14
  344. package/src/renderers/text.js +1 -11
  345. package/src/selectors/coordinates.js +3 -1
  346. package/src/selectors/datasets.js +38 -5
  347. package/src/selectors/layers.js +10 -4
  348. package/src/selectors/markOwners.js +46 -0
  349. package/src/selectors/scales.js +6 -4
  350. package/src/theme/defaults.js +103 -1
  351. package/src/version.js +2 -0
  352. package/types/accessibility.d.ts +37 -0
  353. package/types/basic.d.ts +10 -2
  354. package/types/diagnostics.d.ts +15 -0
  355. package/types/index.d.ts +90 -0
  356. package/types/pdf.d.ts +9 -0
  357. package/types/persistence.d.ts +7 -0
  358. package/types/png.d.ts +9 -0
  359. package/types/program.d.ts +944 -118
@@ -1,22 +1,19 @@
1
- import { action } from "../../core/action.js";
1
+ import { currentIntervalRoleArgs, resolveIntervalRoleScales, applyIntervalStatistics } from "../intervals/revision.js";
2
+ import { closedAction } from "../../core/action.js";
2
3
  import { isPlainObject } from "../../core/immutable.js";
3
4
  import { validateUserId } from "../../core/identifiers.js";
4
- import {
5
- validateOptionObject,
6
- validateKeys,
7
- validateNonEmptyString,
8
- validateNonNegativeFinite,
9
- validateUnitInterval
10
- } from "../../core/validation.js";
5
+ import { validateKeys, validateNonEmptyString, validateNonNegativeFinite, validateUnitInterval } from "../../core/validation.js";
11
6
  import { validateCurveInterpolation } from "../../grammar/curveCommands.js";
12
7
  import { normalizeStrokeDashPattern } from "../../grammar/scales/index.js";
8
+ import {
9
+ requestedStrokeDetails,
10
+ STROKE_STYLE_PROPERTIES
11
+ } from "../../grammar/strokeStyle.js";
13
12
  import { findLayer } from "../../selectors/layers.js";
14
- import { findSemanticScale } from "../../selectors/scales.js";
15
13
  import { removeOwnedMark } from "../marks/remove.js";
16
14
  import { DEFAULT_COLORS } from "../../theme/defaults.js";
17
15
  import { resolveIntervalComposite } from "../intervals/resolve.js";
18
16
  import {
19
- resolveDistributionScalePlan,
20
17
  setCartesianPosition,
21
18
  updateDistributionPositions
22
19
  } from "../distributions/revision.js";
@@ -32,7 +29,8 @@ import {
32
29
  } from "../data/intervalEdit.js";
33
30
 
34
31
  export const ERROR_BAND_BOUNDARY_OPTIONS = Object.freeze([
35
- "stroke", "strokeWidth", "strokeDash", "opacity", "curve"
32
+ "stroke", "strokeWidth", "strokeDash", "opacity", "curve",
33
+ ...STROKE_STYLE_PROPERTIES
36
34
  ]);
37
35
 
38
36
  export function resolveBoundaryAppearance(value, { defaults, operation }) {
@@ -49,14 +47,20 @@ export function resolveBoundaryAppearance(value, { defaults, operation }) {
49
47
  validateNonNegativeFinite(strokeWidth, `${operation} strokeWidth`);
50
48
  const resolvedStrokeDash = normalizeStrokeDashPattern(strokeDash);
51
49
  validateUnitInterval(opacity, `${operation} opacity`);
52
- return { stroke, strokeWidth, strokeDash: resolvedStrokeDash, opacity, curve };
50
+ return {
51
+ stroke,
52
+ strokeWidth,
53
+ strokeDash: resolvedStrokeDash,
54
+ opacity,
55
+ curve,
56
+ ...requestedStrokeDetails({ ...defaults, ...value }, operation)
57
+ };
53
58
  }
54
59
 
55
60
  const EDIT_OPTIONS = Object.freeze([
56
61
  "target", "data", "x", "y", "groupBy", "fill", "opacity", "curve",
57
- "statistics", "boundaries"
62
+ "statistics", "boundaries", ...STROKE_STYLE_PROPERTIES
58
63
  ]);
59
- const STATISTICS_OPTIONS = Object.freeze(["center", "extent", "method", "level"]);
60
64
  const EDIT_POLICY = Object.freeze({
61
65
  operation: "editErrorBand",
62
66
  resourceLabel: "error-band",
@@ -104,48 +108,13 @@ function resolveOwner(program, requested) {
104
108
  });
105
109
  }
106
110
 
107
- function currentRoleArgs(program, owner, current) {
108
- const transform = findIntervalTransform(program, current.data);
109
- const intervalChannel = current.orientation === "vertical" ? "y" : "x";
110
- const positionChannel = intervalChannel === "x" ? "y" : "x";
111
- const position = {
112
- field: current.position.field,
113
- fieldType: current.position.fieldType,
114
- ...(current.position.temporalUnit === undefined
115
- ? {}
116
- : { temporalUnit: current.position.temporalUnit }),
117
- scale: { id: current.positionScale }
118
- };
119
- const interval = transform === undefined
120
- ? {
121
- center: current.centerField ?? owner.encoding[intervalChannel].title,
122
- lower: current.lowerField,
123
- upper: current.upperField,
124
- scale: { id: current.intervalScale }
125
- }
126
- : {
127
- field: transform.field,
128
- center: transform.center,
129
- extent: transform.extent,
130
- ...(transform.method === undefined ? {} : { method: transform.method }),
131
- ...(transform.level === undefined ? {} : { level: transform.level }),
132
- scale: { id: current.intervalScale }
133
- };
134
- return {
135
- source: current.source ?? transform?.source ?? current.data,
136
- x: positionChannel === "x" ? position : interval,
137
- y: positionChannel === "y" ? position : interval,
138
- groupBy: current.groupBy
139
- };
140
- }
141
-
142
111
  function channelArgs(requested, fallback) {
143
112
  if (requested === undefined) return fallback;
144
113
  return requested;
145
114
  }
146
115
 
147
116
  function resolveRoleCandidate(program, owner, current, args) {
148
- const previous = currentRoleArgs(program, owner, current);
117
+ const previous = currentIntervalRoleArgs(program, owner, current, false);
149
118
  const full = {
150
119
  data: Object.hasOwn(args, "data") ? args.data : previous.source,
151
120
  x: channelArgs(args.x, previous.x),
@@ -167,75 +136,11 @@ function resolveRoleCandidate(program, owner, current, args) {
167
136
  "editErrorBand groupBy must differ from the independent position field."
168
137
  );
169
138
  }
170
- if (Object.hasOwn(args, "statistics")) {
171
- if (!isPlainObject(args.statistics)) {
172
- throw new TypeError("editErrorBand statistics must be a plain object.");
173
- }
174
- validateKeys(args.statistics, STATISTICS_OPTIONS, "editErrorBand statistics");
175
- if (!STATISTICS_OPTIONS.some(key => Object.hasOwn(args.statistics, key))) {
176
- throw new Error(
177
- "editErrorBand statistics requires center, extent, method, or level."
178
- );
179
- }
180
- full[resolved.interval.channel] = {
181
- ...full[resolved.interval.channel],
182
- ...args.statistics
183
- };
184
- resolved = resolveIntervalComposite(program, full, policy);
185
- }
186
- const positionRole = {
187
- field: resolved.position.field,
188
- fieldType: resolved.position.fieldType,
189
- scale: resolved.position.scale
190
- };
191
- const intervalTitle = resolved.interval.mode === "statistical"
192
- ? resolved.interval.field
193
- : resolved.interval.title;
194
- const intervalRole = {
195
- field: intervalTitle,
196
- fieldType: "quantitative",
197
- scale: resolved.interval.scale
198
- };
199
- const x = resolved.position.channel === "x" ? positionRole : intervalRole;
200
- const y = resolved.position.channel === "y" ? positionRole : intervalRole;
201
- const plan = (channel, role) => {
202
- const fallback = role === intervalRole
203
- ? current.intervalScale
204
- : current.positionScale;
205
- const stored = findSemanticScale(program, fallback);
206
- const compatible = role.fieldType === "temporal"
207
- ? stored?.type === "time"
208
- : ["linear", "log", "pow", "sqrt", "symlog"].includes(stored?.type);
209
- const requested = role.scale.type !== undefined || compatible
210
- ? role.scale
211
- : { ...role.scale, type: role.fieldType === "temporal" ? "time" : "linear" };
212
- return resolveDistributionScalePlan(program, {
213
- channel,
214
- fieldType: role.fieldType,
215
- requested,
216
- fallback,
217
- defaults: role === intervalRole
218
- ? EDIT_POLICY.intervalScaleDefaults
219
- : EDIT_POLICY.scaleDefaults(role.fieldType)
220
- });
221
- };
222
- const xScale = plan("x", x);
223
- const yScale = plan("y", y);
139
+ resolved = applyIntervalStatistics(program, full, policy, args, resolved);
140
+ const roles = resolveIntervalRoleScales(program, resolved, current, EDIT_POLICY, owner, previous);
224
141
  return {
225
142
  ...resolved,
226
- x: { ...x, scale: xScale.id },
227
- y: { ...y, scale: yScale.id },
228
- xScale,
229
- yScale,
230
- category: resolved.position.field,
231
- categoryType: resolved.position.fieldType,
232
- measure: intervalTitle,
233
- previous: {
234
- x: { field: previous.x.center ?? previous.x.field,
235
- fieldType: owner.encoding.x.fieldType, scale: owner.encoding.x.scale },
236
- y: { field: previous.y.center ?? previous.y.field,
237
- fieldType: owner.encoding.y.fieldType, scale: owner.encoding.y.scale }
238
- }
143
+ ...roles
239
144
  };
240
145
  }
241
146
 
@@ -331,7 +236,8 @@ function currentBoundaryAppearance(program, id) {
331
236
  strokeWidth: config.strokeWidth,
332
237
  strokeDash: config.strokeDash,
333
238
  opacity: config.opacity,
334
- curve: config.curve ?? "linear"
239
+ curve: config.curve ?? "linear",
240
+ ...requestedStrokeDetails(config, "Error-band boundary")
335
241
  };
336
242
  }
337
243
 
@@ -376,17 +282,12 @@ function removeBoundary(program, id) {
376
282
  return removeOwnedMark(program, id);
377
283
  }
378
284
 
379
- export const rematerializeErrorBandBoundary = action(
285
+ export const rematerializeErrorBandBoundary = /* @__PURE__ */ closedAction(
380
286
  {
381
287
  op: "rematerializeErrorBandBoundary",
382
288
  description: "Rematerialize one owned error-band boundary."
383
- },
289
+ }, REMATERIALIZE_OPTIONS,
384
290
  function (args = {}) {
385
- validateOptionObject(
386
- args,
387
- REMATERIALIZE_OPTIONS,
388
- "rematerializeErrorBandBoundary"
389
- );
390
291
  const id = validateUserId(args.id, "Error-band boundary id");
391
292
  currentBoundaryAppearance(this, id);
392
293
  const graphic = this.graphicSpec.objects[id];
@@ -397,7 +298,8 @@ export const rematerializeErrorBandBoundary = action(
397
298
  strokeWidth: args.strokeWidth,
398
299
  strokeDash: args.strokeDash,
399
300
  opacity: args.opacity,
400
- curve: args.curve
301
+ curve: args.curve,
302
+ ...requestedStrokeDetails(args, "Error-band boundary")
401
303
  })
402
304
  .editGraphics({
403
305
  target: id,
@@ -408,20 +310,20 @@ export const rematerializeErrorBandBoundary = action(
408
310
  }
409
311
  );
410
312
 
411
- export const editErrorBand = action(
313
+ export const editErrorBand = /* @__PURE__ */ closedAction(
412
314
  {
413
315
  op: "editErrorBand",
414
316
  description: "Revise one error band's roles, statistics, body, and boundaries."
415
- },
317
+ }, EDIT_OPTIONS,
416
318
  function (args = {}) {
417
- validateOptionObject(args, EDIT_OPTIONS, "editErrorBand");
418
319
  if (!["data", "x", "y", "groupBy", "fill", "opacity", "curve",
419
- "statistics", "boundaries"]
320
+ "statistics", "boundaries", ...STROKE_STYLE_PROPERTIES]
420
321
  .some(key => Object.hasOwn(args, key))) {
421
322
  throw new Error("editErrorBand requires at least one change.");
422
323
  }
423
324
  const owner = resolveOwner(this, args.target);
424
325
  const config = { ...this.markConfigs[owner.id] };
326
+ Object.assign(config, requestedStrokeDetails(args, "editErrorBand"));
425
327
  const errorBand = { ...config.errorBand };
426
328
  if (Object.hasOwn(args, "fill")) {
427
329
  if (args.fill === false) {
@@ -570,17 +472,12 @@ export const editErrorBand = action(
570
472
  }
571
473
  );
572
474
 
573
- export const editErrorBandBoundary = action(
475
+ export const editErrorBandBoundary = /* @__PURE__ */ closedAction(
574
476
  {
575
477
  op: "editErrorBandBoundary",
576
478
  description: "Edit one or both owned error-band boundaries."
577
- },
479
+ }, BOUNDARY_EDIT_OPTIONS,
578
480
  function (args = {}) {
579
- validateOptionObject(
580
- args,
581
- BOUNDARY_EDIT_OPTIONS,
582
- "editErrorBandBoundary"
583
- );
584
481
  if (!ERROR_BAND_BOUNDARY_OPTIONS.some(key => Object.hasOwn(args, key))) {
585
482
  throw new Error("editErrorBandBoundary requires an appearance change.");
586
483
  }
@@ -1,16 +1,15 @@
1
- import { action } from "../../core/action.js";
2
- import {
3
- validateKeys,
4
- validateOptionObject
5
- } from "../../core/validation.js";
1
+ import { closedAction } from "../../core/action.js";
2
+ import { validateOptionObject } from "../../core/validation.js";
6
3
  import { findLayer } from "../../selectors/layers.js";
7
4
  import { findDataset } from "../../selectors/datasets.js";
5
+ import { findSemanticScale } from "../../selectors/scales.js";
8
6
  import { DEFAULT_COLORS } from "../../theme/defaults.js";
9
7
  import {
10
8
  readNominalField,
11
9
  validateCategoricalFieldType
12
10
  } from "../../grammar/scales/index.js";
13
11
  import { normalizeOffsetPadding } from "../../grammar/bars/geometry.js";
12
+ import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
14
13
  import { createResolvedIntervalData, ownOptions } from
15
14
  "../data/intervalEdit.js";
16
15
  import { resolveIntervalComposite } from "../intervals/resolve.js";
@@ -31,7 +30,8 @@ const OPTIONS = Object.freeze([
31
30
  "stroke",
32
31
  "strokeWidth",
33
32
  "strokeDash",
34
- "opacity"
33
+ "opacity",
34
+ ...STROKE_STYLE_PROPERTIES
35
35
  ]);
36
36
 
37
37
  const OFFSET_OPTIONS = Object.freeze([
@@ -101,7 +101,15 @@ function resolveErrorBarOffset(program, args, resolved, operation) {
101
101
  explicit ?? {},
102
102
  resolved.sourceLayer === undefined
103
103
  ? undefined
104
- : program.markConfigs[resolved.sourceLayer.id]?.[channel],
104
+ : (() => {
105
+ const semantic = inferred?.scale === undefined
106
+ ? undefined
107
+ : findSemanticScale(program, inferred.scale);
108
+ return semantic !== undefined && ["paddingInner", "paddingOuter"]
109
+ .some(property => Object.hasOwn(semantic, property))
110
+ ? semantic
111
+ : program.markConfigs[resolved.sourceLayer.id]?.[channel];
112
+ })(),
105
113
  channel
106
114
  );
107
115
  return {
@@ -118,7 +126,8 @@ function resolveErrorBarOffset(program, args, resolved, operation) {
118
126
 
119
127
  function resolveAppearance(args) {
120
128
  return resolveErrorBarAppearance(ownOptions(args, [
121
- "caps", "capSize", "stroke", "strokeWidth", "strokeDash", "opacity"
129
+ "caps", "capSize", "stroke", "strokeWidth", "strokeDash", "opacity",
130
+ ...STROKE_STYLE_PROPERTIES
122
131
  ]), {
123
132
  defaults: {
124
133
  caps: true,
@@ -132,19 +141,19 @@ function resolveAppearance(args) {
132
141
  });
133
142
  }
134
143
 
135
- export const createErrorBarCap = action(
144
+ export const createErrorBarCap = /* @__PURE__ */ closedAction(
136
145
  {
137
146
  op: "createErrorBarCap",
138
147
  description: "Create one fixed-pixel error-bar cap."
139
- },
140
- function (args = {}) {
141
- validateKeys(args, [
148
+ }, [
142
149
  "id", "data", "orientation", "positionField", "positionFieldType",
143
150
  "intervalField", "coordinate", "positionScale", "intervalScale", "positionTemporalUnit",
144
151
  "offsetChannel", "offsetField", "offsetFieldType", "offsetScale",
145
152
  "offsetPaddingInner", "offsetPaddingOuter",
146
- "capSize", "stroke", "strokeWidth", "strokeDash", "opacity"
147
- ], "createErrorBarCap");
153
+ "capSize", "stroke", "strokeWidth", "strokeDash", "opacity",
154
+ ...STROKE_STYLE_PROPERTIES
155
+ ],
156
+ function (args = {}) {
148
157
  if (!["vertical", "horizontal"].includes(args.orientation)) {
149
158
  throw new Error(`Unsupported error-bar orientation "${args.orientation}".`);
150
159
  }
@@ -161,7 +170,13 @@ export const createErrorBarCap = action(
161
170
  const positionAction = vertical ? "encodeX" : "encodeY";
162
171
  const intervalAction = vertical ? "encodeY" : "encodeX";
163
172
  let next = this
164
- .createRuleMark({ id: args.id, data: args.data })
173
+ .createRuleMark({
174
+ id: args.id,
175
+ data: args.data,
176
+ ...Object.fromEntries(STROKE_STYLE_PROPERTIES.flatMap(property =>
177
+ Object.hasOwn(args, property) ? [[property, args[property]]] : []
178
+ ))
179
+ })
165
180
  [positionAction]({
166
181
  target: args.id,
167
182
  field: args.positionField,
@@ -237,17 +252,22 @@ function intervalArgs(resolved, field) {
237
252
  };
238
253
  }
239
254
 
240
- export const createErrorBar = action(
255
+ export const createErrorBar = /* @__PURE__ */ closedAction(
241
256
  {
242
257
  op: "createErrorBar",
243
258
  description: "Create a statistical or explicit vertical or horizontal interval."
244
- },
259
+ }, OPTIONS,
245
260
  function (args = {}) {
246
- validateKeys(args, OPTIONS, "createErrorBar");
247
261
  const resolved = resolveErrorBar(this, args);
248
262
  const appearance = resolveAppearance(args);
249
263
  let next = createResolvedIntervalData(this, resolved);
250
- next = next.createRuleMark({ id: resolved.id, data: resolved.dataId });
264
+ next = next.createRuleMark({
265
+ id: resolved.id,
266
+ data: resolved.dataId,
267
+ ...Object.fromEntries(STROKE_STYLE_PROPERTIES.flatMap(property =>
268
+ Object.hasOwn(appearance, property) ? [[property, appearance[property]]] : []
269
+ ))
270
+ });
251
271
  const positionAction = resolved.position.channel === "x" ? "encodeX" : "encodeY";
252
272
  const intervalAction = resolved.interval.channel === "x" ? "encodeX" : "encodeY";
253
273
  const secondaryAction = resolved.interval.channel === "x" ? "encodeX2" : "encodeY2";
@@ -303,7 +323,10 @@ export const createErrorBar = action(
303
323
  stroke: appearance.stroke,
304
324
  strokeWidth: appearance.strokeWidth,
305
325
  strokeDash: appearance.strokeDash,
306
- opacity: appearance.opacity
326
+ opacity: appearance.opacity,
327
+ ...Object.fromEntries(STROKE_STYLE_PROPERTIES.flatMap(property =>
328
+ Object.hasOwn(appearance, property) ? [[property, appearance[property]]] : []
329
+ ))
307
330
  });
308
331
  }
309
332
  }
@@ -1,5 +1,5 @@
1
- import { action } from "../../core/action.js";
2
- import { isPlainObject } from "../../core/immutable.js";
1
+ import { currentIntervalRoleArgs, resolveIntervalRoleScales, applyIntervalStatistics } from "../intervals/revision.js";
2
+ import { closedAction } from "../../core/action.js";
3
3
  import { validateUserId } from "../../core/identifiers.js";
4
4
  import {
5
5
  validateKeys,
@@ -14,10 +14,8 @@ import {
14
14
  validateRuleStrokeWidth
15
15
  } from "../../grammar/ruleAppearance.js";
16
16
  import { findLayer } from "../../selectors/layers.js";
17
- import { findSemanticScale } from "../../selectors/scales.js";
18
17
  import { resolveIntervalComposite } from "../intervals/resolve.js";
19
18
  import {
20
- resolveDistributionScalePlan,
21
19
  setCartesianPosition,
22
20
  updateDistributionPositions
23
21
  } from "../distributions/revision.js";
@@ -31,17 +29,21 @@ import {
31
29
  releaseIntervalRevision,
32
30
  resolveIntervalOwner
33
31
  } from "../data/intervalEdit.js";
32
+ import {
33
+ requestedStrokeDetails,
34
+ STROKE_STYLE_PROPERTIES
35
+ } from "../../grammar/strokeStyle.js";
34
36
 
35
37
  export const ERROR_BAR_EDIT_OPTIONS = Object.freeze([
36
38
  "target", "data", "x", "y", "xOffset", "yOffset", "groupBy",
37
39
  "caps", "capSize", "stroke", "strokeWidth", "strokeDash", "opacity",
38
- "statistics"
40
+ "statistics", ...STROKE_STYLE_PROPERTIES
39
41
  ]);
40
42
 
41
43
  export const ERROR_BAR_APPEARANCE_OPTIONS = Object.freeze([
42
- "caps", "capSize", "stroke", "strokeWidth", "strokeDash", "opacity"
44
+ "caps", "capSize", "stroke", "strokeWidth", "strokeDash", "opacity",
45
+ ...STROKE_STYLE_PROPERTIES
43
46
  ]);
44
- const STATISTICS_OPTIONS = Object.freeze(["center", "extent", "method", "level"]);
45
47
  const EDIT_POLICY = Object.freeze({
46
48
  operation: "editErrorBar",
47
49
  resourceLabel: "error-bar",
@@ -81,7 +83,15 @@ export function resolveErrorBarAppearance(args, { defaults, operation }) {
81
83
  args.opacity ?? defaults.opacity,
82
84
  `${operation} opacity`
83
85
  );
84
- return { caps, capSize, stroke, strokeWidth, strokeDash, opacity };
86
+ return {
87
+ caps,
88
+ capSize,
89
+ stroke,
90
+ strokeWidth,
91
+ strokeDash,
92
+ opacity,
93
+ ...requestedStrokeDetails({ ...defaults, ...args }, operation)
94
+ };
85
95
  }
86
96
 
87
97
  const REMATERIALIZE_OPTIONS = Object.freeze(["id"]);
@@ -102,45 +112,8 @@ function resolveOwner(program, requested) {
102
112
  });
103
113
  }
104
114
 
105
- function currentRoleArgs(program, owner, current) {
106
- const transform = findIntervalTransform(program, current.data);
107
- const intervalChannel = current.orientation === "vertical" ? "y" : "x";
108
- const positionChannel = intervalChannel === "x" ? "y" : "x";
109
- const position = {
110
- field: current.positionField,
111
- fieldType: current.positionFieldType,
112
- ...(current.positionTemporalUnit === undefined
113
- ? {}
114
- : { temporalUnit: current.positionTemporalUnit }),
115
- scale: { id: current.positionScale }
116
- };
117
- const interval = transform === undefined
118
- ? {
119
- center: current.centerField ?? owner.encoding[intervalChannel].title,
120
- lower: current.lowerField,
121
- upper: current.upperField,
122
- scale: { id: current.intervalScale }
123
- }
124
- : {
125
- field: transform.field,
126
- center: transform.center,
127
- extent: transform.extent,
128
- ...(transform.method === undefined ? {} : { method: transform.method }),
129
- ...(transform.level === undefined ? {} : { level: transform.level }),
130
- scale: { id: current.intervalScale }
131
- };
132
- return {
133
- source: current.source ?? transform?.source ?? current.data,
134
- x: positionChannel === "x" ? position : interval,
135
- y: positionChannel === "y" ? position : interval,
136
- groupBy: current.groupField ?? transform?.groupBy?.find(
137
- field => field !== current.positionField
138
- )
139
- };
140
- }
141
-
142
115
  function resolveRoleCandidate(program, owner, current, args) {
143
- const previous = currentRoleArgs(program, owner, current);
116
+ const previous = currentIntervalRoleArgs(program, owner, current, true);
144
117
  const full = {
145
118
  data: Object.hasOwn(args, "data") ? args.data : previous.source,
146
119
  x: Object.hasOwn(args, "x") ? args.x : previous.x,
@@ -157,65 +130,8 @@ function resolveRoleCandidate(program, owner, current, args) {
157
130
  generatedFields: findIntervalTransform(program, current.data)?.as
158
131
  };
159
132
  let resolved = resolveIntervalComposite(program, full, policy);
160
- if (Object.hasOwn(args, "statistics")) {
161
- if (!isPlainObject(args.statistics)) {
162
- throw new TypeError("editErrorBar statistics must be a plain object.");
163
- }
164
- validateKeys(args.statistics, STATISTICS_OPTIONS, "editErrorBar statistics");
165
- if (!STATISTICS_OPTIONS.some(key => Object.hasOwn(args.statistics, key))) {
166
- throw new Error(
167
- "editErrorBar statistics requires center, extent, method, or level."
168
- );
169
- }
170
- full[resolved.interval.channel] = {
171
- ...full[resolved.interval.channel],
172
- ...args.statistics
173
- };
174
- resolved = resolveIntervalComposite(program, full, policy);
175
- }
176
- const positionRole = {
177
- field: resolved.position.field,
178
- fieldType: resolved.position.fieldType,
179
- scale: resolved.position.scale
180
- };
181
- const intervalTitle = resolved.interval.mode === "statistical"
182
- ? resolved.interval.field
183
- : resolved.interval.title;
184
- const intervalRole = {
185
- field: intervalTitle,
186
- fieldType: "quantitative",
187
- scale: resolved.interval.scale
188
- };
189
- const x = resolved.position.channel === "x" ? positionRole : intervalRole;
190
- const y = resolved.position.channel === "y" ? positionRole : intervalRole;
191
- const plan = (channel, role) => {
192
- const fallback = role === intervalRole
193
- ? current.intervalScale
194
- : current.positionScale;
195
- const stored = findSemanticScale(program, fallback);
196
- const compatible = role.fieldType === "temporal"
197
- ? stored?.type === "time"
198
- : ["nominal", "ordinal"].includes(role.fieldType)
199
- ? ["band", "point"].includes(stored?.type)
200
- : ["linear", "log", "pow", "sqrt", "symlog"].includes(stored?.type);
201
- const defaultType = role.fieldType === "temporal"
202
- ? "time"
203
- : ["nominal", "ordinal"].includes(role.fieldType) ? "band" : "linear";
204
- const requested = role.scale.type !== undefined || compatible
205
- ? role.scale
206
- : { ...role.scale, type: defaultType };
207
- return resolveDistributionScalePlan(program, {
208
- channel,
209
- fieldType: role.fieldType,
210
- requested,
211
- fallback,
212
- defaults: role === intervalRole
213
- ? EDIT_POLICY.intervalScaleDefaults
214
- : EDIT_POLICY.scaleDefaults(role.fieldType)
215
- });
216
- };
217
- const xScale = plan("x", x);
218
- const yScale = plan("y", y);
133
+ resolved = applyIntervalStatistics(program, full, policy, args, resolved);
134
+ const roles = resolveIntervalRoleScales(program, resolved, current, EDIT_POLICY, owner, previous);
219
135
  const expectedOffset = `${resolved.position.channel}Offset`;
220
136
  const incompatibleOffset = expectedOffset === "xOffset" ? "yOffset" : "xOffset";
221
137
  if (Object.hasOwn(args, incompatibleOffset)) {
@@ -257,19 +173,7 @@ function resolveRoleCandidate(program, owner, current, args) {
257
173
  return {
258
174
  ...resolved,
259
175
  offset: normalizedOffset,
260
- x: { ...x, scale: xScale.id },
261
- y: { ...y, scale: yScale.id },
262
- xScale,
263
- yScale,
264
- category: resolved.position.field,
265
- categoryType: resolved.position.fieldType,
266
- measure: intervalTitle,
267
- previous: {
268
- x: { field: previous.x.center ?? previous.x.field,
269
- fieldType: owner.encoding.x.fieldType, scale: owner.encoding.x.scale },
270
- y: { field: previous.y.center ?? previous.y.field,
271
- fieldType: owner.encoding.y.fieldType, scale: owner.encoding.y.scale }
272
- }
176
+ ...roles
273
177
  };
274
178
  }
275
179
 
@@ -307,7 +211,8 @@ function capArgs(config, id, intervalField) {
307
211
  stroke: config.stroke,
308
212
  strokeWidth: config.strokeWidth,
309
213
  strokeDash: config.strokeDash,
310
- opacity: config.opacity
214
+ opacity: config.opacity,
215
+ ...requestedStrokeDetails(config, "Error bar")
311
216
  };
312
217
  }
313
218
 
@@ -323,6 +228,7 @@ function rematerializeRuleAppearance(program, id, config, fixedSpan) {
323
228
  strokeWidth: config.strokeWidth,
324
229
  strokeDash: config.strokeDash,
325
230
  opacity: config.opacity,
231
+ ...requestedStrokeDetails(config, "Error bar"),
326
232
  ...(fixedSpan === undefined ? {} : { fixedSpan })
327
233
  })
328
234
  .rematerializeRuleMark({ id });
@@ -445,13 +351,12 @@ function updateErrorBarRoles(program, owner, current, candidate, dataId, capIds)
445
351
  return next.rematerializeErrorBar({ id: owner.id });
446
352
  }
447
353
 
448
- export const rematerializeErrorBar = action(
354
+ export const rematerializeErrorBar = /* @__PURE__ */ closedAction(
449
355
  {
450
356
  op: "rematerializeErrorBar",
451
357
  description: "Reconcile one error bar and its owned caps."
452
- },
358
+ }, REMATERIALIZE_OPTIONS,
453
359
  function (args = {}) {
454
- validateKeys(args, REMATERIALIZE_OPTIONS, "rematerializeErrorBar");
455
360
  const id = validateUserId(args.id, "Error-bar id");
456
361
  const layer = findLayer(this, id);
457
362
  const config = this.markConfigs[id]?.errorBar;
@@ -479,13 +384,12 @@ export const rematerializeErrorBar = action(
479
384
  }
480
385
  );
481
386
 
482
- export const editErrorBar = action(
387
+ export const editErrorBar = /* @__PURE__ */ closedAction(
483
388
  {
484
389
  op: "editErrorBar",
485
390
  description: "Revise one error bar's roles, statistics, and owned caps."
486
- },
391
+ }, ERROR_BAR_EDIT_OPTIONS,
487
392
  function (args = {}) {
488
- validateKeys(args, ERROR_BAR_EDIT_OPTIONS, "editErrorBar");
489
393
  const editable = ERROR_BAR_EDIT_OPTIONS.filter(option => option !== "target");
490
394
  if (!editable.some(option => Object.hasOwn(args, option))) {
491
395
  throw new Error("editErrorBar requires at least one change.");